{"id":43698,"date":"2021-09-22T12:34:10","date_gmt":"2021-09-22T10:34:10","guid":{"rendered":"https:\/\/kinsta.com\/?p=100908"},"modified":"2025-02-07T15:09:10","modified_gmt":"2025-02-07T14:09:10","slug":"abstraccion-en-wordpress-plugin","status":"publish","type":"post","link":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/","title":{"rendered":"Abstracci\u00f3n en WordPress: Las Mejores Pr\u00e1cticas y Plugins de Abstracci\u00f3n de WordPress"},"content":{"rendered":"<p>WordPress es un CMS antiguo, pero tambi\u00e9n el <a href=\"https:\/\/kinsta.com\/es\/cuota-de-mercado-de-wordpress\/\">m\u00e1s utilizado<\/a>. Gracias a su historia de soporte de versiones de PHP obsoletas y c\u00f3digo heredado, a\u00fan le falta implementar pr\u00e1cticas de codificaci\u00f3n modernas: la abstracci\u00f3n en WordPress es un ejemplo.<\/p>\n<p>Por ejemplo, ser\u00eda mucho mejor dividir el c\u00f3digo base de WordPress en paquetes gestionados por Composer. O tal vez, para autocargar las clases de WordPress desde las rutas de los archivos.<\/p>\n<p>Este art\u00edculo te ense\u00f1ar\u00e1 c\u00f3mo abstraer el c\u00f3digo de WordPress manualmente y utilizar las capacidades abstracci\u00f3n de los plugins de WordPress.<\/p>\n<div><\/div><kinsta-auto-toc heading=\"Table of Contents\" exclude=\"last\" list-style=\"arrow\" selector=\"h2\" count-number=\"-1\"><\/kinsta-auto-toc>\n<h2>Problemas con la integraci\u00f3n de WordPress y las herramientas PHP<\/h2>\n<p>Debido a su antigua arquitectura, ocasionalmente nos encontramos con problemas al integrar WordPress con herramientas para bases de c\u00f3digo PHP, como el analizador est\u00e1tico <a href=\"https:\/\/phpstan.org\/\">PHPStan<\/a>, la librer\u00eda de pruebas unitarias <a href=\"https:\/\/phpunit.de\/\">PHPUnit<\/a> y la librer\u00eda de b\u00fasqueda de espacios de nombres <a href=\"https:\/\/github.com\/humbug\/php-scoper\">PHP-Scoper<\/a>. Por ejemplo, considera los siguientes casos:<\/p>\n<ul>\n<li>Antes de la llegada de <a href=\"https:\/\/kinsta.com\/es\/blog\/wordpress-5-6\/\">WordPress 5.6<\/a> con soporte para <a href=\"https:\/\/kinsta.com\/es\/blog\/php-8\/\">PHP 8.0<\/a>, un informe de Yoast describ\u00eda c\u00f3mo la ejecuci\u00f3n de PHPStan en el n\u00facleo de WordPress produc\u00eda <a href=\"https:\/\/developer.yoast.com\/blog\/the-2020-wordpress-and-php-8-compatibility-report\/#h-scanning-wordpress-with-phpstan\">miles de problemas<\/a>.<\/li>\n<li>Debido a que todav\u00eda soporta PHP 5.6, las suites de prueba de WordPress actualmente <a href=\"https:\/\/core.trac.wordpress.org\/ticket\/46149\">solo soportan PHPUnit hasta la versi\u00f3n 7.5<\/a>, que ha llegado al final de su vida \u00fatil.<\/li>\n<li>El alcance de los plugins de WordPress a trav\u00e9s de PHP-Scoper <a href=\"https:\/\/github.com\/humbug\/php-scoper#wordpress\">es muy dif\u00edcil<\/a>.<\/li>\n<\/ul>\n<p>El c\u00f3digo de WordPress dentro de nuestros proyectos ser\u00e1 solo una fracci\u00f3n del total; el proyecto tambi\u00e9n contendr\u00e1 c\u00f3digo de negocio agn\u00f3stico del CMS subyacente. Sin embargo, por el mero hecho de tener algo de c\u00f3digo WordPress, el proyecto puede no integrarse con las herramientas correctamente.<\/p>\n<p>Debido a esto, podr\u00eda tener sentido dividir el proyecto en paquetes, algunos de ellos conteniendo c\u00f3digo de WordPress y otros teniendo solo c\u00f3digo de negocio usando PHP \u00abvainilla\u00bb y sin c\u00f3digo de WordPress. De esta manera, estos \u00faltimos paquetes no se ver\u00e1n afectados por los problemas descritos anteriormente, sino que podr\u00e1n integrarse perfectamente con las herramientas.<\/p>\n<h2>\u00bfQu\u00e9 es la abstracci\u00f3n del c\u00f3digo?<\/h2>\n<p>La abstracci\u00f3n del c\u00f3digo elimina las dependencias fijas del mismo, produciendo paquetes que interact\u00faan entre s\u00ed mediante contratos. Estos paquetes pueden entonces a\u00f1adirse a diferentes aplicaciones con diferentes pilas, maximizando su usabilidad. El resultado de la abstracci\u00f3n del c\u00f3digo es una base de c\u00f3digo limpiamente desacoplada, basada en los siguientes pilares:<\/p>\n<ol>\n<li>Codifica contra interfaces, no contra implementaciones.<\/li>\n<li>Crea paquetes y distribuirlos a trav\u00e9s de Composer.<\/li>\n<li>Pega todas las partes a trav\u00e9s de la inyecci\u00f3n de dependencias.<\/li>\n<\/ol>\n\n<h2>Codificar contra interfaces, no contra implementaciones<\/h2>\n<p>Codificar contra interfaces es la pr\u00e1ctica de usar contratos para que piezas de c\u00f3digo interact\u00faen entre s\u00ed. Un contrato es simplemente una interfaz de PHP (o de cualquier otro lenguaje) que define qu\u00e9 funciones est\u00e1n disponibles y sus firmas, es decir, qu\u00e9 entradas reciben y su salida.<\/p>\n<p>Una interfaz declara la intenci\u00f3n de la funcionalidad sin explicar c\u00f3mo se implementar\u00e1 la funcionalidad. Al acceder a la funcionalidad a trav\u00e9s de interfaces, nuestra <a href=\"https:\/\/kinsta.com\/es\/blog\/monitoreo-rendimiento-aplicaciones\/\">aplicaci\u00f3n<\/a> puede confiar en piezas de c\u00f3digo aut\u00f3nomas que cumplen un objetivo espec\u00edfico sin saber, o preocuparse, de c\u00f3mo lo hacen. De este modo, la aplicaci\u00f3n no necesita adaptarse para cambiar a otra pieza de c\u00f3digo que logre el mismo objetivo, por ejemplo, de un proveedor diferente.<\/p>\n<h3>Ejemplo de contratos<\/h3>\n<p>El siguiente c\u00f3digo utiliza el contrato <code><a href=\"https:\/\/github.com\/symfony\/symfony\/blob\/302b844\/src\/Symfony\/Contracts\/Cache\/CacheInterface.php\">CacheInterface<\/a><\/code> de Symfony y el contrato <code><a href=\"https:\/\/github.com\/php-fig\/cache\/blob\/0a7c67d\/src\/CacheItemInterface.php\">CacheItemInterface<\/a><\/code> de la Recomendaci\u00f3n Est\u00e1ndar de PHP (PSR) para implementar la funcionalidad de la cach\u00e9:<\/p>\n<pre><code class=\"language-php\">use Psr\\Cache\\CacheItemInterface;\nuse Symfony\\Contracts\\Cache\\CacheInterface;\n\n$value = $cache-&gt;get('my_cache_key', function (CacheItemInterface $item) {\n    $item-&gt;expiresAfter(3600);\n    return 'foobar';\n});<\/code><\/pre>\n<p><code>$cache<\/code> implementa <code>CacheInterface<\/code>, que define el m\u00e9todo <code>get<\/code> para recuperar un objeto de la cach\u00e9. Al acceder a esta funcionalidad a trav\u00e9s del contrato, la aplicaci\u00f3n puede ser ajena a d\u00f3nde est\u00e1 la cach\u00e9. Ya sea en la memoria, en el disco, en la base de datos, en la red o en cualquier otro lugar. Aun as\u00ed, tiene que realizar la funci\u00f3n. <code>CacheItemInterface<\/code> define el m\u00e9todo <code>expiresAfter<\/code> para declarar cu\u00e1nto tiempo debe mantenerse el elemento en la cach\u00e9. La aplicaci\u00f3n puede invocar este m\u00e9todo sin importarle cu\u00e1l es el objeto almacenado en la cach\u00e9; solo le importa el tiempo que debe permanecer en ella.<\/p>\n<h2>Codificar contra interfaces en WordPress<\/h2>\n<p>Como estamos abstrayendo el c\u00f3digo de WordPress, el resultado ser\u00e1 que la aplicaci\u00f3n no har\u00e1 referencia al <a href=\"https:\/\/kinsta.com\/es\/blog\/editar-codigo-wordpress\/\">c\u00f3digo de WordPress<\/a> directamente, sino siempre a trav\u00e9s de una interfaz. Por ejemplo, la funci\u00f3n de WordPress <code>get_posts<\/code> tiene esta firma:<\/p>\n<pre><code class=\"language-php\">\/**\n * @param array $args\n * @return WP_Post[]|int[] Array of post objects or post IDs.\n *\/\nfunction get_posts( $args = null )\n<\/code><\/pre>\n<p>En lugar de invocar este m\u00e9todo directamente, podemos acceder a \u00e9l a trav\u00e9s del contrato <code>Owner\\MyApp\\Contracts\\PostsAPIInterface<\/code>:<\/p>\n<pre><code class=\"language-php\">namespace Owner\\MyApp\\Contracts;\n\ninterface PostAPIInterface\n{\n  public function get_posts(array $args = null): PostInterface[]|int[];\n}<\/code><\/pre>\n<p>Ten en cuenta que la funci\u00f3n de WordPress <code>get_posts<\/code> puede devolver objetos de la clase <code>WP_Post<\/code>, que es espec\u00edfica de WordPress. Al abstraer el c\u00f3digo, tenemos que eliminar este tipo de dependencia fija. El m\u00e9todo <code>get_posts<\/code> en el contrato devuelve objetos del tipo <code>PostInterface<\/code>, lo que le permite hacer referencia a la clase <code>WP_Post<\/code> sin ser expl\u00edcito al respecto. La clase <code>PostInterface<\/code> tendr\u00e1 que proporcionar acceso a todos los m\u00e9todos y atributos de <code>WP_Post<\/code>:<\/p>\n<pre><code class=\"language-php\">namespace Owner\\MyApp\\Contracts;\n\ninterface PostInterface\n{\n  public function get_ID(): int;\n  public function get_post_author(): string;\n  public function get_post_date(): string;\n  \/\/ ...\n}\n<\/code><\/pre>\n<p>La ejecuci\u00f3n de esta estrategia puede cambiar nuestra comprensi\u00f3n de d\u00f3nde encaja WordPress en nuestra pila. En lugar de pensar en WordPress como la propia aplicaci\u00f3n (sobre la que instalamos temas y plugins), podemos pensar en \u00e9l simplemente como una dependencia m\u00e1s dentro de la aplicaci\u00f3n, reemplazable como cualquier otro componente. (Aunque no vayamos a sustituir WordPress en la pr\u00e1ctica, <em>es <\/em>reemplazable desde un punto de vista conceptual).<\/p>\n<h2>Creaci\u00f3n y distribuci\u00f3n de paquetes<\/h2>\n<p><a href=\"https:\/\/getcomposer.org\/\">Composer<\/a> es un gestor de paquetes para PHP. Permite a las aplicaciones PHP recuperar paquetes (es decir, piezas de c\u00f3digo) de un repositorio e instalarlos como dependencias. Para desacoplar la aplicaci\u00f3n de WordPress, debemos distribuir su c\u00f3digo en paquetes de dos tipos diferentes: los que contienen el c\u00f3digo de WordPress y los que contienen la l\u00f3gica de negocio (es decir, sin c\u00f3digo de WordPress).<\/p>\n<p>Finalmente, a\u00f1adimos todos los paquetes como dependencias en la aplicaci\u00f3n, y los instalamos a trav\u00e9s de Composer. Dado que las herramientas se aplicar\u00e1n a los paquetes de c\u00f3digo empresarial, \u00e9stos deben contener la mayor parte del c\u00f3digo de la aplicaci\u00f3n; cuanto mayor sea el porcentaje, mejor. Que gestionen alrededor del 90% del c\u00f3digo total es un buen objetivo.<\/p>\n<h2>C\u00f3mo extraer el c\u00f3digo de WordPress en paquetes<\/h2>\n<p>Siguiendo el ejemplo de antes, los contratos <code>PostAPIInterface<\/code> y <code>PostInterface<\/code> se a\u00f1adir\u00e1n al paquete que contiene el c\u00f3digo de negocio, y otro paquete incluir\u00e1 la implementaci\u00f3n de estos contratos en WordPress. Para satisfacer <code>PostInterface<\/code>, creamos una clase <code>PostWrapper<\/code> que recuperar\u00e1 todos los atributos de un objeto <code>WP_Post<\/code>:<\/p>\n<pre><code class=\"language-php\">namespace Owner\\MyAppForWP\\ContractImplementations;\n\nuse Owner\\MyApp\\Contracts\\PostInterface;\nuse WP_Post;\n\nclass PostWrapper implements PostInterface\n{\n  private WP_Post $post;\n  \n  public function __construct(WP_Post $post)\n  {\n    $this-&gt;post = $post;\n  }\n\n  public function get_ID(): int\n  {\n    return $this-&gt;post-&gt;ID;\n  }\n\n  public function get_post_author(): string\n  {\n    return $this-&gt;post-&gt;post_author;\n  }\n\n  public function get_post_date(): string\n  {\n    return $this-&gt;post-&gt;post_date;\n  }\n\n  \/\/ ...\n}<\/code><\/pre>\n<p>Al implementar <code>PostAPI<\/code>, como el m\u00e9todo <code>get_posts<\/code> devuelve <code>PostInterface[]<\/code>, debemos convertir los objetos de <code>WP_Post<\/code> a <code>PostWrapper<\/code>:<\/p>\n<pre><code class=\"language-php\">namespace Owner\\MyAppForWP\\ContractImplementations;\n\nuse Owner\\MyApp\\Contracts\\PostAPIInterface;\nuse WP_Post;\n\nclass PostAPI implements PostAPIInterface\n{\n  public function get_posts(array $args = null): PostInterface[]|int[]\n  {\n    \/\/ This var will contain WP_Post[] or int[]\n    $wpPosts = \\get_posts($args);\n\n    \/\/ Convert WP_Post[] to PostWrapper[]\n    return array_map(\n      function (WP_Post|int $post) {\n        if ($post instanceof WP_Post) {\n          return new PostWrapper($post);\n        }\n        return $post\n      },\n      $wpPosts\n    );\n  }\n}\n<\/code><\/pre>\n<h2>Uso de la inyecci\u00f3n de dependencia<\/h2>\n<p>La inyecci\u00f3n de dependencias es un patr\u00f3n de dise\u00f1o que permite unir todas las partes de la aplicaci\u00f3n de forma poco acoplada. Con la inyecci\u00f3n de dependencia, la aplicaci\u00f3n accede a los servicios a trav\u00e9s de sus contratos, y las implementaciones de los contratos se \u00abinyectan\u00bb en la aplicaci\u00f3n a trav\u00e9s de la configuraci\u00f3n.<\/p>\n<p>Simplemente cambiando la configuraci\u00f3n, podemos cambiar f\u00e1cilmente de un proveedor de contratos a otro. Hay varias bibliotecas de inyecci\u00f3n de dependencia que podemos elegir. Aconsejamos seleccionar una que se adhiera a las <a href=\"https:\/\/www.php-fig.org\/\">Recomendaciones Est\u00e1ndar de PHP<\/a> (a menudo denominadas \u00abPSR\u00bb), de modo que podamos sustituir f\u00e1cilmente la biblioteca por otra si surge la necesidad. Con respecto a la inyecci\u00f3n de dependencias, la biblioteca debe satisfacer la <a href=\"https:\/\/www.php-fig.org\/psr\/psr-11\/\">PSR-11<\/a>, que proporciona la especificaci\u00f3n para una \u00abinterfaz de contenedor\u00bb. Entre otras, las siguientes bibliotecas cumplen con PSR-11:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/symfony\/dependency-injection\">Dependency Injection de Symfony<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/PHP-DI\/PHP-DI\">PHP-DI<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/auraphp\/Aura.Di\">Aura.Di<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/thephpleague\/container\">Contenedor (inyecci\u00f3n de dependencia)<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/yiisoft\/di\">Inyecci\u00f3n de dependencia en Yii<\/a><\/li>\n<\/ul>\n<h3>Acceso a los servicios a trav\u00e9s del contenedor de servicios<\/h3>\n<p>La biblioteca de inyecci\u00f3n de dependencias pondr\u00e1 a disposici\u00f3n un \u00abcontenedor de servicios\u00bb, que resuelve un contrato en su correspondiente clase implementadora. La aplicaci\u00f3n debe confiar en el contenedor de servicios para acceder a toda la funcionalidad. Por ejemplo, mientras que normalmente invocar\u00edamos las funciones de WordPress directamente:<\/p>\n<pre><code class=\"language-php\">$posts = get_posts();\n<\/code><\/pre>\n<p>&#8230; con el contenedor de servicios, primero debemos obtener el servicio que satisface <code>PostAPIInterface<\/code> y ejecutar la funcionalidad a trav\u00e9s de \u00e9l:<\/p>\n<pre><code class=\"language-php\">use Owner\\MyApp\\Contracts\\PostAPIInterface;\n\n\/\/ Obtain the service container, as specified by the library we use\n$serviceContainer = ContainerBuilderFactory::getInstance();\n\n\/\/ The obtained service will be of class Owner\\MyAppForWP\\ContractImplementations\\PostAPI\n$postAPI = $serviceContainer-&gt;get(PostAPIInterface::class);\n\n\/\/ Now we can invoke the WordPress functionality\n$posts = $postAPI-&gt;get_posts();\n<\/code><\/pre>\n<h3>Uso de DependencyInjection de Symfony<\/h3>\n<p><a href=\"https:\/\/symfony.com\/doc\/current\/components\/dependency_injection.html\">El componente Dependency Injection de Symfony<\/a> es actualmente la biblioteca de inyecci\u00f3n de dependencia m\u00e1s popular. Permite configurar el contenedor de servicios mediante c\u00f3digo PHP, YAML o XML. Por ejemplo, para definir que el contrato <code>PostAPIInterface<\/code> se satisfaga a trav\u00e9s de la clase <code>PostAPI<\/code> se configura en YAML as\u00ed<\/p>\n<pre><code class=\"language-yaml\">services:\n  Owner\\MyApp\\Contracts\\PostAPIInterface:\n    class: \\Owner\\MyAppForWP\\ContractImplementations\\PostAPI\n<\/code><\/pre>\n<p>El DependencyInjection de Symfony tambi\u00e9n permite que las instancias de un servicio se inyecten autom\u00e1ticamente (o \u00abautowired\u00bb) en cualquier otro servicio que dependa de \u00e9l. Adem\u00e1s, facilita la definici\u00f3n de que una clase es una implementaci\u00f3n de su propio servicio. Por ejemplo, considera la <a href=\"https:\/\/github.com\/leoloso\/PoP\/blob\/8602e9041ac92f4683966eed5c4a90686b9395fa\/layers\/GraphQLAPIForWP\/plugins\/graphql-api-for-wp\/config\/hybrid-services.yaml\">siguiente configuraci\u00f3n YAML<\/a>:<\/p>\n<pre><code class=\"language-yaml\">services:\n  _defaults:\n    public: true\n    autowire: true\n\n  GraphQLAPI\\GraphQLAPI\\Registries\\UserAuthorizationSchemeRegistryInterface:\n    class: '\\GraphQLAPI\\GraphQLAPI\\Registries\\UserAuthorizationSchemeRegistry'\n\n  GraphQLAPI\\GraphQLAPI\\Security\\UserAuthorizationInterface:\n    class: '\\GraphQLAPI\\GraphQLAPI\\Security\\UserAuthorization'\n    \n  GraphQLAPI\\GraphQLAPI\\Security\\UserAuthorizationSchemes\\:\n    resource: '..\/src\/Security\/UserAuthorizationSchemes\/*'\n<\/code><\/pre>\n<p>Esta configuraci\u00f3n define lo siguiente:<\/p>\n<ul>\n<li>El contrato <code>UserAuthorizationSchemeRegistryInterface<\/code> se cumple a trav\u00e9s de la clase <code>UserAuthorizationSchemeRegistry<\/code><\/li>\n<li>El contrato <code>UserAuthorizationInterface<\/code> se cumple a trav\u00e9s de la clase <code>UserAuthorization<\/code><\/li>\n<li>Todas las clases de la carpeta <code>UserAuthorizationSchemes\/<\/code> son una implementaci\u00f3n de s\u00ed mismas<\/li>\n<li>Los servicios deben inyectarse autom\u00e1ticamente entre s\u00ed (<code>autowire: true<\/code>)<\/li>\n<\/ul>\n<p>Veamos c\u00f3mo funciona el autocableado. La clase <code><a href=\"https:\/\/github.com\/leoloso\/PoP\/blob\/bd56f23b52a3e02966fdcbde4bc58f246a47a6e5\/layers\/GraphQLAPIForWP\/plugins\/graphql-api-for-wp\/src\/Security\/UserAuthorization.php\">UserAuthorization<\/a><\/code> depende de un <code>UserAuthorizationSchemeRegistryInterface<\/code>:<\/p>\n<pre><code class=\"language-php\">class UserAuthorization implements UserAuthorizationInterface\n{\n  public function __construct(\n      protected UserAuthorizationSchemeRegistryInterface $userAuthorizationSchemeRegistry\n  ) {\n  }\n\n  \/\/ ...\n}\n<\/code><\/pre>\n<p>Gracias a <code>autowire: true<\/code>, el componente DependencyInjection har\u00e1 que el servicio <code>UserAuthorization<\/code> reciba autom\u00e1ticamente su dependencia necesaria, que es una instancia de <code>UserAuthorizationSchemeRegistry<\/code>.<\/p>\n<h2>Cu\u00e1ndo hay que abstraer<\/h2>\n<p>Abstraer el c\u00f3digo podr\u00eda consumir un tiempo y un esfuerzo considerables, por lo que solo deber\u00edamos llevarlo a cabo cuando sus beneficios superen sus costes. A continuaci\u00f3n se sugieren los casos en los que abstraer el c\u00f3digo puede merecer la pena. Puedes hacerlo utilizando los fragmentos de c\u00f3digo de este art\u00edculo o los plugins de WordPress abstractos sugeridos a continuaci\u00f3n.<\/p>\n<h3>Acceso a las herramientas<\/h3>\n<p>Como se ha mencionado anteriormente, <a href=\"https:\/\/github.com\/humbug\/php-scoper\/issues\/303\">ejecutar PHP-Scoperen WordPress es dif\u00edcil<\/a>. Al desacoplar el c\u00f3digo de WordPress en paquetes distintivos, se hace factible el <a href=\"https:\/\/graphql-api.com\/blog\/graphql-api-for-wp-is-now-scoped-thanks-to-php-scoper\/\">alcance de un plugin de WordPress<\/a> directamente.<\/p>\n<h3>Reducir el tiempo y el coste de las herramientas<\/h3>\n<p>Ejecutar un conjunto de pruebas PHPUnit lleva m\u00e1s tiempo cuando tiene que inicializar y ejecutar WordPress que cuando no lo hace. Menos tiempo tambi\u00e9n puede traducirse en menos dinero gastado en la ejecuci\u00f3n de las pruebas: por ejemplo, <a href=\"https:\/\/kinsta.com\/es\/blog\/que-es-github\/\">GitHub<\/a> Actions cobra por los ejecutores alojados en GitHub en funci\u00f3n del tiempo de uso.<\/p>\n<h3>No es necesaria una refactorizaci\u00f3n intensa<\/h3>\n<p>Un proyecto existente puede requerir una fuerte refactorizaci\u00f3n para introducir la arquitectura necesaria (inyecci\u00f3n de dependencias, divisi\u00f3n del c\u00f3digo en paquetes, etc.), lo que dificulta su extracci\u00f3n. Abstraer el c\u00f3digo al crear un proyecto desde cero lo hace mucho m\u00e1s manejable.<\/p>\n<h3>Producci\u00f3n de c\u00f3digo para m\u00faltiples plataformas<\/h3>\n<p>Al extraer el 90% del c\u00f3digo en un paquete agn\u00f3stico para el CMS, podemos producir una versi\u00f3n de la biblioteca que funcione para un CMS o un marco de trabajo diferente sustituyendo solo el 10% de la base de c\u00f3digo general.<\/p>\n<h3>Migraci\u00f3n a una plataforma diferente<\/h3>\n<p>Si tenemos que migrar un proyecto de <a href=\"https:\/\/kinsta.com\/es\/blog\/wordpress-vs-drupal\/\">Drupal a WordPress<\/a>, de WordPress a <a href=\"https:\/\/kinsta.com\/es\/blog\/laravel-9\/\">Laravel<\/a>, o cualquier otra combinaci\u00f3n, solo hay que reescribir el 10% del c\u00f3digo, lo que supone un ahorro importante.<\/p>\n<h2>Mejores pr\u00e1cticas<\/h2>\n<p>Al dise\u00f1ar los contratos para abstraer nuestro c\u00f3digo, hay varias mejoras que podemos aplicar a la base de c\u00f3digo.<\/p>\n<h3>Adherirse al PSR-12<\/h3>\n<p>A la hora de definir la interfaz para acceder a los m\u00e9todos de WordPress, debemos adherirnos a la norma <a href=\"https:\/\/www.php-fig.org\/psr\/psr-12\/\">PSR-12<\/a>. Esta reciente especificaci\u00f3n pretende reducir la fricci\u00f3n cognitiva cuando se analiza el c\u00f3digo de diferentes autores. Adherirse a PSR-12 implica cambiar el nombre de las funciones de WordPress.<\/p>\n<p>WordPress nombra las funciones utilizando <strong>snake_case<\/strong>, mientras que PSR-12 utiliza <strong>camelCase<\/strong>. Por lo tanto, la funci\u00f3n <code>get_posts<\/code> se convertir\u00e1 en <code>getPosts<\/code>:<\/p>\n<pre><code class=\"language-php\">interface PostAPIInterface\n{\n  public function getPosts(array $args = null): PostInterface[]|int[];\n}\n<\/code><\/pre>\n<p>&#8230;y:<\/p>\n<pre><code class=\"language-php\">class PostAPI implements PostAPIInterface\n{\n  public function getPosts(array $args = null): PostInterface[]|int[]\n  {\n    \/\/ This var will contain WP_Post[] or int[]\n    $wpPosts = \\get_posts($args);\n\n    \/\/ Rest of the code\n    \/\/ ...\n  }\n}\n<\/code><\/pre>\n<h3>M\u00e9todos de divisi\u00f3n<\/h3>\n<p>Los m\u00e9todos de la interfaz no tienen por qu\u00e9 ser una r\u00e9plica de los de WordPress. Podemos transformarlos siempre que tenga sentido. Por ejemplo, la funci\u00f3n de WordPress <code>get_user_by($field, $value)<\/code> sabe c\u00f3mo recuperar el usuario de la base de datos a trav\u00e9s del par\u00e1metro <code>$field<\/code>, que acepta los valores <code>\"id\"<\/code>, <code>\"ID\"<\/code>, <code>\"slug\"<\/code>, <code>\"email\"<\/code> o <code>\"login\"<\/code>. Este dise\u00f1o tiene algunos problemas:<\/p>\n<ul>\n<li>No fallar\u00e1 en el momento de la compilaci\u00f3n si pasamos una cadena incorrecta<\/li>\n<li>El par\u00e1metro <code>$value<\/code> necesita aceptar todos los tipos diferentes para todas las opciones, aunque al pasar <code>\"ID\"<\/code> espera un <code>int<\/code>, al pasar <code>\"email\"<\/code> solo puede recibir una cadena<\/li>\n<\/ul>\n<p>Podemos mejorar esta situaci\u00f3n dividiendo la funci\u00f3n en varias:<\/p>\n<pre><code class=\"language-php\">namespace Owner\\MyApp\\Contracts;\n\ninterface UserAPIInterface\n{\n  public function getUserById(int $id): ?UserInterface;\n  public function getUserByEmail(string $email): ?UserInterface;\n  public function getUserBySlug(string $slug): ?UserInterface;\n  public function getUserByLogin(string $login): ?UserInterface;\n}\n<\/code><\/pre>\n<p>El contrato se resuelve para WordPress as\u00ed (asumiendo que hemos creado <code>UserWrapper<\/code> y <code>UserInterface<\/code>, como se explic\u00f3 anteriormente):<\/p>\n<pre><code class=\"language-php\">namespace Owner\\MyAppForWP\\ContractImplementations;\n\nuse Owner\\MyApp\\Contracts\\UserAPIInterface;\n\nclass UserAPI implements UserAPIInterface\n{\n  public function getUserById(int $id): ?UserInterface\n  {\n    return $this-&gt;getUserByProp('id', $id);\n  }\n\n  public function getUserByEmail(string $email): ?UserInterface\n  {\n    return $this-&gt;getUserByProp('email', $email);\n  }\n\n  public function getUserBySlug(string $slug): ?UserInterface\n  {\n    return $this-&gt;getUserByProp('slug', $slug);\n  }\n\n  public function getUserByLogin(string $login): ?UserInterface\n  {\n    return $this-&gt;getUserByProp('login', $login);\n  }\n\n  private function getUserByProp(string $prop, int|string $value): ?UserInterface\n  {\n    if ($user = \\get_user_by($prop, $value)) {\n      return new UserWrapper($user);\n    }\n    return null;\n  }\n}\n<\/code><\/pre>\n<h3>Eliminar los detalles de implementaci\u00f3n de la firma de la funci\u00f3n<\/h3>\n<p>Las funciones en WordPress pueden proporcionar informaci\u00f3n sobre c\u00f3mo se implementan en su propia firma. Esta informaci\u00f3n puede eliminarse al valorar la funci\u00f3n desde una perspectiva abstracta. Por ejemplo, la obtenci\u00f3n del apellido del usuario en WordPress se realiza llamando a <code>get_the_author_meta<\/code>, haciendo expl\u00edcito que el apellido de un usuario se almacena como un valor \u00abmeta\u00bb (en la tabla <code>wp_usermeta<\/code>):<\/p>\n<pre><code class=\"language-php\">$userLastname = get_the_author_meta(\"user_lastname\", $user_id);\n<\/code><\/pre>\n<p>No es necesario transmitir esta informaci\u00f3n al contrato. Las interfaces solo se preocupan por el que, no por el c\u00f3mo. Por lo tanto, el contrato puede tener un m\u00e9todo <code>getUserLastname<\/code>, que no proporciona ninguna informaci\u00f3n sobre c\u00f3mo se implementa:<\/p>\n<pre><code class=\"language-php\">interface UserAPIInterface\n{\n  public function getUserLastname(UserWrapper $userWrapper): string;\n  ...\n}\n<\/code><\/pre>\n<h3>A\u00f1adir tipos m\u00e1s estrictos<\/h3>\n<p>Algunas funciones de WordPress pueden recibir par\u00e1metros de diferentes maneras, lo que lleva a la ambig\u00fcedad. Por ejemplo, la funci\u00f3n <code>add_query_arg<\/code> puede recibir una sola clave y un valor:<\/p>\n<pre><code class=\"language-php\">$url = add_query_arg('id', 5, $url);\n<\/code><\/pre>\n<p>&#8230; o un array de <code>key =&gt; value<\/code>:<\/p>\n<pre><code class=\"language-php\">$url = add_query_arg(['id' =&gt; 5], $url);\n<\/code><\/pre>\n<p>Nuestra interfaz puede definir una intenci\u00f3n m\u00e1s comprensible dividiendo dichas funciones en varias separadas, cada una de las cuales acepta una combinaci\u00f3n \u00fanica de entradas:<\/p>\n<pre><code class=\"language-php\">public function addQueryArg(string $key, string $value, string $url);\npublic function addQueryArgs(array $keyValues, string $url);\n<\/code><\/pre>\n<h3>Eliminar la deuda t\u00e9cnica<\/h3>\n<p>La funci\u00f3n de WordPress <code>get_posts<\/code> no solo devuelve \u00abposts\u00bb sino tambi\u00e9n \u00abp\u00e1ginas\u00bb o cualquier entidad de tipo \u00abcustom posts\u00bb, y estas entidades no son intercambiables. Tanto los posts como las p\u00e1ginas son posts personalizados, pero una p\u00e1gina no es un post y no es una p\u00e1gina. Por lo tanto, ejecutar <code>get_posts<\/code> puede devolver p\u00e1ginas. Este comportamiento es una discrepancia conceptual.<\/p>\n<p>Para hacerlo correctamente, <code>get_posts<\/code> deber\u00eda llamarse <code>get_customposts<\/code>, pero nunca se le cambi\u00f3 el nombre en el n\u00facleo de WordPress. Es un problema com\u00fan con la mayor\u00eda del software de larga duraci\u00f3n y se llama \u00abdeuda t\u00e9cnica\u00bb &#8211; c\u00f3digo que tiene problemas, pero nunca se arregla porque introduce cambios de ruptura.<\/p>\n<p>Sin embargo, al crear nuestros contratos, tenemos la oportunidad de evitar este tipo de deuda t\u00e9cnica. En este caso, podemos crear una nueva interfaz <code>ModelAPIInterface<\/code> que pueda tratar con entidades de diferentes tipos, y hacemos varios m\u00e9todos, cada uno para tratar con un tipo diferente:<\/p>\n<pre><code class=\"language-php\">interface ModelAPIInterface\n{\n  public function getPosts(array $args): array;\n  public function getPages(array $args): array;\n  public function getCustomPosts(array $args): array;\n}\n<\/code><\/pre>\n<p>De esta manera, la discrepancia no se producir\u00e1 m\u00e1s, y ver\u00e1s estos resultados:<\/p>\n<ul>\n<li><code>getPosts<\/code> devuelve solo los mensajes<\/li>\n<li><code>getPages<\/code> devuelve solo las p\u00e1ginas<\/li>\n<li><code>getCustomPosts<\/code> devuelve tanto las entradas como las p\u00e1ginas<\/li>\n<\/ul>\n<h2>Ventajas de abstraer el c\u00f3digo<\/h2>\n<p>Las principales ventajas de abstraer el c\u00f3digo de una aplicaci\u00f3n son:<\/p>\n<ul>\n<li>Las herramientas que se ejecutan en paquetes que s\u00f3lo contienen c\u00f3digo empresarial son m\u00e1s f\u00e1ciles de configurar y tardar\u00e1n menos tiempo (y menos dinero) en funcionar.<\/li>\n<li>Podemos utilizar herramientas que no funcionan con WordPress, como por ejemplo el scoping de un plugin con PHP-Scoper.<\/li>\n<li>Los paquetes que producimos pueden ser aut\u00f3nomos para utilizarlos en otras aplicaciones f\u00e1cilmente.<\/li>\n<li>Migrar una aplicaci\u00f3n a otras plataformas es m\u00e1s f\u00e1cil.<\/li>\n<li>Podemos dejar de pensar en WordPress para pensar en la l\u00f3gica de nuestro negocio.<\/li>\n<li>Los contratos describen la intenci\u00f3n de la aplicaci\u00f3n, haci\u00e9ndola m\u00e1s comprensible.<\/li>\n<li>La aplicaci\u00f3n se organiza a trav\u00e9s de paquetes, creando una aplicaci\u00f3n ligera que contenga lo m\u00ednimo y mejor\u00e1ndola progresivamente seg\u00fan sea necesario.<\/li>\n<li>Podemos eliminar la deuda t\u00e9cnica.<\/li>\n<\/ul>\n<h2>Problemas con la abstracci\u00f3n del c\u00f3digo<\/h2>\n<p>Las desventajas de abstraer el c\u00f3digo de una aplicaci\u00f3n son:<\/p>\n<ul>\n<li>Al principio supone una cantidad considerable de trabajo.<\/li>\n<li>El c\u00f3digo se vuelve m\u00e1s verboso; se a\u00f1aden capas adicionales de c\u00f3digo para conseguir el mismo resultado.<\/li>\n<li>Puedes acabar produciendo <a href=\"https:\/\/graphql-api.com\/blog\/why-to-support-cms-agnosticism-the-graphql-api-split-to-around-90-packages\/\">docenas de paquetes<\/a> que luego hay que gestionar y mantener.<\/li>\n<li>Es posible que necesites un monorepo para gestionar todos los paquetes juntos.<\/li>\n<li>La inyecci\u00f3n de dependencia podr\u00eda ser excesiva para aplicaciones simples (rendimientos decrecientes).<\/li>\n<li>Abstraer el c\u00f3digo nunca se lograr\u00e1 del todo, ya que suele haber una preferencia general impl\u00edcita en la arquitectura del CMS.<\/li>\n<\/ul>\n<h2>Opciones de los plugins abstracci\u00f3n de WordPress<\/h2>\n<p>Aunque por lo general lo m\u00e1s sensato es extraer tu c\u00f3digo a un <a href=\"https:\/\/kinsta.com\/es\/blog\/instalar-wordpress-localmente\/\">entorno local<\/a> antes de trabajar en \u00e9l, algunos plugins de WordPress pueden ayudarte a conseguir tus objetivos de abstracci\u00f3n. Estas son nuestras principales selecciones.<\/p>\n<h3>1. WPide<\/h3>\n<p>Producido por WebFactory Ltd, el popular <a href=\"https:\/\/wordpress.org\/plugins\/wpide\/\">plugin WPide<\/a> ampl\u00eda notablemente la funcionalidad del editor de c\u00f3digo por defecto de WordPress. Sirve como un plugin abstracto de WordPress al permitirte ver tu c\u00f3digo in situ para visualizar mejor lo que necesita atenci\u00f3n.<\/p>\n<figure>\n<p><figure style=\"width: 900px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2021\/08\/wpide-plugin.jpg\" alt=\"El plugin WPide.\" width=\"900\" height=\"291\"><figcaption class=\"wp-caption-text\">El plugin WPide.<\/figcaption><\/figure><\/figure>\n<p>WPide tambi\u00e9n dispone de una funci\u00f3n de b\u00fasqueda y sustituci\u00f3n para localizar r\u00e1pidamente el c\u00f3digo obsoleto o caducado y sustituirlo por una versi\u00f3n refactorizada.<\/p>\n<p>Adem\u00e1s de esto, WPide proporciona un mont\u00f3n de caracter\u00edsticas adicionales, incluyendo:<\/p>\n<ul>\n<li>Resaltado de sintaxis y bloques<\/li>\n<li><a href=\"https:\/\/kinsta.com\/es\/docs\/alojamiento-wordpress\/copias-de-seguridad-wordpress\/#wordpress-backup\">Copias de seguridad autom\u00e1ticas<\/a><\/li>\n<li>Creaci\u00f3n de archivos y carpetas<\/li>\n<li>Completo explorador de archivos<\/li>\n<li>Acceso a la API del sistema de archivos de WordPress<\/li>\n<\/ul>\n<h3>2. Ultimate DB Manager<\/h3>\n<p>El <a href=\"https:\/\/wordpress.org\/plugins\/ultimate-db-manager-lite\/\">plugin Ultimate WP DB Manager<\/a> de WPHobby te ofrece una forma r\u00e1pida de descargar tus bases de datos en su totalidad para su extracci\u00f3n y refactorizaci\u00f3n.<\/p>\n<figure>\n<p><figure style=\"width: 900px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/kinsta.com\/wp-content\/uploads\/2021\/08\/ultimate-db-manager-plugin.jpg\" alt=\"El plugin Ultimate DB Manager.\" width=\"900\" height=\"250\"><figcaption class=\"wp-caption-text\">El plugin Ultimate DB Manager.<\/figcaption><\/figure><\/figure>\n<p>Por supuesto, los plugins de este tipo no son necesarios para los usuarios de Kinsta, ya que Kinsta ofrece <a href=\"https:\/\/kinsta.com\/es\/docs\/alojamiento-wordpress\/gestion-de-bases-de-datos\/acceso-a-la-base-de-datos-de-wordpress\/\">acceso directo a la base de datos<\/a> a todos los clientes. Sin embargo, si no tienes suficiente acceso a la base de datos a trav\u00e9s de tu proveedor de alojamiento, Ultimate DB Manager podr\u00eda ser \u00fatil como un plugin abstracto de WordPress.<\/p>\n<h3>3. Tu propio plugin de WordPress abstracto personalizado<\/h3>\n<p>Al final, la mejor opci\u00f3n para la abstracci\u00f3n siempre ser\u00e1 crear tu plugin. Puede parecer una gran empresa, pero si tienes una capacidad limitada para gestionar los archivos del n\u00facleo de WordPress directamente, esto ofrece una soluci\u00f3n de abstracci\u00f3n.<\/p>\n<p>Hacerlo tiene claros beneficios:<\/p>\n<ul>\n<li>Extrae tus funciones de los archivos de su tema<\/li>\n<li>Conserva tu c\u00f3digo a trav\u00e9s de los cambios de tema y las actualizaciones de la base de datos<\/li>\n<\/ul>\n<p>Puedes aprender a crear tu plugin abstracto de WordPress a trav\u00e9s <a href=\"https:\/\/developer.wordpress.org\/plugins\/\">Manual del Desarrollador de Plugins de WordPress<\/a>.<\/p>\n\n<h2>Resumen<\/h2>\n<p>\u00bfDebemos abstraer el c\u00f3digo de nuestras aplicaciones? Como con todo, no hay una \u00abrespuesta correcta\u00bb predefinida, ya que depende de cada proyecto. Aquellos proyectos que requieren una enorme cantidad de tiempo para analizar con PHPUnit o PHPStan pueden ser los m\u00e1s beneficiados, pero el esfuerzo necesario para llevarlo a cabo no siempre merece la pena.<\/p>\n<p>Has aprendido todo lo que necesitas saber para empezar a abstraer el c\u00f3digo de WordPress.<\/p>\n<p><em>\u00bfPiensas aplicar esta estrategia en tu proyecto? Si es as\u00ed, \u00bfutilizar\u00e1s un plugin abstracto de WordPress? H\u00e1znoslo saber en la secci\u00f3n de comentarios.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>WordPress es un CMS antiguo, pero tambi\u00e9n el m\u00e1s utilizado. Gracias a su historia de soporte de versiones de PHP obsoletas y c\u00f3digo heredado, a\u00fan le &#8230;<\/p>\n","protected":false},"author":196,"featured_media":43704,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kinsta_gated_content":false,"_kinsta_gated_content_redirect":"","footnotes":""},"tags":[410,403],"topic":[1345,1352],"class_list":["post-43698","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-code","tag-web-development","topic-desarrollo-wordpress","topic-plugins-wordpress"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v24.6 (Yoast SEO v24.6) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Abstracci\u00f3n en WordPress: Las Mejores Pr\u00e1cticas y Plugins de Abstracci\u00f3n de WordPress<\/title>\n<meta name=\"description\" content=\"Aprende a utilizar fragmentos de c\u00f3digo o un plugin de abstracci\u00f3n de WordPress para eliminar las dependencias definidas por el c\u00f3digo y producir paquetes interactivos.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Abstracci\u00f3n en WordPress: Las Mejores Pr\u00e1cticas y Plugins de Abstracci\u00f3n de WordPress\" \/>\n<meta property=\"og:description\" content=\"Aprende a utilizar fragmentos de c\u00f3digo o un plugin de abstracci\u00f3n de WordPress para eliminar las dependencias definidas por el c\u00f3digo y producir paquetes interactivos.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/\" \/>\n<meta property=\"og:site_name\" content=\"Kinsta\u00ae\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/kinsta.es\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-22T10:34:10+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-02-07T14:09:10+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg\" \/>\n\t<meta property=\"og:image:width\" content=\"1460\" \/>\n\t<meta property=\"og:image:height\" content=\"730\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Leonardo Losoviz\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:description\" content=\"Aprende a utilizar fragmentos de c\u00f3digo o un plugin de abstracci\u00f3n de WordPress para eliminar las dependencias definidas por el c\u00f3digo y producir paquetes interactivos.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg\" \/>\n<meta name=\"twitter:creator\" content=\"@losoviz\" \/>\n<meta name=\"twitter:site\" content=\"@Kinsta_ES\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Leonardo Losoviz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/\"},\"author\":{\"name\":\"Leonardo Losoviz\",\"@id\":\"https:\/\/kinsta.com\/es\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238\"},\"headline\":\"Abstracci\u00f3n en WordPress: Las Mejores Pr\u00e1cticas y Plugins de Abstracci\u00f3n de WordPress\",\"datePublished\":\"2021-09-22T10:34:10+00:00\",\"dateModified\":\"2025-02-07T14:09:10+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/\"},\"wordCount\":3400,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/es\/#organization\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg\",\"keywords\":[\"code\",\"web development\"],\"articleSection\":[\"Los mejores tutoriales de WordPress\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/\",\"url\":\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/\",\"name\":\"Abstracci\u00f3n en WordPress: Las Mejores Pr\u00e1cticas y Plugins de Abstracci\u00f3n de WordPress\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/es\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg\",\"datePublished\":\"2021-09-22T10:34:10+00:00\",\"dateModified\":\"2025-02-07T14:09:10+00:00\",\"description\":\"Aprende a utilizar fragmentos de c\u00f3digo o un plugin de abstracci\u00f3n de WordPress para eliminar las dependencias definidas por el c\u00f3digo y producir paquetes interactivos.\",\"breadcrumb\":{\"@id\":\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#primaryimage\",\"url\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg\",\"width\":1460,\"height\":730,\"caption\":\"Abstracci\u00f3n en WordPress: Mejores pr\u00e1cticas y plugins de abstracci\u00f3n de WordPress\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/kinsta.com\/es\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Desarrollo WordPress\",\"item\":\"https:\/\/kinsta.com\/es\/secciones\/desarrollo-wordpress\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Abstracci\u00f3n en WordPress: Las Mejores Pr\u00e1cticas y Plugins de Abstracci\u00f3n de WordPress\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/kinsta.com\/es\/#website\",\"url\":\"https:\/\/kinsta.com\/es\/\",\"name\":\"Kinsta\u00ae\",\"description\":\"Soluciones de alojamiento premium, r\u00e1pidas y seguras\",\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/es\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/kinsta.com\/es\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/kinsta.com\/es\/#organization\",\"name\":\"Kinsta\",\"url\":\"https:\/\/kinsta.com\/es\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/kinsta.com\/es\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/12\/kinsta-logo.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/12\/kinsta-logo.jpeg\",\"width\":500,\"height\":500,\"caption\":\"Kinsta\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/es\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/kinsta.es\/\",\"https:\/\/x.com\/Kinsta_ES\",\"https:\/\/www.instagram.com\/kinstahosting\/\",\"https:\/\/www.linkedin.com\/company\/kinsta\/\",\"https:\/\/www.pinterest.com\/kinstahosting\/\",\"https:\/\/www.youtube.com\/c\/Kinsta\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/kinsta.com\/es\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238\",\"name\":\"Leonardo Losoviz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/kinsta.com\/es\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/b28085726ee66e49f08be16ad668efd5?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/b28085726ee66e49f08be16ad668efd5?s=96&d=mm&r=g\",\"caption\":\"Leonardo Losoviz\"},\"description\":\"Leo writes about innovative web development trends, mostly concerning PHP, WordPress and GraphQL. You can find him at leoloso.com and twitter.com\/losoviz.\",\"sameAs\":[\"https:\/\/leoloso.com\",\"https:\/\/x.com\/losoviz\",\"https:\/\/www.youtube.com\/@GatoGraphQL\"],\"url\":\"https:\/\/kinsta.com\/es\/blog\/author\/leonardolosoviz\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Abstracci\u00f3n en WordPress: Las Mejores Pr\u00e1cticas y Plugins de Abstracci\u00f3n de WordPress","description":"Aprende a utilizar fragmentos de c\u00f3digo o un plugin de abstracci\u00f3n de WordPress para eliminar las dependencias definidas por el c\u00f3digo y producir paquetes interactivos.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/","og_locale":"es_ES","og_type":"article","og_title":"Abstracci\u00f3n en WordPress: Las Mejores Pr\u00e1cticas y Plugins de Abstracci\u00f3n de WordPress","og_description":"Aprende a utilizar fragmentos de c\u00f3digo o un plugin de abstracci\u00f3n de WordPress para eliminar las dependencias definidas por el c\u00f3digo y producir paquetes interactivos.","og_url":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/","og_site_name":"Kinsta\u00ae","article_publisher":"https:\/\/www.facebook.com\/kinsta.es\/","article_published_time":"2021-09-22T10:34:10+00:00","article_modified_time":"2025-02-07T14:09:10+00:00","og_image":[{"width":1460,"height":730,"url":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg","type":"image\/jpeg"}],"author":"Leonardo Losoviz","twitter_card":"summary_large_image","twitter_description":"Aprende a utilizar fragmentos de c\u00f3digo o un plugin de abstracci\u00f3n de WordPress para eliminar las dependencias definidas por el c\u00f3digo y producir paquetes interactivos.","twitter_image":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg","twitter_creator":"@losoviz","twitter_site":"@Kinsta_ES","twitter_misc":{"Escrito por":"Leonardo Losoviz","Tiempo de lectura":"16 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#article","isPartOf":{"@id":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/"},"author":{"name":"Leonardo Losoviz","@id":"https:\/\/kinsta.com\/es\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238"},"headline":"Abstracci\u00f3n en WordPress: Las Mejores Pr\u00e1cticas y Plugins de Abstracci\u00f3n de WordPress","datePublished":"2021-09-22T10:34:10+00:00","dateModified":"2025-02-07T14:09:10+00:00","mainEntityOfPage":{"@id":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/"},"wordCount":3400,"commentCount":0,"publisher":{"@id":"https:\/\/kinsta.com\/es\/#organization"},"image":{"@id":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg","keywords":["code","web development"],"articleSection":["Los mejores tutoriales de WordPress"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/","url":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/","name":"Abstracci\u00f3n en WordPress: Las Mejores Pr\u00e1cticas y Plugins de Abstracci\u00f3n de WordPress","isPartOf":{"@id":"https:\/\/kinsta.com\/es\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#primaryimage"},"image":{"@id":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg","datePublished":"2021-09-22T10:34:10+00:00","dateModified":"2025-02-07T14:09:10+00:00","description":"Aprende a utilizar fragmentos de c\u00f3digo o un plugin de abstracci\u00f3n de WordPress para eliminar las dependencias definidas por el c\u00f3digo y producir paquetes interactivos.","breadcrumb":{"@id":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#primaryimage","url":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg","contentUrl":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2021\/09\/abstract-wordpress-plugin.jpeg","width":1460,"height":730,"caption":"Abstracci\u00f3n en WordPress: Mejores pr\u00e1cticas y plugins de abstracci\u00f3n de WordPress"},{"@type":"BreadcrumbList","@id":"https:\/\/kinsta.com\/es\/blog\/abstraccion-en-wordpress-plugin\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kinsta.com\/es\/"},{"@type":"ListItem","position":2,"name":"Desarrollo WordPress","item":"https:\/\/kinsta.com\/es\/secciones\/desarrollo-wordpress\/"},{"@type":"ListItem","position":3,"name":"Abstracci\u00f3n en WordPress: Las Mejores Pr\u00e1cticas y Plugins de Abstracci\u00f3n de WordPress"}]},{"@type":"WebSite","@id":"https:\/\/kinsta.com\/es\/#website","url":"https:\/\/kinsta.com\/es\/","name":"Kinsta\u00ae","description":"Soluciones de alojamiento premium, r\u00e1pidas y seguras","publisher":{"@id":"https:\/\/kinsta.com\/es\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kinsta.com\/es\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/kinsta.com\/es\/#organization","name":"Kinsta","url":"https:\/\/kinsta.com\/es\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/kinsta.com\/es\/#\/schema\/logo\/image\/","url":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/12\/kinsta-logo.jpeg","contentUrl":"https:\/\/kinsta.com\/es\/wp-content\/uploads\/sites\/8\/2023\/12\/kinsta-logo.jpeg","width":500,"height":500,"caption":"Kinsta"},"image":{"@id":"https:\/\/kinsta.com\/es\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/kinsta.es\/","https:\/\/x.com\/Kinsta_ES","https:\/\/www.instagram.com\/kinstahosting\/","https:\/\/www.linkedin.com\/company\/kinsta\/","https:\/\/www.pinterest.com\/kinstahosting\/","https:\/\/www.youtube.com\/c\/Kinsta"]},{"@type":"Person","@id":"https:\/\/kinsta.com\/es\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238","name":"Leonardo Losoviz","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/kinsta.com\/es\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/b28085726ee66e49f08be16ad668efd5?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b28085726ee66e49f08be16ad668efd5?s=96&d=mm&r=g","caption":"Leonardo Losoviz"},"description":"Leo writes about innovative web development trends, mostly concerning PHP, WordPress and GraphQL. You can find him at leoloso.com and twitter.com\/losoviz.","sameAs":["https:\/\/leoloso.com","https:\/\/x.com\/losoviz","https:\/\/www.youtube.com\/@GatoGraphQL"],"url":"https:\/\/kinsta.com\/es\/blog\/author\/leonardolosoviz\/"}]}},"acf":[],"_links":{"self":[{"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/posts\/43698","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/users\/196"}],"replies":[{"embeddable":true,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/comments?post=43698"}],"version-history":[{"count":14,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/posts\/43698\/revisions"}],"predecessor-version":[{"id":43997,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/posts\/43698\/revisions\/43997"}],"alternate":[{"embeddable":true,"hreflang":"en","title":"English","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/43698\/translations\/en"},{"embeddable":true,"hreflang":"it","title":"Italian","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/43698\/translations\/it"},{"embeddable":true,"hreflang":"fr","title":"French","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/43698\/translations\/fr"},{"embeddable":true,"hreflang":"es","title":"Spanish","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/43698\/translations\/es"},{"embeddable":true,"hreflang":"pt","title":"Portuguese","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/43698\/translations\/pt"},{"embeddable":true,"hreflang":"de","title":"German","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/43698\/translations\/de"},{"embeddable":true,"hreflang":"nl","title":"Dutch","href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/43698\/translations\/nl"},{"href":"https:\/\/kinsta.com\/es\/wp-json\/kinsta\/v1\/posts\/43698\/tree"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/media\/43704"}],"wp:attachment":[{"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/media?parent=43698"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/tags?post=43698"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/kinsta.com\/es\/wp-json\/wp\/v2\/topic?post=43698"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}