{"id":48186,"date":"2021-09-06T12:44:06","date_gmt":"2021-09-06T10:44:06","guid":{"rendered":"https:\/\/kinsta.com\/?p=100908"},"modified":"2024-09-20T11:59:48","modified_gmt":"2024-09-20T10:59:48","slug":"plugin-wordpress-abstraction","status":"publish","type":"post","link":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/","title":{"rendered":"Abstraction WordPress : Meilleures pratiques et plugins WordPress d&rsquo;abstraction"},"content":{"rendered":"<p>WordPress est un CMS ancien, mais aussi le <a href=\"https:\/\/kinsta.com\/fr\/part-de-marche-de-wordpress\/\" target=\"_blank\" rel=\"noopener noreferrer\">plus utilis\u00e9<\/a>. Gr\u00e2ce \u00e0 son historique de prise en charge de versions PHP obsol\u00e8tes et de code h\u00e9rit\u00e9, il manque encore d&rsquo;impl\u00e9mentation de pratiques de codage modernes &#8211; l&rsquo;abstraction de WordPress en est un exemple.<\/p>\n<p>Par exemple, il serait tellement mieux de diviser le code du c\u0153ur de WordPress en paquets g\u00e9r\u00e9s par Composer. Ou peut-\u00eatre, pour charger automatiquement les classes WordPress \u00e0 partir des chemins de fichiers.<\/p>\n<p>Cet article vous apprendra \u00e0 abstraire le code de WordPress manuellement et \u00e0 utiliser les capacit\u00e9s d&rsquo;abstraction des extensions 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>Probl\u00e8mes d&rsquo;int\u00e9gration de WordPress et des outils PHP<\/h2>\n<p>En raison de son ancienne architecture, nous rencontrons parfois des probl\u00e8mes lors de l&rsquo;int\u00e9gration de WordPress avec des outils pour les bases de code PHP, tels que l&rsquo;analyseur statique <a href=\"https:\/\/phpstan.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">PHPStan<\/a>, la biblioth\u00e8que de tests unitaires <a href=\"https:\/\/phpunit.de\/\" target=\"_blank\" rel=\"noopener noreferrer\">PHPUnit<\/a> et la biblioth\u00e8que de d\u00e9tection des espaces de noms <a href=\"https:\/\/github.com\/humbug\/php-scoper\" target=\"_blank\" rel=\"noopener noreferrer\">PHP-Scoper<\/a>. Par exemple, consid\u00e8rez les cas suivants :<\/p>\n<ul>\n<li>Avant la sortie de <a href=\"https:\/\/kinsta.com\/fr\/blog\/wordpress-5-6\/\">WordPress 5.6<\/a> avec prise en charge de <a href=\"https:\/\/kinsta.com\/fr\/blog\/php-8\/\">PHP 8.0<\/a>, un rapport de Yoast d\u00e9crivait comment l&rsquo;ex\u00e9cution de PHPStan sur le c\u0153ur de WordPress produirait des <a href=\"https:\/\/developer.yoast.com\/blog\/the-2020-wordpress-and-php-8-compatibility-report\/#h-scanning-wordpress-with-phpstan\" target=\"_blank\" rel=\"noopener noreferrer\">milliers de probl\u00e8mes<\/a>.<\/li>\n<li>Parce qu&rsquo;elles prennent toujours en charge PHP 5.6, les suites de test de WordPress <a href=\"https:\/\/core.trac.wordpress.org\/ticket\/46149\" target=\"_blank\" rel=\"noopener noreferrer\">ne supportent actuellement<\/a><a href=\"https:\/\/core.trac.wordpress.org\/ticket\/46149\" target=\"_blank\" rel=\"noopener noreferrer\"> PHPUnit que jusqu&rsquo;\u00e0 la version 7.5<\/a>, qui a atteint sa fin de vie.<\/li>\n<li>L&rsquo;\u00e9valuation des extensions WordPress via PHP-Scoper <a href=\"https:\/\/github.com\/humbug\/php-scoper#wordpress\" target=\"_blank\" rel=\"noopener noreferrer\">est tr\u00e8s difficile<\/a>.<\/li>\n<\/ul>\n<p>Le code WordPress au sein de nos projets ne repr\u00e9sentera qu&rsquo;une fraction du total; le projet contiendra \u00e9galement du code commercial agnostique du CMS sous-jacent. Pourtant, rien qu&rsquo;en ayant un peu de code WordPress, le projet risque de ne pas s&rsquo;int\u00e9grer correctement \u00e0 l&rsquo;outillage.<\/p>\n<p>Pour cette raison, il pourrait \u00eatre judicieux de diviser le projet en paquets, certains contenant du code WordPress et d&rsquo;autres ne contenant que du code commercial utilisant du PHP \u00ab vanilla \u00bb et aucun code WordPress. De cette fa\u00e7on, ces derniers paquets ne seront pas affect\u00e9s par les probl\u00e8mes d\u00e9crits ci-dessus mais pourront \u00eatre parfaitement int\u00e9gr\u00e9s \u00e0 l&rsquo;outillage.<\/p>\n<h2>Qu&rsquo;est-ce que l&rsquo;abstraction de code ?<\/h2>\n<p>L&rsquo;abstraction de code supprime les d\u00e9pendances fixes du code, produisant des paquets qui interagissent les uns avec les autres via des contrats. Ces paquets peuvent ensuite \u00eatre ajout\u00e9s \u00e0 diff\u00e9rentes applications avec des piles diff\u00e9rentes, ce qui maximise leur utilisabilit\u00e9. Le r\u00e9sultat de l&rsquo;abstraction de code est une base de code proprement d\u00e9coupl\u00e9e bas\u00e9e sur les piliers suivants :<\/p>\n<ol>\n<li>Coder contre les interfaces, pas contre les impl\u00e9mentations.<\/li>\n<li>Cr\u00e9ez des paquets et distribuez-les via Composer.<\/li>\n<li>Collez toutes les parties ensemble via l&rsquo;injection de d\u00e9pendances.<\/li>\n<\/ol>\n\n<h2>Coder contre les interfaces, pas contre les impl\u00e9mentations<\/h2>\n<p>Le codage contre les interfaces est la pratique consistant \u00e0 utiliser des contrats pour faire interagir des morceaux de code entre eux. Un contrat est simplement une interface PHP (ou tout autre langage diff\u00e9rent) qui d\u00e9finit les fonctions disponibles et leurs signatures, c&rsquo;est-\u00e0-dire les entr\u00e9es qu&rsquo;elles re\u00e7oivent et leur sortie.<\/p>\n<p>Une interface d\u00e9clare l&rsquo;intention de la fonctionnalit\u00e9 sans expliquer comment la fonctionnalit\u00e9 sera mise en \u0153uvre. En acc\u00e9dant aux fonctionnalit\u00e9s par le biais d&rsquo;interfaces, notre <a href=\"https:\/\/kinsta.com\/fr\/blog\/application-surveillance-performance\/\">application<\/a> peut s&rsquo;appuyer sur des morceaux de code autonomes qui accomplissent un objectif sp\u00e9cifique sans savoir, ou sans se soucier, de la fa\u00e7on dont ils le font. Ainsi, l&rsquo;application n&rsquo;a pas besoin d&rsquo;\u00eatre adapt\u00e9e pour passer \u00e0 un autre morceau de code qui accomplit le m\u00eame objectif &#8211; par exemple, d&rsquo;un fournisseur diff\u00e9rent.<\/p>\n<h3>Exemple de contrats<\/h3>\n<p>Le code suivant utilise le contrat de Symfony <a href=\"https:\/\/github.com\/symfony\/symfony\/blob\/302b844\/src\/Symfony\/Contracts\/Cache\/CacheInterface.php\"><code>CacheInterface<\/code><\/a> et le contrat de la recommandation standard PHP (PHP Standard Recommendation ou PSR) <a href=\"https:\/\/github.com\/php-fig\/cache\/blob\/0a7c67d\/src\/CacheItemInterface.php\"><code>CacheItemInterface<\/code><\/a> pour impl\u00e9menter la fonctionnalit\u00e9 de mise en cache :<\/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});\n<\/code><\/pre>\n<p><code>$cache<\/code> impl\u00e9mente <code>CacheInterface<\/code>, qui d\u00e9finit la m\u00e9thode <code>get<\/code> pour r\u00e9cup\u00e9rer un objet dans le cache. En acc\u00e9dant \u00e0 cette fonctionnalit\u00e9 via le contrat, l&rsquo;application peut ignorer o\u00f9 se trouve le cache. Que ce soit dans la m\u00e9moire, sur le disque, dans la base de donn\u00e9es, sur le r\u00e9seau ou ailleurs. Elle doit tout de m\u00eame ex\u00e9cuter la fonction. <code>CacheItemInterface<\/code> d\u00e9finit la m\u00e9thode <code>expiresAfter<\/code> pour d\u00e9clarer combien de temps l&rsquo;\u00e9l\u00e9ment doit \u00eatre conserv\u00e9 dans le cache. L&rsquo;application peut invoquer cette m\u00e9thode sans se soucier de l&rsquo;objet mis en cache; elle ne se soucie que de la dur\u00e9e pendant laquelle il doit \u00eatre mis en cache.<\/p>\n<h2>Coder contre les interfaces dans WordPress<\/h2>\n<p>Comme nous abstrayons le code de WordPress, le r\u00e9sultat sera que l&rsquo;application ne fera pas directement r\u00e9f\u00e9rence au <a href=\"https:\/\/kinsta.com\/fr\/blog\/modifier-code-wordpress\/\">code de WordPress<\/a>, mais toujours via une interface. Par exemple, la fonction WordPress <code>get_posts<\/code> a cette signature :<\/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>Au lieu d&rsquo;invoquer cette m\u00e9thode directement, nous pouvons y acc\u00e9der via le contrat <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}\n<\/code><\/pre>\n<p>Note que la fonction WordPress <code>get_posts<\/code> peut renvoyer des objets de la classe <code>WP_Post<\/code>, qui est sp\u00e9cifique \u00e0 WordPress. Lorsque nous abstrayons le code, nous devons supprimer ce type de d\u00e9pendance fixe. La m\u00e9thode <code>get_posts<\/code> du contrat renvoie des objets du type <code>PostInterface<\/code>, ce qui vous permet de faire r\u00e9f\u00e9rence \u00e0 la classe <code>WP_Post<\/code> sans \u00eatre explicite \u00e0 ce sujet. La classe <code>PostInterface<\/code> devra fournir un acc\u00e8s \u00e0 toutes les m\u00e9thodes et tous les attributs 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>L&rsquo;ex\u00e9cution de cette strat\u00e9gie peut changer notre compr\u00e9hension de la place de WordPress dans notre pile. Au lieu de consid\u00e9rer WordPress comme l&rsquo;application elle-m\u00eame (sur laquelle nous installons des th\u00e8mes et des extensions), nous pouvons le consid\u00e9rer simplement comme une autre d\u00e9pendance au sein de l&rsquo;application, rempla\u00e7able comme tout autre composant. (M\u00eame si nous ne remplacerons pas WordPress dans la pratique, il <em>est<\/em> rempla\u00e7able d&rsquo;un point de vue conceptuel)<\/p>\n<h2>Cr\u00e9er et distribuer des paquets<\/h2>\n<p><a href=\"https:\/\/getcomposer.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">Composer<\/a> est un gestionnaire de paquets pour PHP. Il permet aux applications PHP de r\u00e9cup\u00e9rer des paquets (c&rsquo;est-\u00e0-dire des morceaux de code) dans un d\u00e9p\u00f4t et de les installer en tant que d\u00e9pendances. Pour d\u00e9coupler l&rsquo;application de WordPress, nous devons distribuer son code dans des paquets de deux types diff\u00e9rents : ceux qui contiennent le code WordPress et les autres qui contiennent la logique commerciale (c&rsquo;est-\u00e0-dire aucun code WordPress).<\/p>\n<p>Enfin, nous ajoutons tous les paquets en tant que d\u00e9pendances dans l&rsquo;application, et nous les installons via Composer. Comme l&rsquo;outillage sera appliqu\u00e9 aux paquets de code commercial, ceux-ci doivent contenir la majeure partie du code de l&rsquo;application; plus le pourcentage est \u00e9lev\u00e9, mieux c&rsquo;est. Leur faire g\u00e9rer environ 90 % du code global est un bon objectif.<\/p>\n<h2>Extraire le code de WordPress dans les paquets<\/h2>\n<p>En suivant l&rsquo;exemple pr\u00e9c\u00e9dent, les contrats <code>PostAPIInterface<\/code> et <code>PostInterface<\/code> seront ajout\u00e9s au paquet contenant le code commercial, et un autre paquet comprendra l&rsquo;impl\u00e9mentation WordPress de ces contrats. Pour satisfaire <code>PostInterface<\/code>, nous cr\u00e9ons une classe <code>PostWrapper<\/code> qui r\u00e9cup\u00e9rera tous les attributs d&rsquo;un objet <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}\n<\/code><\/pre>\n<p>Lors de l&rsquo;impl\u00e9mentation de <code>PostAPI<\/code>, puisque la m\u00e9thode <code>get_posts<\/code> renvoie <code>PostInterface[]<\/code>, nous devons convertir les objets de <code>WP_Post<\/code> en <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>Utiliser l&rsquo;injection de d\u00e9pendances<\/h2>\n<p>L&rsquo;injection de d\u00e9pendances est un mod\u00e8le de conception qui vous permet de coller ensemble toutes les parties de l&rsquo;application d&rsquo;une mani\u00e8re peu contraignante. Avec l&rsquo;injection de d\u00e9pendances, l&rsquo;application acc\u00e8de aux services par le biais de leurs contrats, et les mises en \u0153uvre des contrats sont \u00ab inject\u00e9es \u00bb dans l&rsquo;application par le biais de la configuration.<\/p>\n<p>En modifiant simplement la configuration, on peut facilement passer d&rsquo;un fournisseur de contrat \u00e0 un autre. Il existe plusieurs biblioth\u00e8ques d&rsquo;injection de d\u00e9pendances parmi lesquelles nous pouvons choisir. Nous vous conseillons d&rsquo;en choisir une qui adh\u00e8re aux <a href=\"https:\/\/www.php-fig.org\/\" target=\"_blank\" rel=\"noopener noreferrer\">recommandations standard de PHP<\/a> (souvent appel\u00e9es \u00ab PSR \u00bb), afin que nous puissions facilement remplacer la biblioth\u00e8que par une autre si le besoin s&rsquo;en fait sentir. Concernant l&rsquo;injection de d\u00e9pendances, la biblioth\u00e8que doit satisfaire la <a href=\"https:\/\/www.php-fig.org\/psr\/psr-11\/\" target=\"_blank\" rel=\"noopener noreferrer\">PSR-11<\/a>, qui fournit la sp\u00e9cification d&rsquo;une \u00ab interface de conteneur \u00bb Les biblioth\u00e8ques suivantes, entre autres, sont conformes \u00e0 PSR-11 :<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/symfony\/dependency-injection\" target=\"_blank\" rel=\"noopener noreferrer\">Symfony&rsquo;s DependencyInjection<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/PHP-DI\/PHP-DI\" target=\"_blank\" rel=\"noopener noreferrer\">PHP-DI<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/auraphp\/Aura.Di\" target=\"_blank\" rel=\"noopener noreferrer\">Aura.Di<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/thephpleague\/container\" target=\"_blank\" rel=\"noopener noreferrer\">Container (Dependency Injection)<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/yiisoft\/di\" target=\"_blank\" rel=\"noopener noreferrer\">Yii Dependency Injection<\/a><\/li>\n<\/ul>\n<h3>Acc\u00e9der aux services via le conteneur de services<\/h3>\n<p>La biblioth\u00e8que d&rsquo;injection de d\u00e9pendances mettra \u00e0 disposition un \u00ab conteneur de services \u00bb, qui r\u00e9sout un contrat en sa classe d&rsquo;impl\u00e9mentation correspondante. L&rsquo;application doit s&rsquo;appuyer sur le conteneur de services pour acc\u00e9der \u00e0 toutes les fonctionnalit\u00e9s. Par exemple, alors que nous invoquerions g\u00e9n\u00e9ralement directement les fonctions de WordPress :<\/p>\n<pre><code class=\"language-php\">$posts = get_posts();<\/code><\/pre>\n<p>&#8230;avec le conteneur de services, nous devons d&rsquo;abord obtenir le service qui satisfait <code>PostAPIInterface<\/code> et ex\u00e9cuter la fonctionnalit\u00e9 par son interm\u00e9diaire :<\/p>\n<pre class=\" language-php\"><code class=\" language-php\"><span class=\"token keyword\">use<\/span> <span class=\"token package\">Owner<span class=\"token punctuation\">\\<\/span>MyApp<span class=\"token punctuation\">\\<\/span>Contracts<span class=\"token punctuation\">\\<\/span>PostAPIInterface<\/span><span class=\"token punctuation\">;<\/span>\n\n<span class=\"token comment\">\/\/ Obtain the service container, as specified by the library we use<\/span>\n<span class=\"token variable\">$serviceContainer<\/span> <span class=\"token operator\">=<\/span> <span class=\"token class-name static-context\">ContainerBuilderFactory<\/span><span class=\"token operator\">::<\/span><span class=\"token function\">getInstance<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\n\n<span class=\"token comment\">\/\/ The obtained service will be of class Owner\\MyAppForWP\\ContractImplementations\\PostAPI<\/span>\n<span class=\"token variable\">$postAPI<\/span> <span class=\"token operator\">=<\/span> <span class=\"token variable\">$serviceContainer<\/span><span class=\"token operator\">-&gt;<\/span><span class=\"token function\">get<\/span><span class=\"token punctuation\">(<\/span><span class=\"token class-name static-context\">PostAPIInterface<\/span><span class=\"token operator\">::<\/span><span class=\"token keyword\">class<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\n\n<span class=\"token comment\">\/\/ Now we can invoke the WordPress functionality<\/span>\n<span class=\"token variable\">$posts<\/span> <span class=\"token operator\">=<\/span> <span class=\"token variable\">$postAPI<\/span><span class=\"token operator\">-&gt;<\/span><span class=\"token function\">get_posts<\/span><span class=\"token punctuation\">(<\/span><span class=\"token punctuation\">)<\/span><span class=\"token punctuation\">;<\/span>\n<\/code><\/pre>\n<h3>Utiliser le composant DependencyInjection de Symfony<\/h3>\n<p>Le <a href=\"https:\/\/symfony.com\/doc\/current\/components\/dependency_injection.html\" target=\"_blank\" rel=\"noopener noreferrer\">composant DependencyInjection de Symfony<\/a> est actuellement la biblioth\u00e8que d&rsquo;injection de d\u00e9pendances la plus populaire. Il vous permet de configurer le conteneur de services via un code PHP, YAML ou XML. Par exemple, pour d\u00e9finir que le contrat <code>PostAPIInterface<\/code> est satisfait via la classe <code>PostAPI<\/code>, il faut le configurer dans YAML comme ceci :<\/p>\n<pre><code class=\"language-yaml\">services:\n  Owner\\MyApp\\Contracts\\PostAPIInterface:\n    class: \\Owner\\MyAppForWP\\ContractImplementations\\PostAPI\n<\/code><\/pre>\n<p>DependencyInjection de Symfony permet \u00e9galement aux instances d&rsquo;un service d&rsquo;\u00eatre automatiquement inject\u00e9es (ou \u00ab autowired \u00bb) dans tout autre service qui en d\u00e9pend. En outre, il est facile de d\u00e9finir qu&rsquo;une classe est une impl\u00e9mentation de son propre service. Par exemple, consid\u00e9rez la <a href=\"https:\/\/github.com\/leoloso\/PoP\/blob\/8602e9041ac92f4683966eed5c4a90686b9395fa\/layers\/GraphQLAPIForWP\/plugins\/graphql-api-for-wp\/config\/hybrid-services.yaml\" target=\"_blank\" rel=\"noopener noreferrer\">configuration YAML suivante<\/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>Cette configuration d\u00e9finit ce qui suit :<\/p>\n<ul>\n<li>Le contrat <code>UserAuthorizationSchemeRegistryInterface<\/code> est satisfait via la classe <code>UserAuthorizationSchemeRegistry<\/code><\/li>\n<li>Le contrat <code>UserAuthorizationInterface<\/code> est satisfait via la classe <code>UserAuthorization<\/code><\/li>\n<li>Toutes les classes du r\u00e9pertoire <code>UserAuthorizationSchemes\/<\/code> sont une impl\u00e9mentation d&rsquo;elles-m\u00eames<\/li>\n<li>Les services doivent \u00eatre automatiquement inject\u00e9s les uns dans les autres<code>(autowire : true<\/code>)<\/li>\n<\/ul>\n<p>Voyons comment fonctionne l&rsquo;injection automatique. La classe <a href=\"https:\/\/github.com\/leoloso\/PoP\/blob\/bd56f23b52a3e02966fdcbde4bc58f246a47a6e5\/layers\/GraphQLAPIForWP\/plugins\/graphql-api-for-wp\/src\/Security\/UserAuthorization.php\"><code>UserAuthorization<\/code><\/a> d\u00e9pend du service avec le contrat <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>Gr\u00e2ce \u00e0 <code>autowire : true<\/code>, le composant DependencyInjection fera automatiquement en sorte que le service <code>UserAuthorization<\/code> re\u00e7oive sa d\u00e9pendance n\u00e9cessaire, qui est une instance de <code>UserAuthorizationSchemeRegistry<\/code>.<\/p>\n<h2>Quand faire l&rsquo;abstraction<\/h2>\n<p>L&rsquo;abstraction de code peut consommer beaucoup de temps et d&rsquo;efforts, c&rsquo;est pourquoi nous ne devrions l&rsquo;entreprendre que lorsque ses avantages l&#8217;emportent sur ses co\u00fbts. Voici des suggestions pour savoir quand l&rsquo;abstraction du code peut en valoir la peine. Vous pouvez le faire en utilisant les extraits de code de cet article ou les extensions WordPress d&rsquo;abstraction sugg\u00e9r\u00e9es ci-dessous.<\/p>\n<h3>Acc\u00e9der \u00e0 l&rsquo;outillage<\/h3>\n<p>Comme mentionn\u00e9 pr\u00e9c\u00e9demment, <a href=\"https:\/\/github.com\/humbug\/php-scoper\/issues\/303\" target=\"_blank\" rel=\"noopener noreferrer\">il est difficile d&rsquo;ex\u00e9cuter PHP-Scoper sur WordPress<\/a>. En d\u00e9couplant le code de WordPress en paquets distincts, il devient possible d&rsquo;<a href=\"https:\/\/graphql-api.com\/blog\/graphql-api-for-wp-is-now-scoped-thanks-to-php-scoper\/\" target=\"_blank\" rel=\"noopener noreferrer\">\u00e9valuer directement une extension<\/a><a href=\"https:\/\/graphql-api.com\/blog\/graphql-api-for-wp-is-now-scoped-thanks-to-php-scoper\/\" target=\"_blank\" rel=\"noopener noreferrer\"> WordPress<\/a>.<\/p>\n<h3>R\u00e9duire le temps et le co\u00fbt de l&rsquo;outillage<\/h3>\n<p>L&rsquo;ex\u00e9cution d&rsquo;une suite de tests PHPUnit prend plus de temps lorsqu&rsquo;elle doit initialiser et ex\u00e9cuter WordPress que lorsqu&rsquo;elle ne le fait pas. Moins de temps peut aussi se traduire par moins d&rsquo;argent d\u00e9pens\u00e9 pour ex\u00e9cuter les tests &#8211; par exemple, <a href=\"https:\/\/kinsta.com\/fr\/blog\/base-de-connaissances-github\/\">GitHub<\/a> Actions facture les ex\u00e9cuteurs h\u00e9berg\u00e9s par GitHub en fonction du temps pass\u00e9 \u00e0 les utiliser.<\/p>\n<h3>Un remaniement lourd n&rsquo;est pas n\u00e9cessaire<\/h3>\n<p>Un projet existant peut n\u00e9cessiter un remaniement lourd pour introduire l&rsquo;architecture requise (injection de d\u00e9pendances, division du code en paquets, etc.), ce qui le rend difficile \u00e0 retirer. Abstraire le code lors de la cr\u00e9ation d&rsquo;un projet \u00e0 partir de z\u00e9ro le rend beaucoup plus facile \u00e0 g\u00e9rer.<\/p>\n<h3>Produire du code pour plusieurs plateformes<\/h3>\n<p>En extrayant 90 % du code dans un paquet agnostique aux CMS, nous pouvons produire une version de la biblioth\u00e8que qui fonctionne pour un CMS ou un framework diff\u00e9rent en ne rempla\u00e7ant que 10 % de la base de code globale.<\/p>\n<h3>Migrer vers une plateforme diff\u00e9rente<\/h3>\n<p>Si nous devons migrer un projet de <a href=\"https:\/\/kinsta.com\/fr\/blog\/wordpress-vs-drupal\/\">Drupal \u00e0 WordPress<\/a>, de WordPress \u00e0 <a href=\"https:\/\/kinsta.com\/fr\/blog\/laravel-9\/\">Laravel<\/a>, ou toute autre combinaison, seuls 10% du code doivent \u00eatre r\u00e9\u00e9crits &#8211; une \u00e9conomie consid\u00e9rable.<\/p>\n<h2>Meilleures pratiques<\/h2>\n<p>Tout en concevant les contrats pour abstraire notre code, il existe plusieurs am\u00e9liorations que nous pouvons appliquer \u00e0 la base de code.<\/p>\n<h3>Adh\u00e8rer au PSR-12<\/h3>\n<p>Lorsque nous d\u00e9finissons l&rsquo;interface pour acc\u00e9der aux m\u00e9thodes de WordPress, nous devons adh\u00e9rer \u00e0 <a href=\"https:\/\/www.php-fig.org\/psr\/psr-12\/\" target=\"_blank\" rel=\"noopener noreferrer\">PSR-12<\/a>. Cette sp\u00e9cification r\u00e9cente vise \u00e0 r\u00e9duire les frictions cognitives lors de l&rsquo;analyse du code de diff\u00e9rents auteurs. Adh\u00e9rer \u00e0 PSR-12 implique de renommer les fonctions de WordPress.<\/p>\n<p>WordPress nomme les fonctions en utilisant <strong>snake_case<\/strong>, alors que PSR-12 utilise <strong>camelCase<\/strong>. Ainsi, la fonction <code>get_posts<\/code> deviendra <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;et :<\/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>Diviser les m\u00e9thodes<\/h3>\n<p>Les m\u00e9thodes de l&rsquo;interface n&rsquo;ont pas besoin d&rsquo;\u00eatre une r\u00e9plique de celles de WordPress. Nous pouvons les transformer lorsque cela a du sens. Par exemple, la fonction WordPress <code>get_user_by($field, $value)<\/code> sait comment r\u00e9cup\u00e9rer l&rsquo;utilisateur dans la base de donn\u00e9es via le param\u00e8tre <code>$field<\/code>, qui accepte les valeurs <code>\u00ab id \u00bb<\/code>, <code>\u00ab ID \u00bb<\/code>, <code>\u00ab slug \u00bb<\/code>, <code>\u00ab email \u00bb<\/code> ou <code>\u00ab login \u00bb<\/code>. Cette conception pr\u00e9sente quelques probl\u00e8mes :<\/p>\n<ul>\n<li>Elle n&rsquo;\u00e9chouera pas au moment de la compilation si nous passons une mauvaise cha\u00eene de caract\u00e8res<\/li>\n<li>Le param\u00e8tre <code>$value<\/code> doit accepter tous les types diff\u00e9rents pour toutes les options, m\u00eame si en passant <code>\u00ab ID \u00bb<\/code> il s&rsquo;attend \u00e0 un <code>int<\/code>, en passant <code>\u00ab email \u00bb<\/code> il ne peut recevoir qu&rsquo;une <code>string<\/code><\/li>\n<\/ul>\n<p>Nous pouvons am\u00e9liorer cette situation en divisant la fonction en plusieurs :<\/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>Le contrat est r\u00e9solu comme ceci pour WordPress (en supposant que nous avons cr\u00e9\u00e9 <code>UserWrapper<\/code> et <code>UserInterface<\/code>, comme expliqu\u00e9 pr\u00e9c\u00e9demment) :<\/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>Supprimer les d\u00e9tails d&rsquo;impl\u00e9mentation de la signature de la fonction<\/h3>\n<p>Les fonctions de WordPress peuvent fournir des informations sur la fa\u00e7on dont elles sont impl\u00e9ment\u00e9es dans leur propre signature. Ces informations peuvent \u00eatre supprim\u00e9es lors de l&rsquo;\u00e9valuation de la fonction d&rsquo;un point de vue abstrait. Par exemple, l&rsquo;obtention du nom de l&rsquo;utilisateur dans WordPress se fait en appelant <code>get_the_author_meta<\/code>, en rendant explicite le fait que le nom d&rsquo;un utilisateur est stock\u00e9 comme une valeur \u00ab m\u00e9ta \u00bb (sur la table <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>Vous n&rsquo;avez pas besoin de transmettre ces informations au contrat. Les interfaces ne s&rsquo;int\u00e9ressent qu&rsquo;au quoi, pas au comment. Par cons\u00e9quent, le contrat peut plut\u00f4t avoir une m\u00e9thode <code>getUserLastname<\/code>, qui ne fournit aucune information sur la fa\u00e7on dont elle est impl\u00e9ment\u00e9e :<\/p>\n<pre><code class=\"language-php\">interface UserAPIInterface\n{\n  public function getUserLastname(UserWrapper $userWrapper): string;\n  ...\n}\n<\/code><\/pre>\n<h3>Ajoutez des types plus stricts<\/h3>\n<p>Certaines fonctions WordPress peuvent recevoir des param\u00e8tres de diff\u00e9rentes mani\u00e8res, ce qui entra\u00eene une ambigu\u00eft\u00e9. Par exemple, la fonction <code>add_query_arg<\/code> peut soit recevoir une seule cl\u00e9 et une seule valeur :<\/p>\n<pre><code class=\"language-php\">$url = add_query_arg('id', 5, $url);\n<\/code><\/pre>\n<p>&#8230; ou un tableau de <code>cl\u00e9 =&gt; valeur<\/code>:<\/p>\n<pre><code class=\"language-php\">$url = add_query_arg(['id' =&gt; 5], $url);\n<\/code><\/pre>\n<p>Notre interface peut d\u00e9finir une intention plus compr\u00e9hensible en divisant ces fonctions en plusieurs fonctions distinctes, chacune d&rsquo;entre elles acceptant une combinaison unique d&rsquo;entr\u00e9es :<\/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>Effacer la dette technique<\/h3>\n<p>La fonction WordPress <code>get_posts<\/code> renvoie non seulement les \u00ab articles \u00bb mais aussi les \u00ab pages \u00bb ou toute entit\u00e9 de type \u00ab \u00ab publication personnalis\u00e9e \u00bb, et ces entit\u00e9s ne sont pas interchangeables. Les articles et les pages sont tous deux des publications personnalis\u00e9es, mais une page n&rsquo;est ni un article ni une page. Par cons\u00e9quent, l&rsquo;ex\u00e9cution de <code>get_posts<\/code> peut renvoyer des pages. Ce comportement est une divergence conceptuelle.<\/p>\n<p>Pour le rendre correct, <code>get_posts<\/code> devrait plut\u00f4t s&rsquo;appeler <code>get_customposts<\/code>, mais il n&rsquo;a jamais \u00e9t\u00e9 renomm\u00e9 dans le c\u0153ur de WordPress. C&rsquo;est un probl\u00e8me courant avec la plupart des logiciels \u00e0 longue dur\u00e9e de vie et c&rsquo;est ce qu&rsquo;on appelle la w dette technique \u00bb &#8211; un code qui a des probl\u00e8mes, mais qui n&rsquo;est jamais corrig\u00e9 parce qu&rsquo;il introduit des changements cassants.<\/p>\n<p>Cependant, lorsque nous cr\u00e9ons nos contrats, nous avons la possibilit\u00e9 d&rsquo;\u00e9viter ce type de dette technique. Dans ce cas, nous pouvons cr\u00e9er une nouvelle interface <code>ModelAPIInterface<\/code> qui peut traiter des entit\u00e9s de diff\u00e9rents types, et nous cr\u00e9ons plusieurs m\u00e9thodes, chacune pour traiter un type diff\u00e9rent :<\/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 cette fa\u00e7on, la divergence ne se produira plus, et vous verrez ces r\u00e9sultats :<\/p>\n<ul>\n<li><code>getPosts<\/code> renvoie uniquement les articles<\/li>\n<li><code>getPages<\/code> renvoie uniquement les pages<\/li>\n<li><code>getCustomPosts<\/code> renvoie les articles et les pages<\/li>\n<\/ul>\n<h2>Avantages de l&rsquo;abstraction du code<\/h2>\n<p>Les principaux avantages de l&rsquo;abstraction du code d&rsquo;une application sont les suivants :<\/p>\n<ul>\n<li>L&rsquo;outillage fonctionnant sur des paquets contenant uniquement du code commercial est plus facile \u00e0 configurer et prendra moins de temps (et moins d&rsquo;argent) pour fonctionner.<\/li>\n<li>Nous pouvons utiliser des outils qui ne fonctionnent pas avec WordPress, comme le scoping d&rsquo;une extension avec PHP-Scoper.<\/li>\n<li>Les paquets que nous produisons peuvent \u00eatre autonomes pour \u00eatre utilis\u00e9s facilement dans d&rsquo;autres applications.<\/li>\n<li>La migration d&rsquo;une application vers d&rsquo;autres plateformes devient plus facile.<\/li>\n<li>Nous pouvons changer notre \u00e9tat d&rsquo;esprit en passant de la pens\u00e9e WordPress \u00e0 la pens\u00e9e en termes de logique commerciale.<\/li>\n<li>Les contrats d\u00e9crivent l&rsquo;intention de l&rsquo;application, ce qui la rend plus compr\u00e9hensible.<\/li>\n<li>L&rsquo;application s&rsquo;organise par paquets, cr\u00e9ant une application all\u00e9g\u00e9e contenant le strict minimum et l&rsquo;am\u00e9liorant progressivement selon les besoins.<\/li>\n<li>Nous pouvons \u00e9liminer la dette technique.<\/li>\n<\/ul>\n<h2>Probl\u00e8mes li\u00e9s \u00e0 l&rsquo;abstraction du code<\/h2>\n<p>Les inconv\u00e9nients de l&rsquo;abstraction du code d&rsquo;une application sont les suivants :<\/p>\n<ul>\n<li>Cela implique une quantit\u00e9 consid\u00e9rable de travail au d\u00e9part.<\/li>\n<li>Le code devient plus verbeux; ajoute des couches de code suppl\u00e9mentaires pour obtenir le m\u00eame r\u00e9sultat.<\/li>\n<li>Vous pouvez peux finir par produire des <a href=\"https:\/\/graphql-api.com\/blog\/why-to-support-cms-agnosticism-the-graphql-api-split-to-around-90-packages\/\" target=\"_blank\" rel=\"noopener noreferrer\">dizaines de paquets<\/a> qui doivent ensuite \u00eatre g\u00e9r\u00e9s et maintenus.<\/li>\n<li>Vous aurez peut-\u00eatre besoin d&rsquo;un mono-repo pour g\u00e9rer tous les paquets ensemble.<\/li>\n<li>L&rsquo;injection de d\u00e9pendances pourrait \u00eatre excessive pour les applications simples (rendements d\u00e9croissants).<\/li>\n<li>L&rsquo;abstraction du code ne sera jamais compl\u00e8tement accomplie car il y a g\u00e9n\u00e9ralement une pr\u00e9f\u00e9rence g\u00e9n\u00e9rale implicite dans l&rsquo;architecture du CMS.<\/li>\n<\/ul>\n<h2>Options d&rsquo;extensions WordPress d&rsquo;abstraction<\/h2>\n<p>Bien qu&rsquo;il soit g\u00e9n\u00e9ralement plus sage d&rsquo;extraire votre code dans un <a href=\"https:\/\/kinsta.com\/fr\/blog\/installer-wordpress-localement\/\">environnement local<\/a> avant de travailler dessus, certaines extensions WordPress peuvent vous aider \u00e0 atteindre vos objectifs d&rsquo;abstraction. Voici nos meilleurs choix.<\/p>\n<h3>1. WPide<\/h3>\n<p>Produit par WebFactory Ltd, la c\u00e9l\u00e8bre <a href=\"https:\/\/wordpress.org\/plugins\/wpide\/\" target=\"_blank\" rel=\"noopener noreferrer\">extension WPide<\/a> \u00e9tend consid\u00e9rablement les fonctionnalit\u00e9s de l&rsquo;\u00e9diteur de code par d\u00e9faut de WordPress. Il sert d&rsquo;extension WordPress d&rsquo;abstraction en vous permettant de voir votre code in situ pour mieux visualiser ce qui n\u00e9cessite de l&rsquo;attention.<\/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=\"WPide abstract wordpress plugin\" width=\"900\" height=\"291\"><figcaption class=\"wp-caption-text\">L&rsquo;extension WPide.<\/figcaption><\/figure><\/figure>\n<p>WPide dispose \u00e9galement d&rsquo;une fonction de recherche et de remplacement pour localiser rapidement un code p\u00e9rim\u00e9 ou expir\u00e9 et le remplacer par un rendu remani\u00e9.<\/p>\n<p>En plus de cela, WPide propose des tas de fonctionnalit\u00e9s suppl\u00e9mentaires, notamment :<\/p>\n<ul>\n<li>Mise en \u00e9vidence de la syntaxe et des blocs<\/li>\n<li><a href=\"https:\/\/kinsta.com\/fr\/docs\/hebergement-wordpress\/sauvegardes-wordpress\/#wordpress-backup\">Sauvegardes automatiques<\/a><\/li>\n<li>Cr\u00e9ation de fichiers et de r\u00e9pertoires<\/li>\n<li>Navigateur d&rsquo;arborescence de fichiers complet<\/li>\n<li>Acc\u00e8s \u00e0 l&rsquo;API du syst\u00e8me de fichiers de WordPress<\/li>\n<\/ul>\n<h3>2. Ultimate DB Manager<\/h3>\n<p>L&rsquo;extension <a href=\"https:\/\/wordpress.org\/plugins\/ultimate-db-manager-lite\/\" target=\"_blank\" rel=\"noopener noreferrer\">Ultimate WP DB Manager<\/a> de WPHobby vous donne un moyen rapide de t\u00e9l\u00e9charger vos bases de donn\u00e9es dans leur int\u00e9gralit\u00e9 pour les extraire et les remanier.<\/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=\"Screenshot of the Ultimate DB Manager plugin's logo with the words: \"Create database backup easily on single click and clean &#038; optimize database\".\" width=\"900\" height=\"250\"><figcaption class=\"wp-caption-text\">L&rsquo;extension Ultimate DB Manager.<\/figcaption><\/figure><\/figure>\n<p>Bien s\u00fbr, les extensions de ce type ne sont pas n\u00e9cessaires pour les utilisateurs de Kinsta, car Kinsta offre \u00e0 tous ses clients un <a href=\"https:\/\/kinsta.com\/fr\/docs\/hebergement-wordpress\/gestion-base-de-donnees\/acces-base-donnees-wordpress\/\">acc\u00e8s direct aux bases de donn\u00e9es<\/a>. Cependant, si vous n&rsquo;avez pas un acc\u00e8s suffisant aux bases de donn\u00e9es par le biais de votre h\u00e9bergeur, Ultimate DB Manager pourrait \u00eatre utile en tant qu&rsquo;extension WordPress d&rsquo;abstraction.<\/p>\n<h3>3. Votre propre extension WordPress d&rsquo;abstraction personnalis\u00e9e<\/h3>\n<p>En fin de compte, le meilleur choix pour l&rsquo;abstraction sera toujours de cr\u00e9er votre extension. Cela peut sembler \u00eatre une grande entreprise, mais si vous avez une capacit\u00e9 limit\u00e9e \u00e0 g\u00e9rer directement tes fichiers du c\u0153ur de WordPress, cela offre une solution de contournement favorable \u00e0 l&rsquo;abstraction.<\/p>\n<p>Faire cela pr\u00e9sente des avantages \u00e9vidents :<\/p>\n<ul>\n<li>Abr\u00e9gez vos fonctions \u00e0 partir des fichiers de votre th\u00e8me<\/li>\n<li>Pr\u00e9servez votre code malgr\u00e9 les changements de th\u00e8me et les mises \u00e0 jour de la base de donn\u00e9es<\/li>\n<\/ul>\n<p>Vous pouvez apprendre \u00e0 cr\u00e9er votre extension WordPress d&rsquo;abstraction gr\u00e2ce au <a href=\"https:\/\/developer.wordpress.org\/plugins\/\" target=\"_blank\" rel=\"noopener noreferrer\">Manuel WordPress du d\u00e9veloppeur d&rsquo;extensions<\/a>.<\/p>\n\n<h2>R\u00e9sum\u00e9<\/h2>\n<p>Devrions-nous abstraire le code de nos applications ? Comme pour tout, il n&rsquo;y a pas de \u00ab bonne r\u00e9ponse \u00bb pr\u00e9d\u00e9finie, car cela d\u00e9pend de chaque projet. Les projets n\u00e9cessitant une quantit\u00e9 \u00e9norme de temps pour \u00eatre analys\u00e9s avec PHPUnit ou PHPStan peuvent en b\u00e9n\u00e9ficier le plus, mais l&rsquo;effort n\u00e9cessaire pour y parvenir n&rsquo;en vaut pas toujours la peine.<\/p>\n<p>Vous avez appris tout ce que vous devez savoir pour commencer \u00e0 abstraire le code de WordPress.<\/p>\n<p><em>Vous pr\u00e9voyez de mettre en \u0153uvre cette strat\u00e9gie dans votre projet ? Si oui, utiliserez-vous une extension WordPress d&rsquo;abstraction ? Faites-nous signe dans la section des commentaires !<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>WordPress est un CMS ancien, mais aussi le plus utilis\u00e9. Gr\u00e2ce \u00e0 son historique de prise en charge de versions PHP obsol\u00e8tes et de code h\u00e9rit\u00e9, &#8230;<\/p>\n","protected":false},"author":196,"featured_media":48193,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kinsta_gated_content":false,"_kinsta_gated_content_redirect":"","footnotes":""},"tags":[401,341],"topic":[1028,1035],"class_list":["post-48186","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-code","tag-web-development","topic-developpement-wordpress","topic-extensions-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>Abstraction WordPress : Meilleures pratiques et plugins WordPress d&#039;abstraction<\/title>\n<meta name=\"description\" content=\"Apprenez \u00e0 utiliser des extraits de code ou une extension WordPress d&#039;abstraction pour supprimer les d\u00e9pendances fixes du code et produire des paquets en interaction.\" \/>\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\/fr\/blog\/plugin-wordpress-abstraction\/\" \/>\n<meta property=\"og:locale\" content=\"fr_FR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Abstraction WordPress : Meilleures pratiques et plugins WordPress d&#039;abstraction\" \/>\n<meta property=\"og:description\" content=\"Apprenez \u00e0 utiliser des extraits de code ou une extension WordPress d&#039;abstraction pour supprimer les d\u00e9pendances fixes du code et produire des paquets en interaction.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/\" \/>\n<meta property=\"og:site_name\" content=\"Kinsta\u00ae\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/kinstafrance\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-06T10:44:06+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-09-20T10:59:48+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/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=\"Apprenez \u00e0 utiliser des extraits de code ou une extension WordPress d&#039;abstraction pour supprimer les d\u00e9pendances fixes du code et produire des paquets en interaction.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2021\/09\/abstract-wordpress-plugin.jpeg\" \/>\n<meta name=\"twitter:creator\" content=\"@losoviz\" \/>\n<meta name=\"twitter:site\" content=\"@kinsta_fr\" \/>\n<meta name=\"twitter:label1\" content=\"\u00c9crit par\" \/>\n\t<meta name=\"twitter:data1\" content=\"Leonardo Losoviz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Dur\u00e9e de lecture estim\u00e9e\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/\"},\"author\":{\"name\":\"Leonardo Losoviz\",\"@id\":\"https:\/\/kinsta.com\/fr\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238\"},\"headline\":\"Abstraction WordPress : Meilleures pratiques et plugins WordPress d&rsquo;abstraction\",\"datePublished\":\"2021-09-06T10:44:06+00:00\",\"dateModified\":\"2024-09-20T10:59:48+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/\"},\"wordCount\":3587,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/fr\/#organization\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2021\/09\/abstract-wordpress-plugin.jpeg\",\"keywords\":[\"code\",\"web development\"],\"articleSection\":[\"Meilleurs Tutoriels WordPress\"],\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/\",\"url\":\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/\",\"name\":\"Abstraction WordPress : Meilleures pratiques et plugins WordPress d'abstraction\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/fr\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2021\/09\/abstract-wordpress-plugin.jpeg\",\"datePublished\":\"2021-09-06T10:44:06+00:00\",\"dateModified\":\"2024-09-20T10:59:48+00:00\",\"description\":\"Apprenez \u00e0 utiliser des extraits de code ou une extension WordPress d'abstraction pour supprimer les d\u00e9pendances fixes du code et produire des paquets en interaction.\",\"breadcrumb\":{\"@id\":\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#breadcrumb\"},\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#primaryimage\",\"url\":\"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2021\/09\/abstract-wordpress-plugin.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2021\/09\/abstract-wordpress-plugin.jpeg\",\"width\":1460,\"height\":730,\"caption\":\"Abstraction WordPress : Meilleures pratiques et plugins d'abstraction WordPress\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/kinsta.com\/fr\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"D\u00e9veloppement WordPress\",\"item\":\"https:\/\/kinsta.com\/fr\/sujets\/developpement-wordpress\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Abstraction WordPress : Meilleures pratiques et plugins WordPress d&#8217;abstraction\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/kinsta.com\/fr\/#website\",\"url\":\"https:\/\/kinsta.com\/fr\/\",\"name\":\"Kinsta\u00ae\",\"description\":\"Solutions d&#039;h\u00e9bergement premium, rapides et s\u00e9curis\u00e9es\",\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/fr\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/kinsta.com\/fr\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"fr-FR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/kinsta.com\/fr\/#organization\",\"name\":\"Kinsta\",\"url\":\"https:\/\/kinsta.com\/fr\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"https:\/\/kinsta.com\/fr\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2023\/12\/kinsta-logo.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2023\/12\/kinsta-logo.jpeg\",\"width\":500,\"height\":500,\"caption\":\"Kinsta\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/fr\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/kinstafrance\/\",\"https:\/\/x.com\/kinsta_fr\",\"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\/fr\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238\",\"name\":\"Leonardo Losoviz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"https:\/\/kinsta.com\/fr\/#\/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\/fr\/blog\/author\/leonardolosoviz\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Abstraction WordPress : Meilleures pratiques et plugins WordPress d'abstraction","description":"Apprenez \u00e0 utiliser des extraits de code ou une extension WordPress d'abstraction pour supprimer les d\u00e9pendances fixes du code et produire des paquets en interaction.","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\/fr\/blog\/plugin-wordpress-abstraction\/","og_locale":"fr_FR","og_type":"article","og_title":"Abstraction WordPress : Meilleures pratiques et plugins WordPress d'abstraction","og_description":"Apprenez \u00e0 utiliser des extraits de code ou une extension WordPress d'abstraction pour supprimer les d\u00e9pendances fixes du code et produire des paquets en interaction.","og_url":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/","og_site_name":"Kinsta\u00ae","article_publisher":"https:\/\/www.facebook.com\/kinstafrance\/","article_published_time":"2021-09-06T10:44:06+00:00","article_modified_time":"2024-09-20T10:59:48+00:00","og_image":[{"width":1460,"height":730,"url":"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2021\/09\/abstract-wordpress-plugin.jpeg","type":"image\/jpeg"}],"author":"Leonardo Losoviz","twitter_card":"summary_large_image","twitter_description":"Apprenez \u00e0 utiliser des extraits de code ou une extension WordPress d'abstraction pour supprimer les d\u00e9pendances fixes du code et produire des paquets en interaction.","twitter_image":"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2021\/09\/abstract-wordpress-plugin.jpeg","twitter_creator":"@losoviz","twitter_site":"@kinsta_fr","twitter_misc":{"\u00c9crit par":"Leonardo Losoviz","Dur\u00e9e de lecture estim\u00e9e":"17 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#article","isPartOf":{"@id":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/"},"author":{"name":"Leonardo Losoviz","@id":"https:\/\/kinsta.com\/fr\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238"},"headline":"Abstraction WordPress : Meilleures pratiques et plugins WordPress d&rsquo;abstraction","datePublished":"2021-09-06T10:44:06+00:00","dateModified":"2024-09-20T10:59:48+00:00","mainEntityOfPage":{"@id":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/"},"wordCount":3587,"commentCount":0,"publisher":{"@id":"https:\/\/kinsta.com\/fr\/#organization"},"image":{"@id":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2021\/09\/abstract-wordpress-plugin.jpeg","keywords":["code","web development"],"articleSection":["Meilleurs Tutoriels WordPress"],"inLanguage":"fr-FR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/","url":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/","name":"Abstraction WordPress : Meilleures pratiques et plugins WordPress d'abstraction","isPartOf":{"@id":"https:\/\/kinsta.com\/fr\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#primaryimage"},"image":{"@id":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2021\/09\/abstract-wordpress-plugin.jpeg","datePublished":"2021-09-06T10:44:06+00:00","dateModified":"2024-09-20T10:59:48+00:00","description":"Apprenez \u00e0 utiliser des extraits de code ou une extension WordPress d'abstraction pour supprimer les d\u00e9pendances fixes du code et produire des paquets en interaction.","breadcrumb":{"@id":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#breadcrumb"},"inLanguage":"fr-FR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/"]}]},{"@type":"ImageObject","inLanguage":"fr-FR","@id":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#primaryimage","url":"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2021\/09\/abstract-wordpress-plugin.jpeg","contentUrl":"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2021\/09\/abstract-wordpress-plugin.jpeg","width":1460,"height":730,"caption":"Abstraction WordPress : Meilleures pratiques et plugins d'abstraction WordPress"},{"@type":"BreadcrumbList","@id":"https:\/\/kinsta.com\/fr\/blog\/plugin-wordpress-abstraction\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kinsta.com\/fr\/"},{"@type":"ListItem","position":2,"name":"D\u00e9veloppement WordPress","item":"https:\/\/kinsta.com\/fr\/sujets\/developpement-wordpress\/"},{"@type":"ListItem","position":3,"name":"Abstraction WordPress : Meilleures pratiques et plugins WordPress d&#8217;abstraction"}]},{"@type":"WebSite","@id":"https:\/\/kinsta.com\/fr\/#website","url":"https:\/\/kinsta.com\/fr\/","name":"Kinsta\u00ae","description":"Solutions d&#039;h\u00e9bergement premium, rapides et s\u00e9curis\u00e9es","publisher":{"@id":"https:\/\/kinsta.com\/fr\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kinsta.com\/fr\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"fr-FR"},{"@type":"Organization","@id":"https:\/\/kinsta.com\/fr\/#organization","name":"Kinsta","url":"https:\/\/kinsta.com\/fr\/","logo":{"@type":"ImageObject","inLanguage":"fr-FR","@id":"https:\/\/kinsta.com\/fr\/#\/schema\/logo\/image\/","url":"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2023\/12\/kinsta-logo.jpeg","contentUrl":"https:\/\/kinsta.com\/fr\/wp-content\/uploads\/sites\/4\/2023\/12\/kinsta-logo.jpeg","width":500,"height":500,"caption":"Kinsta"},"image":{"@id":"https:\/\/kinsta.com\/fr\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/kinstafrance\/","https:\/\/x.com\/kinsta_fr","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\/fr\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238","name":"Leonardo Losoviz","image":{"@type":"ImageObject","inLanguage":"fr-FR","@id":"https:\/\/kinsta.com\/fr\/#\/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\/fr\/blog\/author\/leonardolosoviz\/"}]}},"acf":[],"_links":{"self":[{"href":"https:\/\/kinsta.com\/fr\/wp-json\/wp\/v2\/posts\/48186","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinsta.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinsta.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinsta.com\/fr\/wp-json\/wp\/v2\/users\/196"}],"replies":[{"embeddable":true,"href":"https:\/\/kinsta.com\/fr\/wp-json\/wp\/v2\/comments?post=48186"}],"version-history":[{"count":14,"href":"https:\/\/kinsta.com\/fr\/wp-json\/wp\/v2\/posts\/48186\/revisions"}],"predecessor-version":[{"id":48619,"href":"https:\/\/kinsta.com\/fr\/wp-json\/wp\/v2\/posts\/48186\/revisions\/48619"}],"alternate":[{"embeddable":true,"hreflang":"en","title":"English","href":"https:\/\/kinsta.com\/fr\/wp-json\/kinsta\/v1\/posts\/48186\/translations\/en"},{"embeddable":true,"hreflang":"it","title":"Italian","href":"https:\/\/kinsta.com\/fr\/wp-json\/kinsta\/v1\/posts\/48186\/translations\/it"},{"embeddable":true,"hreflang":"fr","title":"French","href":"https:\/\/kinsta.com\/fr\/wp-json\/kinsta\/v1\/posts\/48186\/translations\/fr"},{"embeddable":true,"hreflang":"es","title":"Spanish","href":"https:\/\/kinsta.com\/fr\/wp-json\/kinsta\/v1\/posts\/48186\/translations\/es"},{"embeddable":true,"hreflang":"pt","title":"Portuguese","href":"https:\/\/kinsta.com\/fr\/wp-json\/kinsta\/v1\/posts\/48186\/translations\/pt"},{"embeddable":true,"hreflang":"de","title":"German","href":"https:\/\/kinsta.com\/fr\/wp-json\/kinsta\/v1\/posts\/48186\/translations\/de"},{"embeddable":true,"hreflang":"nl","title":"Dutch","href":"https:\/\/kinsta.com\/fr\/wp-json\/kinsta\/v1\/posts\/48186\/translations\/nl"},{"href":"https:\/\/kinsta.com\/fr\/wp-json\/kinsta\/v1\/posts\/48186\/tree"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kinsta.com\/fr\/wp-json\/wp\/v2\/media\/48193"}],"wp:attachment":[{"href":"https:\/\/kinsta.com\/fr\/wp-json\/wp\/v2\/media?parent=48186"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinsta.com\/fr\/wp-json\/wp\/v2\/tags?post=48186"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/kinsta.com\/fr\/wp-json\/wp\/v2\/topic?post=48186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}