{"id":231101,"date":"2022-12-21T13:24:00","date_gmt":"2022-12-21T10:24:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=231101"},"modified":"2022-12-07T10:29:37","modified_gmt":"2022-12-07T07:29:37","slug":"widgets-de-wordpress-refactorizacion-parte-11","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/es\/widgets-de-wordpress-refactorizacion-parte-11\/","title":{"rendered":"Widgets de WordPress: Refactorizaci\u00f3n, Parte 11"},"content":{"rendered":"\n<p>En la publicaci\u00f3n anterior, analizamos muchas refactorizaciones que separaron las preocupaciones en sus propias clases.<\/p>\n<p>En \u00faltima instancia, esto ayuda a mostrar c\u00f3mo podemos mantener un alto nivel de cohesi\u00f3n mientras no solo trabajamos con clases en WordPress, sino que lo hacemos junto con las API preexistentes.<\/p>\n<p>Debido a que las \u00faltimas publicaciones sobre la refactorizaci\u00f3n de la base de c\u00f3digo han sido tan largas, el conjunto actual de publicaciones se centra en cambios peque\u00f1os e incrementales y, por lo tanto, publicaciones m\u00e1s cortas y enfocadas.<\/p>\n<p>Como se mencion\u00f3 en el art\u00edculo anterior:<\/p>\n<blockquote>\n<p>Pero si actualiza la p\u00e1gina, es posible que observe que la desinfecci\u00f3n y la serializaci\u00f3n no parecen funcionar al recuperar los datos. Y eso es lo que vamos a ver en el siguiente post.<\/p>\n<\/blockquote>\n<p>As\u00ed que ah\u00ed es donde vamos a retomar en este art\u00edculo.<\/p>\n<h2>El modelo de widget de WordPress: Refactorizaci\u00f3n Parte 11<\/h2>\n<p>Antes de escribir cualquier c\u00f3digo, lo primero que debe notar es que si completa una de las \u00e1reas de contenido del widget (como el t\u00edtulo) con algo <a href=\"https:\/\/gist.github.com\/tommcfarlin\/39038338730b7141a19c3d2f48801dac#file-00-example-title-js\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">como esto<\/a> :<\/p>\n<pre><code>&lt;script type=\"text\/javascript\"&gt;This is the Title&lt;\/script&gt;<\/code><\/pre>\n<p>Y luego haga clic en Guardar, el contenido real se desinfectar\u00e1 y se escribir\u00e1 en la base de datos. Puede ver que esto es cierto mirando el valor del widget en la base de datos.<\/p>\n<p>Adem\u00e1s, los datos se ven bien a primera vista, pero si actualiza la p\u00e1gina, aparece el contenido sin desinfectar. Si navega a otra p\u00e1gina, como Men\u00fas, y luego regresa, el contenido del widget aparece pero se desinfecta correctamente.<\/p>\n<p>\u00bfPor qu\u00e9, entonces, muestra una cosa en la base de datos y otra en el front-end del \u00e1rea de administraci\u00f3n al realizar ciertos pasos?<\/p>\n<p>Esto tiene que ver con el cach\u00e9 de widgets y, afortunadamente, podemos vaciar este cach\u00e9 a voluntad usando los ganchos que queramos (es decir, podemos suscribirnos a cualquier evento y luego hacer que vac\u00ede el cach\u00e9).<\/p>\n<\/p>\n<p>De la <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/wp_cache_delete\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">referencia del c\u00f3digo<\/a> :<\/p>\n<blockquote>\n<p>Elimina el contenido de la memoria cach\u00e9 que coincide con la clave y el grupo.<\/p>\n<\/blockquote>\n<p>Tenga en cuenta, sin embargo, que requiere que proporcionemos la clave y un grupo opcional. En Boilerplate, hemos estado usando el slug del widget como clave y el grupo es widget.<\/p>\n<h3>Limpiando el cach\u00e9<\/h3>\n<p>Dado que la funci\u00f3n se puede vincular a cualquier evento, podemos crear un suscriptor que podamos vincular a cualquier evento. Esto significa <a href=\"https:\/\/gist.github.com\/tommcfarlin\/39038338730b7141a19c3d2f48801dac#file-01-delete-widget-cache-subscriber-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">que podemos crear un suscriptor DeleteWidgetCache en nuestro espacio de nombres de suscriptor:<\/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>Luego <a href=\"https:\/\/gist.github.com\/tommcfarlin\/39038338730b7141a19c3d2f48801dac#file-02-wordpress-widget-plugin-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">actualizaremos el arranque<\/a> para agregar el suscriptor al registro y usaremos un gancho personalizado, flush_widget_cache, que usaremos moment\u00e1neamente.<\/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>Para los prop\u00f3sitos de Boilerplate, usaremos el evento personalizado cada vez que se llame al c\u00f3digo de serializaci\u00f3n del widget.<\/p>\n<p>Primero, definiremos una\u00a0 llamada <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/do_action\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">do_action<\/a>, la identificaremos como flush_widget_cache y luego <a href=\"https:\/\/gist.github.com\/tommcfarlin\/39038338730b7141a19c3d2f48801dac#file-03-widget-serialization-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">pasaremos los argumentos necesarios<\/a> al evento para que el suscriptor pueda leerlos:<\/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>Y luego, en el suscriptor, <a href=\"https:\/\/gist.github.com\/tommcfarlin\/39038338730b7141a19c3d2f48801dac#file-04-delete-widget-cache-subscriber-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">vaciaremos el cach\u00e9<\/a> en funci\u00f3n de los argumentos entrantes:<\/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>Y eso lo hace.<\/p>\n<h2>Listo para el front-end<\/h2>\n<p>En este punto, contamos con un mecanismo que puede vaciar la cach\u00e9 de widgets cuando queramos, no solo con un evento personalizado, sino tambi\u00e9n con cualquiera de los eventos que ofrece WordPress.<\/p>\n<p>Esto puede ser \u00fatil si est\u00e1 utilizando Boilerplate para algo que utilizar\u00e1 una consulta en cach\u00e9 o cualquier otro mecanismo de almacenamiento en cach\u00e9, y quiere asegurarse de que el contenido sea claro.<\/p>\n<p>A continuaci\u00f3n, veremos la representaci\u00f3n de contenido en el front-end. Nos acercamos al final de la refactorizaci\u00f3n de Boilerplate, pero queda un poco m\u00e1s por hacer antes de que estemos listos para fusionarlo en la rama maestra de la base de c\u00f3digo.<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">Fuente de grabaci\u00f3n:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/tommcfarlin.com\" class=\"external external_icon\">tommcfarlin.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u00bfPor qu\u00e9, entonces, WordPress muestra una cosa en la base de datos y otra en el \u00e1rea de administraci\u00f3n? Esto tiene que ver con el cach\u00e9 de widgets.<\/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":[892,716,831],"tags":[1172],"class_list":["post-231101","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-codigo","category-desarrollador","category-guia-para-principiantes","tag-affiai-es"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts\/231101","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/comments?post=231101"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts\/231101\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/media\/235955"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/media?parent=231101"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/categories?post=231101"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/tags?post=231101"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}