{"id":230848,"date":"2022-12-21T12:51:00","date_gmt":"2022-12-21T09:51:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=230848"},"modified":"2022-12-07T10:29:48","modified_gmt":"2022-12-07T07:29:48","slug":"widzety-wordpress-refaktoryzacja-czesc-11","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pl\/widzety-wordpress-refaktoryzacja-czesc-11\/","title":{"rendered":"Wid\u017cety WordPress: Refaktoryzacja, cz\u0119\u015b\u0107 11"},"content":{"rendered":"\n<p>W poprzednim po\u015bcie przeszli\u015bmy przez wiele refaktoryzacji, kt\u00f3re rozdzieli\u0142y obawy na ich w\u0142asne klasy.<\/p>\n<p>Ostatecznie pomaga to pokaza\u0107, w jaki spos\u00f3b mo\u017cemy utrzyma\u0107 wysoki poziom sp\u00f3jno\u015bci, nie tylko pracuj\u0105c z klasami w WordPressie, ale robi\u0105c to wraz z istniej\u0105cymi interfejsami API.<\/p>\n<p>Poniewa\u017c kilka ostatnich post\u00f3w na temat refaktoryzacji bazy kodu by\u0142o tak d\u0142ugich, obecny zestaw post\u00f3w skupia si\u0119 na ma\u0142ych, przyrostowych zmianach, a tym samym kr\u00f3tszych, bardziej skoncentrowanych postach.<\/p>\n<p>Jak wspomniano w poprzednim artykule:<\/p>\n<blockquote>\n<p>Ale je\u015bli od\u015bwie\u017cysz stron\u0119, mo\u017cesz zauwa\u017cy\u0107, \u017ce oczyszczanie i serializacja nie dzia\u0142aj\u0105 podczas pobierania danych. I tym zajmiemy si\u0119 w nast\u0119pnym po\u015bcie.<\/p>\n<\/blockquote>\n<p>Wi\u0119c to w\u0142a\u015bnie tam zajmiemy si\u0119 w tym artykule.<\/p>\n<h2>WordPress Widget Boilerplate: Refaktoryzacja Cz\u0119\u015b\u0107 11<\/h2>\n<p>Przed napisaniem jakiegokolwiek kodu, pierwsz\u0105 rzecz\u0105, na kt\u00f3r\u0105 nale\u017cy zwr\u00f3ci\u0107 uwag\u0119, jest to, \u017ce je\u015bli wype\u0142nisz jeden z obszar\u00f3w zawarto\u015bci wid\u017cetu (takiego jak tytu\u0142) czym\u015b takim, <a href=\"https:\/\/gist.github.com\/tommcfarlin\/39038338730b7141a19c3d2f48801dac#file-00-example-title-js\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">jak to<\/a> :<\/p>\n<pre><code>&lt;script type=\"text\/javascript\"&gt;This is the Title&lt;\/script&gt;<\/code><\/pre>\n<p>A nast\u0119pnie kliknij Zapisz, rzeczywista zawarto\u015b\u0107 zostanie oczyszczona i zapisana w bazie danych. Mo\u017cesz zobaczy\u0107, \u017ce to prawda, patrz\u0105c na warto\u015b\u0107 wid\u017cetu w bazie danych.<\/p>\n<p>Co wi\u0119cej, dane na pierwszy rzut oka wygl\u0105daj\u0105 dobrze, ale je\u015bli od\u015bwie\u017cysz stron\u0119, pojawi si\u0119 nieoczyszczona zawarto\u015b\u0107. Je\u015bli przejdziesz do innej strony, takiej jak Menu, a nast\u0119pnie wr\u00f3cisz, zawarto\u015b\u0107 wid\u017cetu zostanie wy\u015bwietlona, \u200b\u200bale prawid\u0142owo oczyszczona.<\/p>\n<p>Dlaczego wi\u0119c pokazuje jedn\u0105 rzecz w bazie danych i jedn\u0105 rzecz na froncie obszaru administracyjnego podczas wykonywania okre\u015blonych krok\u00f3w?<\/p>\n<p>Ma to zwi\u0105zek z pami\u0119ci\u0105 podr\u0119czn\u0105 wid\u017cet\u00f3w i na szcz\u0119\u015bcie jeste\u015bmy w stanie opr\u00f3\u017cni\u0107 t\u0119 pami\u0119\u0107 podr\u0119czn\u0105 do woli, u\u017cywaj\u0105c dowolnych zaczep\u00f3w (to znaczy, mo\u017cemy subskrybowa\u0107 dowolne zdarzenie, a nast\u0119pnie opr\u00f3\u017cni\u0107 pami\u0119\u0107 podr\u0119czn\u0105).<\/p>\n<\/p>\n<p>Z <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_cache_delete\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">odniesienia do kodu<\/a> :<\/p>\n<blockquote>\n<p>Usuwa zawarto\u015b\u0107 pami\u0119ci podr\u0119cznej pasuj\u0105c\u0105 do klucza i grupy.<\/p>\n<\/blockquote>\n<p>Pami\u0119taj jednak, \u017ce wymaga to podania klucza i opcjonalnej grupy. W Boilerplate u\u017cywamy slug widgetu jako klucza i grupy jest widgetem.<\/p>\n<h3>Czyszczenie pami\u0119ci podr\u0119cznej<\/h3>\n<p>Poniewa\u017c funkcj\u0119 mo\u017cna podpi\u0105\u0107 do dowolnego zdarzenia, mo\u017cemy utworzy\u0107 subskrybenta, kt\u00f3rego mo\u017cemy podpi\u0105\u0107 do dowolnego zdarzenia. Oznacza to <a href=\"https:\/\/gist.github.com\/tommcfarlin\/39038338730b7141a19c3d2f48801dac#file-01-delete-widget-cache-subscriber-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">, \u017ce mo\u017cemy utworzy\u0107 subskrybenta DeleteWidgetCache w naszej przestrzeni nazw subskrybenta:<\/a><\/p>\n<pre><code>&lt;?php\n\n&lt;?php\n\n\/*\n * This file is part of WordPress Widget Boilerplate\n * (c) Tom McFarlin &lt;tom@tommcfarlin.com&gt;\n *\n * This source file is subject to the GPL license that is bundled\n * with this source code in the file LICENSE.\n *\/\n\nnamespace WordPressWidgetBoilerplateSubscriber;\n\n\/**\n * Deletes the cached contents of the widget.\n *\/\nclass DeleteWidgetCacheSubscriber extends AbstractSubscriber\n{\n    \/**\n     * {@inheritdoc}\n     *\/\n    public function __construct(string $hook)\n    {\n        parent::__construct($hook);\n    }\n\n    \/**\n     * Flushes the widget's cache based on the key that's specified in the function arguments.\n     *\/\n    public function load()\n    {\n        \/* Because we're implementing an abstract class, we'll parse arguments from the\n         * func_get_args().\n         *\/\n        $args = func_get_args();\n        if (!$this-&gt;hasValidArguments($args)) {\n            return;\n        }\n\n        \/\/ TODO: More to come...\n    }\n\n    \/**\n     * Verifies that we have valid arguments with which to work.\n     *\n     * @param array $args the array of arguments we are validating\n     *\n     * @return bool true if the arguments are valid; otherwise, false\n     *\/\n    private function hasValidArguments(array $args): bool\n    {\n        \/\/ First, check the initial index of the arguments.\n        if (!isset($args[0])) {\n            return false;\n        }\n\n        \/\/ Next, check the values of the arguments for the widget key and group.\n        $args = $args[0];\n        if (!isset($args[0]) &amp;&amp; !isset($args[1])) {\n            return false;\n        }\n\n        return true;\n    }\n}\n<\/code><\/pre>\n<p>Nast\u0119pnie <a href=\"https:\/\/gist.github.com\/tommcfarlin\/39038338730b7141a19c3d2f48801dac#file-02-wordpress-widget-plugin-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">zaktualizujemy bootstrap<\/a>, aby doda\u0107 subskrybenta do rejestru i u\u017cyjemy niestandardowego haka, flush_widget_cache, kt\u00f3rego u\u017cyjemy chwilowo.<\/p>\n<pre><code>&lt;?php\n\/**\n * WordPress Widget Boilerplate\n *\n * The WordPress Widget Boilerplate is an organized, maintainable boilerplate for building\n * widgets using WordPress best practices.\n *\n * @package   WordPressWidgetBoilerplate\n * @author    Your Name &lt;email@example.com&gt;\n * @license   GPL-3.0+\n * @link      http:\/\/example.com\n * @copyright 2018 - 2019 Your Name or Company Name\n *\n * @wordpress-plugin\n * Plugin Name:       WordPress Widget Boilerplate\n * Plugin URI:        https:\/\/github.com\/tommcfarlin\/wordpress-widget-boilerplate\n * Description:       An object-oriented foundation for building WordPress Widgets.\n * Version:           1.0.0\n * Author:            Tom McFarlin\n * Author URI:        https:\/\/tommcfarlin.com\n * Text Domain:       widget-name\n * License:           GPL-3.0+\n * License URI:       http:\/\/www.gnu.org\/licenses\/gpl-3.0.txt\n * Domain Path:       \/lang\n *\/\n\nnamespace WordPressWidgetBoilerplate;\n\nuse WordPressWidgetBoilerplateUtilitiesRegistry;\nuse WordPressWidgetBoilerplatePlugin;\nuse WordPressWidgetBoilerplateSubscriberWidgetSubscriber;\nuse WordPressWidgetBoilerplateSubscriberDeleteWidgetCacheSubscriber;\n\n\/\/ Prevent this file from being called directly.\ndefined('WPINC') || die;\n\n\/\/ Include the autoloader.\nrequire_once __DIR__. '\/vendor\/autoload.php';\n\n\/\/ Setup a filter so we can retrieve the registry throughout the plugin.\n$registry = new Registry();\nadd_filter('wpwBoilerplateRegistry', function() use ($registry) {\n    return $registry;\n});\n\n\/\/ Add subscribers.\n$registry-&gt;add('deleteWidgetCacheSubscriber', new DeleteWidgetCacheSubscriber('flush_widget_cache'));\n\n\/\/ Add the Widget base class to the Registry.\n$registry-&gt;add('widgetSubscriber', new WidgetSubscriber('widgets_init'));\n\n\/\/ Start the machine.\n(new Plugin($registry))-&gt;start();\n<\/code><\/pre>\n<p>Na potrzeby Boilerplate u\u017cyjemy zdarzenia niestandardowego za ka\u017cdym razem, gdy zostanie wywo\u0142any kod serializacji wid\u017cetu.<\/p>\n<p>Najpierw zdefiniujemy\u00a0 wywo\u0142anie <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/do_action\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">do_action<\/a>, zidentyfikujemy je jako flush_widget_cache, a nast\u0119pnie <a href=\"https:\/\/gist.github.com\/tommcfarlin\/39038338730b7141a19c3d2f48801dac#file-03-widget-serialization-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">przeka\u017cemy niezb\u0119dne argumenty<\/a> do zdarzenia, aby subskrybent m\u00f3g\u0142 je odczyta\u0107:<\/p>\n<pre><code>&lt;?php\n\n\/*\n * This file is part of WordPress Widget Boilerplate\n * (c) Tom McFarlin &lt;tom@tommcfarlin.com&gt;\n *\n * This source file is subject to the GPL license that is bundled\n * with this source code in the file LICENSE.\n *\/\n\nnamespace WordPressWidgetBoilerplateWordPress;\n\n\/**\n * Santiizes and saves the data for the widget.\n *\/\nclass WidgetSerializer\n{\n    \/**\n     * @var string a reference to the slug of the widget to which the serialier is associated\n     *\/\n    private $widgetSlug;\n\n    \/**\n     * Initializes the class.\n     *\n     * @param string a reference to the slug of the widget to which the serialier is associated\n     *\/\n    public function __construct(string $widgetSlug)\n    {\n        $this-&gt;widgetSlug = $widgetSlug;\n    }\n\n    \/**\n     * Updates the values of the widget. Sanitizes the information before saving it.\n     *\n     * @param array $newInstance the array of new options to save\n     *\/\n    public function update($newInstance)\n    {\n        $instance = [];\n        foreach ($newInstance as $key =&gt; $value) {\n            $instance[$key] = strip_tags(\n                stripslashes($value)\n            );\n        }\n\n        do_action('flush_widget_cache', [$this-&gt;widgetSlug, 'widget']);\n\n        return $instance;\n    }\n}\n<\/code><\/pre>\n<p>A nast\u0119pnie w subskrybencie <a href=\"https:\/\/gist.github.com\/tommcfarlin\/39038338730b7141a19c3d2f48801dac#file-04-delete-widget-cache-subscriber-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">opr\u00f3\u017cnimy pami\u0119\u0107 podr\u0119czn\u0105<\/a> na podstawie przychodz\u0105cych argument\u00f3w:<\/p>\n<pre><code>&lt;?php\n\n&lt;?php\n\n\/*\n * This file is part of WordPress Widget Boilerplate\n * (c) Tom McFarlin &lt;tom@tommcfarlin.com&gt;\n *\n * This source file is subject to the GPL license that is bundled\n * with this source code in the file LICENSE.\n *\/\n\nnamespace WordPressWidgetBoilerplateSubscriber;\n\n\/**\n * Deletes the cached contents of the widget.\n *\/\nclass DeleteWidgetCacheSubscriber extends AbstractSubscriber\n{\n    \/**\n     * {@inheritdoc}\n     *\/\n    public function __construct(string $hook)\n    {\n        parent::__construct($hook);\n    }\n\n    \/**\n     * Flushes the widget's cache based on the key that's specified in the function arguments.\n     *\/\n    public function load()\n    {\n        \/* Because we're implementing an abstract class, we'll parse arguments from the\n         * func_get_args().\n         *\/\n        $args = func_get_args();\n        if (!$this-&gt;hasValidArguments($args)) {\n            return;\n        }\n\n        $args = $args[0];\n        wp_cache_delete($args[0], $args[1]);\n    }\n\n    \/**\n     * Verifies that we have valid arguments with which to work.\n     *\n     * @param array $args the array of arguments we are validating\n     *\n     * @return bool true if the arguments are valid; otherwise, false\n     *\/\n    private function hasValidArguments(array $args): bool\n    {\n        \/\/ First, check the initial index of the arguments.\n        if (!isset($args[0])) {\n            return false;\n        }\n\n        \/\/ Next, check the values of the arguments for the widget key and group.\n        $args = $args[0];\n        if (!isset($args[0]) &amp;&amp; !isset($args[1])) {\n            return false;\n        }\n\n        return true;\n    }\n}\n<\/code><\/pre>\n<p>I to wystarczy.<\/p>\n<h2>Gotowy na front-end<\/h2>\n<p>W tym momencie mamy mechanizm, kt\u00f3ry mo\u017ce opr\u00f3\u017cni\u0107 pami\u0119\u0107 podr\u0119czn\u0105 wid\u017cet\u00f3w, kiedy tylko zechcemy \u2013 nie tylko za pomoc\u0105 niestandardowego zdarzenia \u2013 ale tak\u017ce z dowolnymi zdarzeniami oferowanymi przez WordPress.<\/p>\n<p>Mo\u017ce si\u0119 to przyda\u0107, je\u015bli u\u017cywasz Boilerplate do czego\u015b, co b\u0119dzie u\u017cywa\u0107 buforowanego zapytania lub dowolnego innego mechanizmu buforowania i chcesz si\u0119 upewni\u0107, \u017ce zawarto\u015b\u0107 jest przejrzysta.<\/p>\n<p>Nast\u0119pnie przyjrzymy si\u0119 renderowaniu tre\u015bci na interfejsie u\u017cytkownika. Zbli\u017camy si\u0119 do ko\u0144ca refaktoryzacji Boilerplate, ale jest jeszcze troch\u0119 do zrobienia, zanim b\u0119dziemy gotowi do scalenia go z g\u0142\u00f3wn\u0105 ga\u0142\u0119zi\u0105 bazy kodu.<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">\u0179r\u00f3d\u0142o nagrywania:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/tommcfarlin.com\" class=\"external external_icon\">tommcfarlin.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dlaczego zatem WordPress pokazuje jedn\u0105 rzecz w bazie danych i jedn\u0105 rzecz w obszarze administracyjnym? Ma to zwi\u0105zek z pami\u0119ci\u0105 podr\u0119czn\u0105 wid\u017cet\u00f3w.<\/p>\n","protected":false},"author":1,"featured_media":235955,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[721,897,836],"tags":[1169],"class_list":["post-230848","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-deweloper","category-kod","category-przewodnik-dla-poczatkujacych","tag-affiai-pl"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/230848","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/comments?post=230848"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/230848\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media\/235955"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media?parent=230848"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/categories?post=230848"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/tags?post=230848"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}