{"id":43462,"date":"2021-09-12T14:53:32","date_gmt":"2021-09-12T12:53:32","guid":{"rendered":"https:\/\/kinsta.com\/?p=100908"},"modified":"2023-10-03T15:23:55","modified_gmt":"2023-10-03T14:23:55","slug":"wordpress-abstraktions-plugins","status":"publish","type":"post","link":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/","title":{"rendered":"WordPress-Abstraktion: Bew\u00e4hrte Praktiken und WordPress-Abstraktions-Plugins"},"content":{"rendered":"<p>WordPress ist ein altes CMS, aber auch das <a href=\"https:\/\/kinsta.com\/de\/wordpress-marktanteil\/\">meistgenutzte<\/a>. Da es in der Vergangenheit veraltete PHP-Versionen und Legacy-Code unterst\u00fctzt hat, mangelt es immer noch an der Umsetzung moderner Programmierpraktiken &#8211; WordPress-Abstraktion ist ein Beispiel daf\u00fcr.<\/p>\n<p>Es w\u00e4re zum Beispiel viel besser, die WordPress-Kern-Codebasis in Pakete aufzuteilen, die von Composer verwaltet werden. Oder vielleicht, um WordPress-Klassen automatisch aus Dateipfaden zu laden.<\/p>\n<p>In diesem Artikel erf\u00e4hrst du, wie du WordPress-Code manuell abstrahieren und abstrakte WordPress-Plugin-Funktionen nutzen kannst.<\/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>Probleme bei der Integration von WordPress und PHP-Tools<\/h2>\n<p>Aufgrund seiner alten Architektur sto\u00dfen wir gelegentlich auf Probleme, wenn wir WordPress mit Werkzeugen f\u00fcr PHP-Codebasen integrieren, z. B. mit dem statischen Analysator <a href=\"https:\/\/phpstan.org\/\">PHPStan<\/a>, der Unit-Test-Bibliothek <a href=\"https:\/\/phpunit.de\/\">PHPUnit<\/a> und der Namespace-Scoping-Bibliothek <a href=\"https:\/\/github.com\/humbug\/php-scoper\">PHP-Scoper<\/a>. Betrachte zum Beispiel die folgenden F\u00e4lle:<\/p>\n<ul>\n<li>Vor der Ver\u00f6ffentlichung von <a href=\"https:\/\/kinsta.com\/de\/blog\/wordpress-5-6\/\">WordPress 5.6<\/a> mit Unterst\u00fctzung f\u00fcr<a href=\"https:\/\/kinsta.com\/de\/blog\/php-8\/\"> PHP 8.0<\/a> wurde in einem Bericht von Yoast beschrieben, dass die Ausf\u00fchrung von PHPStan auf dem WordPress-Kern <a href=\"https:\/\/developer.yoast.com\/blog\/the-2020-wordpress-and-php-8-compatibility-report\/#h-scanning-wordpress-with-phpstan\">tausende von Fehlern<\/a> erzeugen w\u00fcrde.<\/li>\n<li>Da WordPress immer noch PHP 5.6 unterst\u00fctzt, <a href=\"https:\/\/core.trac.wordpress.org\/ticket\/46149\">unterst\u00fctzen die Testsuiten von WordPress derzeit nur PHPUnit bis zur Version 7.5<\/a>, die das Ende ihrer Lebensdauer erreicht hat.<\/li>\n<li>Das Scoping von WordPress-Plugins mit PHP-Scoper ist <a href=\"https:\/\/github.com\/humbug\/php-scoper#wordpress\">eine gro\u00dfe Herausforderung<\/a>.<\/li>\n<\/ul>\n<p>Der WordPress-Code in unseren Projekten macht nur einen Bruchteil des Gesamtumfangs aus; das Projekt enth\u00e4lt auch Gesch\u00e4ftscode, der unabh\u00e4ngig vom zugrunde liegenden CMS ist. Dennoch kann es sein, dass das Projekt allein aufgrund des WordPress-Codes nicht richtig in das Tooling integriert werden kann.<\/p>\n<p>Aus diesem Grund k\u00f6nnte es sinnvoll sein, das Projekt in Pakete aufzuteilen, von denen einige WordPress-Code enthalten und andere nur Business-Code mit &#8222;Vanilla&#8220;-PHP und keinen WordPress-Code enthalten. Auf diese Weise sind die letztgenannten Pakete nicht von den oben beschriebenen Problemen betroffen, sondern k\u00f6nnen perfekt in das Tooling integriert werden.<\/p>\n<h2>Was ist Code-Abstraktion?<\/h2>\n<p>Die Code-Abstraktion entfernt feste Abh\u00e4ngigkeiten aus dem Code und erzeugt Pakete, die \u00fcber Vertr\u00e4ge miteinander interagieren. Diese Pakete k\u00f6nnen dann zu verschiedenen Anwendungen mit unterschiedlichen Stacks hinzugef\u00fcgt werden, um ihre Nutzbarkeit zu maximieren. Das Ergebnis der Codeabstraktion ist eine sauber entkoppelte Codebasis, die auf den folgenden S\u00e4ulen beruht:<\/p>\n<ol>\n<li>Programmiere gegen Schnittstellen, nicht gegen Implementierungen.<\/li>\n<li>Erstelle Pakete und verteile sie \u00fcber den Composer.<\/li>\n<li>Verbinde alle Teile \u00fcber Dependency Injection miteinander.<\/li>\n<\/ol>\n\n<h2>Gegen Schnittstellen programmieren, nicht gegen Implementierungen<\/h2>\n<p>Beim Programmieren gegen Schnittstellen werden Vertr\u00e4ge verwendet, um Code-Teile miteinander interagieren zu lassen. Ein Vertrag ist einfach eine PHP-Schnittstelle (oder eine andere Sprache), die festlegt, welche Funktionen verf\u00fcgbar sind und welche Signaturen sie haben, d.h. welche Eingaben sie erhalten und welche Ausgaben sie haben.<\/p>\n<p>Eine Schnittstelle deklariert die Absicht der Funktionalit\u00e4t, ohne zu erkl\u00e4ren, wie die Funktionalit\u00e4t implementiert wird. Indem wir \u00fcber Schnittstellen auf Funktionen zugreifen, kann sich unsere <a href=\"https:\/\/kinsta.com\/de\/blog\/application-performance-monitoring\/\">Anwendung<\/a> auf autonome Codeteile verlassen, die ein bestimmtes Ziel erreichen, ohne zu wissen oder sich darum zu k\u00fcmmern, wie sie es erreichen. Auf diese Weise muss die Anwendung nicht angepasst werden, um zu einem anderen Teil des Codes zu wechseln, der dasselbe Ziel erreicht &#8211; zum Beispiel von einem anderen Anbieter.<\/p>\n<h3>Beispiel f\u00fcr Vertr\u00e4ge<\/h3>\n<p>Der folgende Code verwendet den Vertrag <a href=\"https:\/\/github.com\/symfony\/symfony\/blob\/302b844\/src\/Symfony\/Contracts\/Cache\/CacheInterface.php\"><code>CacheInterface<\/code><\/a> von Symfony und den Vertrag <a href=\"https:\/\/github.com\/php-fig\/cache\/blob\/0a7c67d\/src\/CacheItemInterface.php\"><code>CacheItemInterface<\/code><\/a> der PHP Standard Recommendation (PSR), um die Caching-Funktionalit\u00e4t zu implementieren:<\/p>\n<pre><code class=\"language-php\">use Psr\\<span id=\"urn:enhancement-879f5fac-ac26-4011-b238-a0c284f17239\" class=\"textannotation\">Cache<\/span>\\CacheItemInterface;\nuse <span id=\"urn:enhancement-6cb88507-4df7-4704-b697-0708a487f682\" class=\"textannotation\">Symfony<\/span>\\<span id=\"urn:enhancement-666298e3-1629-4842-b2d0-d1509fbae6a6\" class=\"textannotation\">Contracts<\/span>\\<span id=\"urn:enhancement-7159fc71-ea38-4813-9c5b-650493ceb703\" class=\"textannotation\">Cache<\/span>\\CacheInterface;\n\n$<span id=\"urn:enhancement-1e511e2e-c39d-4215-9ea0-3f96ba256f56\" class=\"textannotation\">value<\/span> = $cache-&gt;get('my_cache_key', <span id=\"urn:enhancement-8529ae57-f72a-4d95-acb8-62f92e4769d7\" class=\"textannotation\">function<\/span> (CacheItemInterface $item) {\n    $item-&gt;expiresAfter(3600);\n    <span id=\"urn:enhancement-e6c4cf80-2d68-4ef0-ae65-72b146a59102\" class=\"textannotation\">return<\/span> 'foobar';\n});\n<\/code><\/pre>\n<p><code>$cache<\/code> implementiert das <code>CacheInterface<\/code>, das die Methode <code>get<\/code> definiert, um ein Objekt aus dem Cache zu holen. Durch den Zugriff auf diese Funktion \u00fcber den Vertrag kann die Anwendung nicht wissen, wo sich der Cache befindet. Ob er sich im Speicher, auf der Festplatte, in der Datenbank, im Netzwerk oder sonst wo befindet. Trotzdem muss sie die Funktion ausf\u00fchren. <code>CacheItemInterface<\/code> definiert die Methode <code>expiresAfter,<\/code> um festzulegen, wie lange das Objekt im Cache gehalten werden muss. Die Anwendung kann diese Methode aufrufen, ohne sich darum zu k\u00fcmmern, was das gecachte Objekt ist; es ist nur wichtig, wie lange es im Cache bleiben muss.<\/p>\n<h2>Gegen Schnittstellen in WordPress programmieren<\/h2>\n<p>Da wir den WordPress-Code abstrahieren, hat das zur Folge, dass die Anwendung nicht direkt auf <a href=\"https:\/\/kinsta.com\/de\/blog\/bearbeitest-wordpress-code\/\">WordPress-Code<\/a> verweist, sondern immer \u00fcber eine Schnittstelle. Die WordPress-Funktion <code>get_posts<\/code> hat zum Beispiel diese Signatur:<\/p>\n<pre><code class=\"language-php\">\/**\n * @param array $<span id=\"urn:enhancement-1d4c409b-ca9f-4e75-b4ec-bd00224c7015\" class=\"textannotation\">args<\/span>\n * @<span id=\"urn:enhancement-a77204f5-7dc0-4420-9a4c-10ddb1727209\" class=\"textannotation\">return<\/span> <span id=\"urn:enhancement-680e5b46-d0e4-4d69-b375-87e591bef167\" class=\"textannotation\">WP<\/span>_Post[]|int[] <span id=\"urn:enhancement-9730c6c0-da70-4f47-8daa-8935a001df73\" class=\"textannotation\">Array<\/span> of <span id=\"urn:enhancement-04041cde-476c-450e-9ec9-2ffac26f5068\" class=\"textannotation\">post<\/span> objects or <span id=\"urn:enhancement-dc7df883-2568-403b-914c-41f26254b7c4\" class=\"textannotation\">post<\/span> IDs.\n *\/\n<span id=\"urn:enhancement-9ad2f6f9-03f2-4d32-83c0-115c7427b74d\" class=\"textannotation\">function<\/span> get_posts( $<span id=\"urn:enhancement-36116b80-75d3-4f2f-a2d5-b380b9ce376a\" class=\"textannotation\">args<\/span> = null )\n<\/code><\/pre>\n<p>Anstatt diese Methode direkt aufzurufen, k\u00f6nnen wir sie \u00fcber den Vertrag <code>Owner\\MyApp\\<span id=\"urn:enhancement-63f0d7cc-ae47-4ea7-8d30-218c6c6f21e9\" class=\"textannotation\">Contracts<\/span>\\PostsAPIInterface<\/code>:<\/p>\n<pre><code class=\"language-php\"><span id=\"urn:enhancement-34adf003-6b2e-46dd-975c-04a99c9ea820\" class=\"textannotation\">namespace<\/span> Owner\\MyApp\\<span id=\"urn:enhancement-836d0837-cabc-432d-8370-74f659a0e530\" class=\"textannotation\">Contracts<\/span>;\n\ninterface PostAPIInterface\n{\n  <span id=\"urn:enhancement-fea5cf1b-9684-4624-b22e-82d2f75d5487\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-dcd5d241-25aa-4f18-9082-aa81dfdf04c6\" class=\"textannotation\">function<\/span> get_posts(array $<span id=\"urn:enhancement-5c242e40-2deb-47d1-8924-d68c9342874e\" class=\"textannotation\">args<\/span> = null): PostInterface[]|int[];\n}\n<\/code><\/pre>\n<p>Beachte, dass die WordPress-Funktion <code>get_posts<\/code> Objekte der Klasse <code>WP_Post<\/code> zur\u00fcckgeben kann, die spezifisch f\u00fcr WordPress ist. Wenn wir den Code abstrahieren, m\u00fcssen wir diese Art der festen Abh\u00e4ngigkeit aufheben. Die Methode <code>get_posts<\/code> im Vertrag gibt Objekte des Typs <code>PostInterface<\/code> zur\u00fcck, so dass du die Klasse <code>WP_Post<\/code> referenzieren kannst, ohne es explizit zu erw\u00e4hnen. Die Klasse <code>PostInterface<\/code> muss Zugriff auf alle Methoden und Attribute von <code>WP_Post<\/code> bieten:<\/p>\n<pre><code class=\"language-php\"><span id=\"urn:enhancement-cdd1c5b5-dceb-46fa-9a03-9b25c74b221c\" class=\"textannotation\">namespace<\/span> Owner\\MyApp\\<span id=\"urn:enhancement-70c014d2-7157-43cd-8bc0-489085b7a1cd\" class=\"textannotation\">Contracts<\/span>;\n\ninterface PostInterface\n{\n  <span id=\"urn:enhancement-f704a3cc-23a3-4a0a-9031-f0d41cc53aa8\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-b224debe-2daa-46e7-a409-67325890418e\" class=\"textannotation\">function<\/span> get_<span id=\"urn:enhancement-0e62304f-5926-4654-bcef-fae1250af012\" class=\"textannotation\">ID<\/span>(): int;\n  <span id=\"urn:enhancement-c66163c7-505a-452f-99ec-1a4643f232b4\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-a37494dc-b503-48fb-a38b-8414880761c5\" class=\"textannotation\">function<\/span> get_<span id=\"urn:enhancement-d036a55c-2aa3-4f74-a8d7-0a82f01af6bb\" class=\"textannotation\">post<\/span>_<span id=\"urn:enhancement-4672917e-d6b5-4743-a1e7-4017d98906a6\" class=\"textannotation\">author<\/span>(): string;\n  <span id=\"urn:enhancement-87a28813-e3b9-4a25-8f25-5700a41b19fc\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-33a7e010-5da0-472f-97b0-2a70e6cfbde7\" class=\"textannotation\">function<\/span> get_<span id=\"urn:enhancement-01d7ad55-7f9d-48d3-8107-4efdaf3b2a43\" class=\"textannotation\">post<\/span>_date(): string;\n  \/\/ ...\n}\n<\/code><\/pre>\n<p>Executing this <span id=\"urn:enhancement-d8cbdbba-7a14-4c49-be04-599272e445e9\" class=\"textannotation\">strategy<\/span> can change our understanding of where <span id=\"urn:enhancement-50da1f70-5f2a-46c6-b6ae-d9eadcca3d3d\" class=\"textannotation\">WordPress<\/span> fits in our stack. Instead of thinking of <span id=\"urn:enhancement-a98ea8bf-bde9-4508-b94b-0bc7e0a372b8\" class=\"textannotation\">WordPress<\/span> as the <span id=\"urn:enhancement-babf0b6b-f01b-4110-ab73-a2cd50c27117\" class=\"textannotation\">application<\/span> itself (over which we install themes and <span id=\"urn:enhancement-8b503865-f26c-4946-aa68-4870ada3f311\" class=\"textannotation\">plugins<\/span>), we can think of it simply as another <span id=\"urn:enhancement-b9ad1894-248f-4634-bfe3-b9c04f82125b\" class=\"textannotation\">dependency<\/span> within the <span id=\"urn:enhancement-9ee3ed46-c5f6-46b6-b4bb-a0a8f4502a38\" class=\"textannotation\">application<\/span>, replaceable as any other <span id=\"urn:enhancement-b25b68b5-b146-4c83-92b5-cc3953b5850c\" class=\"textannotation\">component<\/span>. (Even though we won&#8217;t replace <span id=\"urn:enhancement-12fb5581-9125-4bee-a40c-d22c99082205\" class=\"textannotation\">WordPress<\/span> in practice, it <em>is<\/em> replaceable from a conceptual point of <span id=\"urn:enhancement-de2b5639-09c5-4e66-8a68-1fadc90def58\" class=\"textannotation\">view<\/span>.)<\/p>\n<h2>Erstellen und Verteilen von Paketen<\/h2>\n<p><a href=\"https:\/\/getcomposer.org\/\">Composer<\/a> ist ein Paketmanager f\u00fcr PHP. Er erm\u00f6glicht es PHP-Anwendungen, Pakete (d. h. Codeteile) aus einem Repository abzurufen und als Abh\u00e4ngigkeiten zu installieren. Um die Anwendung von WordPress zu entkoppeln, m\u00fcssen wir ihren Code in zwei verschiedene Pakete aufteilen: die Pakete mit WordPress-Code und die anderen mit Gesch\u00e4ftslogik (also ohne WordPress-Code).<\/p>\n<p>Schlie\u00dflich f\u00fcgen wir alle Pakete als Abh\u00e4ngigkeiten in die Anwendung ein und installieren sie \u00fcber den Composer. Da das Tooling auf die Pakete mit dem Gesch\u00e4ftscode angewendet wird, m\u00fcssen diese den gr\u00f6\u00dften Teil des Codes der Anwendung enthalten; je h\u00f6her der Prozentsatz, desto besser. Ein gutes Ziel ist es, dass sie etwa 90% des gesamten Codes verwalten.<\/p>\n<h2>WordPress-Code in Pakete extrahieren<\/h2>\n<p>In Anlehnung an das Beispiel von vorhin werden die Vertr\u00e4ge <code>PostAPIInterface<\/code> und <code>PostInterface<\/code> zu dem Paket hinzugef\u00fcgt, das den Gesch\u00e4ftscode enth\u00e4lt, und ein weiteres Paket wird die WordPress-Implementierung dieser Vertr\u00e4ge enthalten. Um <code>PostInterface<\/code> zu erf\u00fcllen, erstellen wir eine <code>PostWrapper<\/code>-Klasse, die alle Attribute von einem <code>WP_Post<\/code>-Objekt abruft:<\/p>\n<pre><code class=\"language-php\"><span id=\"urn:enhancement-90ac4d94-b0cb-4281-a20d-ffcda86bf355\" class=\"textannotation\">namespace<\/span> Owner\\MyAppForWP\\ContractImplementations;\n\nuse Owner\\MyApp\\<span id=\"urn:enhancement-c159f6f7-6414-40c7-a9d8-eaea33db00e9\" class=\"textannotation\">Contracts<\/span>\\PostInterface;\nuse <span id=\"urn:enhancement-259e4e45-b28e-444f-ab7c-90c1a9921d12\" class=\"textannotation\">WP<\/span>_Post;\n\n<span id=\"urn:enhancement-1f88ee49-e77a-43a5-80a4-4a78b670f04b\" class=\"textannotation\">class<\/span> PostWrapper <span id=\"urn:enhancement-04ca1a6a-90e7-4a94-9d50-a3e8fccf9ad5\" class=\"textannotation\">implements<\/span> PostInterface\n{\n  private <span id=\"urn:enhancement-3a11f491-240d-47c8-939c-39b4db71d35b\" class=\"textannotation\">WP<\/span>_Post $<span id=\"urn:enhancement-2efd8ac1-af13-43a7-af33-9eb22e113776\" class=\"textannotation\">post<\/span>;\n  \n  <span id=\"urn:enhancement-4d9b4640-840b-4291-9e08-3b9d81076f64\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-8696a3a1-3070-4e6a-8ed6-42337c7dd865\" class=\"textannotation\">function<\/span> __construct(<span id=\"urn:enhancement-5ad994d2-ae64-4fdc-901d-e087701cc202\" class=\"textannotation\">WP<\/span>_Post $<span id=\"urn:enhancement-26243a5c-04dc-4c99-aa31-bb0dd12d9980\" class=\"textannotation\">post<\/span>)\n  {\n    $this-&gt;<span id=\"urn:enhancement-99ada088-fb80-4ff6-91f3-987a8bf60fc6\" class=\"textannotation\">post<\/span> = $<span id=\"urn:enhancement-32e62759-0d24-4cca-a374-b6695a28d0c9\" class=\"textannotation\">post<\/span>;\n  }\n\n  <span id=\"urn:enhancement-22c9483e-ee7d-44f1-ba54-c95178968577\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-7c5ba073-a3a9-49ca-a837-42eb1cc74cec\" class=\"textannotation\">function<\/span> get_<span id=\"urn:enhancement-96e913dd-40bf-4225-9c88-06e958753f9d\" class=\"textannotation\">ID<\/span>(): int\n  {\n    <span id=\"urn:enhancement-c35366f3-f8f4-4e46-a09f-8a1229d2a7ba\" class=\"textannotation\">return<\/span> $this-&gt;<span id=\"urn:enhancement-aa52c6fc-080d-49ad-961a-ed0009e2db00\" class=\"textannotation\">post<\/span>-&gt;<span id=\"urn:enhancement-82d0c698-b3d4-4e2e-be15-16291253d8a6\" class=\"textannotation\">ID<\/span>;\n  }\n\n  <span id=\"urn:enhancement-eb83d315-ca4e-4c32-9af3-eb004d7e5b37\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-6fe429eb-3986-4111-a772-789cd70dbefd\" class=\"textannotation\">function<\/span> get_<span id=\"urn:enhancement-961e51fa-ee2e-404e-8a97-1cfaf7e4270f\" class=\"textannotation\">post<\/span>_<span id=\"urn:enhancement-83138123-9f8a-4bfd-9c01-7672e3f9aa0e\" class=\"textannotation\">author<\/span>(): string\n  {\n    <span id=\"urn:enhancement-05e10168-e303-46d0-a265-ceb93ed2cce6\" class=\"textannotation\">return<\/span> $this-&gt;<span id=\"urn:enhancement-5877c90e-535d-4d93-ae6c-4c05d727e93f\" class=\"textannotation\">post<\/span>-&gt;<span id=\"urn:enhancement-5d8217be-78ae-4ca3-8582-c48de5a63ced\" class=\"textannotation\">post<\/span>_<span id=\"urn:enhancement-2ea5c480-9609-4d3b-ae15-5c10f43f4b18\" class=\"textannotation\">author<\/span>;\n  }\n\n  <span id=\"urn:enhancement-3ff2c721-3b24-4e60-b502-8e1588c6dd8c\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-e126fe3c-a542-46e5-a57b-2547a338bf7d\" class=\"textannotation\">function<\/span> get_<span id=\"urn:enhancement-a62468df-2cb2-4f6c-870e-0ae78684b10d\" class=\"textannotation\">post<\/span>_date(): string\n  {\n    <span id=\"urn:enhancement-ca44b08b-c278-44eb-8e15-0eafd00f02e6\" class=\"textannotation\">return<\/span> $this-&gt;<span id=\"urn:enhancement-485ab084-97be-4346-ae83-c6b95aa1e733\" class=\"textannotation\">post<\/span>-&gt;<span id=\"urn:enhancement-3ddd2fe5-019d-40c4-9d47-94470388ae50\" class=\"textannotation\">post<\/span>_date;\n  }\n\n  \/\/ ...\n}\n<\/code><\/pre>\n<p>Bei der Implementierung der <code>PostAPI<\/code> m\u00fcssen wir, da die Methode <code>get_posts<\/code> <code>PostInterface[]<\/code> zur\u00fcckgibt, Objekte von <code>WP_Post<\/code> in <code>PostWrapper<\/code> umwandeln:<\/p>\n<pre><code class=\"language-php\"><span id=\"urn:enhancement-cedd57f6-7c29-4b5a-b077-eec8f54cf5f3\" class=\"textannotation\">namespace<\/span> Owner\\MyAppForWP\\ContractImplementations;\n\nuse Owner\\MyApp\\<span id=\"urn:enhancement-5d17c51e-3914-4695-8d7c-8cabc7205a9d\" class=\"textannotation\">Contracts<\/span>\\PostAPIInterface;\nuse <span id=\"urn:enhancement-82981d3e-6659-4665-9b63-3a2618501e34\" class=\"textannotation\">WP<\/span>_Post;\n\n<span id=\"urn:enhancement-0c5db9bc-c715-47e0-8d17-8e8d03e6db75\" class=\"textannotation\">class<\/span> PostAPI <span id=\"urn:enhancement-74b0411e-1ebe-42e3-913a-7bc16a592418\" class=\"textannotation\">implements<\/span> PostAPIInterface\n{\n  <span id=\"urn:enhancement-f7dc14dd-e851-4b7c-9db6-35e029b255c2\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-abf5ba99-d728-4e4c-ab1c-ed452081d9c1\" class=\"textannotation\">function<\/span> get_posts(array $<span id=\"urn:enhancement-f39fab8c-2e27-4fd1-8515-78944ec1a0d0\" class=\"textannotation\">args<\/span> = null): PostInterface[]|int[]\n  {\n    \/\/ This var <span id=\"urn:enhancement-2a83df9e-61ed-48dc-b3d4-de13f8e5ac53\" class=\"textannotation\">will<\/span> contain <span id=\"urn:enhancement-4e009f78-221f-4021-b537-690589bedba5\" class=\"textannotation\">WP<\/span>_Post[] or int[]\n    $wpPosts = \\get_posts($<span id=\"urn:enhancement-c0106ecb-028c-44a3-a55b-b293ba6b5299\" class=\"textannotation\">args<\/span>);\n\n    \/\/ Convert <span id=\"urn:enhancement-db06c176-dcb5-424f-b116-7e591fcefdf0\" class=\"textannotation\">WP<\/span>_Post[] to PostWrapper[]\n    <span id=\"urn:enhancement-de341245-d60b-4d17-9c5f-d81863d1fbaa\" class=\"textannotation\">return<\/span> array_map(\n      <span id=\"urn:enhancement-55f450ce-361f-4c64-aa8e-cf0f62cdee0b\" class=\"textannotation\">function<\/span> (<span id=\"urn:enhancement-a56049df-3f01-4369-b7a7-c0d4379305f5\" class=\"textannotation\">WP<\/span>_Post|int $<span id=\"urn:enhancement-d6681a37-a867-46e8-8fd4-27dc37002a4b\" class=\"textannotation\">post<\/span>) {\n        if ($<span id=\"urn:enhancement-be59a86f-d265-48ac-9e75-deef0381e3f7\" class=\"textannotation\">post<\/span> instanceof <span id=\"urn:enhancement-d5c957e0-d6ab-4c40-ad9d-5bf1e6ab85da\" class=\"textannotation\">WP<\/span>_Post) {\n          <span id=\"urn:enhancement-43a29167-7d99-43d9-81f5-cf750ff3fb0b\" class=\"textannotation\">return<\/span> <span id=\"urn:enhancement-31f088e1-0946-4fc1-8be9-71a5ff568e7c\" class=\"textannotation\">new<\/span> PostWrapper($<span id=\"urn:enhancement-7361db52-0ae0-4867-aeae-5b2c73faf1b5\" class=\"textannotation\">post<\/span>);\n        }\n        <span id=\"urn:enhancement-1594b2c9-06db-40cf-bc46-a18cad3e7a68\" class=\"textannotation\">return<\/span> $<span id=\"urn:enhancement-a89c142a-1231-4084-84a6-7be360f2be6f\" class=\"textannotation\">post<\/span>\n      },\n      $wpPosts\n    );\n  }\n}\n<\/code><\/pre>\n<h2>Dependency Injection verwenden<\/h2>\n<p>Dependency Injection ist ein Entwurfsmuster, mit dem du alle Teile der Anwendung lose miteinander koppeln kannst. Bei Dependency Injection greift die Anwendung \u00fcber ihre Vertr\u00e4ge auf Dienste zu, und die Vertragsimplementierungen werden \u00fcber die Konfiguration in die Anwendung &#8222;injiziert&#8220;.<\/p>\n<p>Wenn du die Konfiguration \u00e4nderst, kannst du ganz einfach von einem Vertragsanbieter zu einem anderen wechseln. Es gibt mehrere Bibliotheken f\u00fcr die Injektion von Abh\u00e4ngigkeiten, aus denen wir w\u00e4hlen k\u00f6nnen. Wir empfehlen, eine auszuw\u00e4hlen, die sich an die <a href=\"https:\/\/www.php-fig.org\/\">PHP Standard Recommendations<\/a> (oft als &#8222;PSR&#8220; bezeichnet) h\u00e4lt, damit wir die Bibliothek bei Bedarf leicht durch eine andere ersetzen k\u00f6nnen. Was die Dependency Injection angeht, muss die Bibliothek <a href=\"https:\/\/www.php-fig.org\/psr\/psr-11\/\">PSR-11<\/a> erf\u00fcllen, die die Spezifikation f\u00fcr eine &#8222;Container-Schnittstelle&#8220; bietet. Unter anderem erf\u00fcllen die folgenden Bibliotheken die PSR-11:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/symfony\/dependency-injection\">Symfony\u2019s DependencyInjection<\/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\">Di<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/thephpleague\/container\">Container (Dependency Injection)<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/yiisoft\/di\">Yii Dependency Injection<\/a><\/li>\n<\/ul>\n<h3>Zugriff auf Dienste \u00fcber den Service Container<\/h3>\n<p>Die Dependency-Injection-Bibliothek stellt einen &#8222;Service-Container&#8220; zur Verf\u00fcgung, der einen Vertrag in die entsprechende implementierende Klasse aufl\u00f6st. Die Anwendung muss sich auf den Service-Container verlassen, um auf alle Funktionen zuzugreifen. Normalerweise w\u00fcrden wir zum Beispiel WordPress-Funktionen direkt aufrufen:<\/p>\n<pre><code class=\"language-php\">$posts = get_posts();\n<\/code><\/pre>\n<p>&#8230;mit dem Service-Container m\u00fcssen wir zun\u00e4chst den Dienst erhalten, der <code>PostAPIInterface<\/code> erf\u00fcllt, und die Funktionalit\u00e4t \u00fcber ihn ausf\u00fchren:<\/p>\n<pre><code class=\"language-php\">use Owner\\MyApp\\<span id=\"urn:enhancement-9c7094e9-13ad-4565-8c80-8843041cb57d\" class=\"textannotation\">Contracts<\/span>\\PostAPIInterface;\n\n\/\/ Obtain the <span id=\"urn:enhancement-e43a0ab4-e8fa-441b-8bb5-183576bae0f4\" class=\"textannotation\">service<\/span> <span id=\"urn:enhancement-198c8ca3-5505-42cf-8bf0-1cdf52e59902\" class=\"textannotation\">container<\/span>, as specified by the library we use\n$serviceContainer = ContainerBuilderFactory::getInstance();\n\n\/\/ The obtained <span id=\"urn:enhancement-d97570e8-3a50-4067-bee5-6b017bd3c506\" class=\"textannotation\">service<\/span> <span id=\"urn:enhancement-73c345ec-84a6-4c7a-9b70-acd03414f85f\" class=\"textannotation\">will<\/span> be of <span id=\"urn:enhancement-17b42386-c0a8-4ecc-8836-ef0576b61c46\" class=\"textannotation\">class<\/span> Owner\\MyAppForWP\\ContractImplementations\\PostAPI\n$postAPI = $serviceContainer-&gt;get(PostAPIInterface::<span id=\"urn:enhancement-120a3fa2-2e5a-466c-a273-12d206819835\" class=\"textannotation\">class<\/span>);\n\n\/\/ Now we can invoke the <span id=\"urn:enhancement-4f5d3155-6147-42fd-a06c-4d4a9e8e7583\" class=\"textannotation\">WordPress<\/span> <span id=\"urn:enhancement-6a68c6d3-dcdb-4e5a-a85f-72fb636ce728\" class=\"textannotation\">functionality<\/span>\n$posts = $postAPI-&gt;get_posts();\n<\/code><\/pre>\n<h3>DependencyInjection von Symfony verwenden<\/h3>\n<p>Die <a href=\"https:\/\/symfony.com\/doc\/current\/components\/dependency_injection.html\">DependencyInjection-Komponente von Symfony<\/a> ist derzeit die beliebteste Dependency-Injection-Bibliothek. Sie erm\u00f6glicht es dir, den Service-Container \u00fcber PHP-, YAML- oder XML-Code zu konfigurieren. Um zum Beispiel festzulegen, dass der Vertrag <code>PostAPIInterface<\/code> \u00fcber die Klasse <code>PostAPI<\/code> erf\u00fcllt wird, wird dieser in YAML wie folgt konfiguriert:<\/p>\n<pre><code class=\"language-yaml\"><span id=\"urn:enhancement-c2a3a80f-617f-4fa1-a97a-d2edcdf9a4be\" class=\"textannotation\">services<\/span>:\n  Owner\\MyApp\\<span id=\"urn:enhancement-3760e2d0-8992-4f69-9eb8-25480e15e8e1\" class=\"textannotation\">Contracts<\/span>\\PostAPIInterface:\n    <span id=\"urn:enhancement-4e34ecd7-df18-4cb8-92fd-c30af9d5e342\" class=\"textannotation\">class<\/span>: \\Owner\\MyAppForWP\\ContractImplementations\\PostAPI\n<\/code><\/pre>\n<p>Mit DependencyInjection von Symfony k\u00f6nnen Instanzen eines Dienstes auch automatisch in jeden anderen Dienst injiziert (oder &#8222;autowired&#8220;) werden, der von ihm abh\u00e4ngt. Au\u00dferdem ist es einfach zu definieren, dass eine Klasse eine Implementierung ihres eigenen Dienstes ist. Betrachte zum Beispiel die <a href=\"https:\/\/github.com\/leoloso\/PoP\/blob\/8602e9041ac92f4683966eed5c4a90686b9395fa\/layers\/GraphQLAPIForWP\/plugins\/graphql-api-for-wp\/config\/hybrid-services.yaml\">folgende YAML-Konfiguration<\/a>:<\/p>\n<pre><code class=\"language-yaml\"><span id=\"urn:enhancement-4fcd578e-6966-4907-9948-4c4978c5f5d2\" class=\"textannotation\">services<\/span>:\n  _defaults:\n    <span id=\"urn:enhancement-7116f3ac-f6d2-4529-ac46-892bc1ea3e14\" class=\"textannotation\">public<\/span>: true\n    autowire: true\n\n  GraphQLAPI\\GraphQLAPI\\Registries\\UserAuthorizationSchemeRegistryInterface:\n    <span id=\"urn:enhancement-428c29ba-a7ff-421f-978e-dfb959a81219\" class=\"textannotation\">class<\/span>: '\\GraphQLAPI\\GraphQLAPI\\Registries\\UserAuthorizationSchemeRegistry'\n\n  GraphQLAPI\\GraphQLAPI\\<span id=\"urn:enhancement-9fa8639b-78d3-4025-bd14-93fb63fb638e\" class=\"textannotation\">Security<\/span>\\UserAuthorizationInterface:\n    <span id=\"urn:enhancement-f68b2da4-ed74-4737-8ae8-e90a99118de1\" class=\"textannotation\">class<\/span>: '\\GraphQLAPI\\GraphQLAPI\\<span id=\"urn:enhancement-c4f65d87-571f-4ca7-aea9-55c93530ec55\" class=\"textannotation\">Security<\/span>\\UserAuthorization'\n    \n  GraphQLAPI\\GraphQLAPI\\<span id=\"urn:enhancement-3dd7983d-09d4-4f5e-ad43-0ba1ac51e2ae\" class=\"textannotation\">Security<\/span>\\UserAuthorizationSchemes\\:\n    resource: '..\/src\/<span id=\"urn:enhancement-70a71d09-d402-480e-8f7a-e0e4061c82a4\" class=\"textannotation\">Security<\/span>\/UserAuthorizationSchemes\/*'\n<\/code><\/pre>\n<p>Diese Konfiguration definiert Folgendes:<\/p>\n<ul>\n<li>Der Vertrag <code>UserAuthorizationSchemeRegistryInterface<\/code> wird durch die Klasse <code>UserAuthorizationSchemeRegistry<\/code> erf\u00fcllt<\/li>\n<li>Der Vertrag <code>UserAuthorizationInterface<\/code> wird durch die Klasse <code>UserAuthorization<\/code> erf\u00fcllt.<\/li>\n<li>Alle Klassen unter dem Ordner <code>UserAuthorizationSchemes<\/code>\/ sind eine Implementierung von sich selbst<\/li>\n<li>Dienste m\u00fcssen automatisch ineinander injiziert werden (<code>autowire: true<\/code>)<\/li>\n<\/ul>\n<p>Schauen wir uns an, wie das Autowiring funktioniert. Die Klasse <a href=\"https:\/\/github.com\/leoloso\/PoP\/blob\/bd56f23b52a3e02966fdcbde4bc58f246a47a6e5\/layers\/GraphQLAPIForWP\/plugins\/graphql-api-for-wp\/src\/Security\/UserAuthorization.php\"><code>UserAuthorization<\/code><\/a> h\u00e4ngt vom Dienst mit dem Vertrag <code>UserAuthorizationSchemeRegistryInterface<\/code> ab:<\/p>\n<pre><code class=\"language-php\"><span id=\"urn:enhancement-68709a1f-6ecb-4440-9b4f-1dcbd7c2f45b\" class=\"textannotation\">class<\/span> UserAuthorization <span id=\"urn:enhancement-34bc64c4-6c0f-4ee2-b46a-552aa06fbc43\" class=\"textannotation\">implements<\/span> UserAuthorizationInterface\n{\n  <span id=\"urn:enhancement-cc04aade-cfee-41ea-80c6-8ccd7d24297d\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-ef7f4c75-28e2-4417-913e-1385c9b091a0\" class=\"textannotation\">function<\/span> __construct(\n      protected UserAuthorizationSchemeRegistryInterface $userAuthorizationSchemeRegistry\n  ) {\n  }\n\n  \/\/ ...\n}\n<\/code><\/pre>\n<p>Dank <code>autowire: true<\/code> erh\u00e4lt die DependencyInjection-Komponente f\u00fcr den Dienst <code>UserAuthorization<\/code> automatisch die erforderliche Abh\u00e4ngigkeit, n\u00e4mlich eine Instanz von <code>UserAuthorizationSchemeRegistry<\/code>.<\/p>\n<h2>Wann man abstrahieren sollte<\/h2>\n<p>Das Abstrahieren von Code kann viel Zeit und M\u00fche kosten, deshalb sollten wir es nur dann tun, wenn die Vorteile die Kosten \u00fcberwiegen. Im Folgenden findest du Vorschl\u00e4ge, wann es sich lohnen kann, den Code zu abstrahieren. Du kannst dazu die Codeschnipsel in diesem Artikel oder die unten vorgeschlagenen abstrakten WordPress-Plugins verwenden.<\/p>\n<h3>Zugang zu Werkzeugen<\/h3>\n<p>Wie bereits erw\u00e4hnt, ist es <a href=\"https:\/\/github.com\/humbug\/php-scoper\/issues\/303\">schwierig, PHP-Scoper auf WordPress laufen zu lassen<\/a>. Durch die Entkopplung des WordPress-Codes in verschiedene Pakete wird es m\u00f6glich, ein <a href=\"https:\/\/graphql-api.com\/blog\/graphql-api-for-wp-is-now-scoped-thanks-to-php-scoper\/\">WordPress-Plugin direkt zu scopen<\/a>.<\/p>\n<h3>Zeit- und Kostenersparnis beim Tooling<\/h3>\n<p>Die Ausf\u00fchrung einer PHPUnit-Testsuite dauert l\u00e4nger, wenn sie WordPress initialisieren und ausf\u00fchren muss, als wenn sie das nicht muss. Ein geringerer Zeitaufwand kann sich auch in geringeren Kosten f\u00fcr die Durchf\u00fchrung der Tests niederschlagen &#8211; GitHub Actions zum Beispiel berechnet die Kosten f\u00fcr auf <a href=\"https:\/\/kinsta.com\/de\/blog\/was-ist-github\/\">GitHub<\/a> gehostete Runner nach dem Zeitaufwand f\u00fcr die Nutzung.<\/p>\n<h3>Schweres Refactoring muss nicht sein<\/h3>\n<p>Ein bestehendes Projekt erfordert m\u00f6glicherweise ein umfangreiches Refactoring, um die erforderliche Architektur einzuf\u00fchren (Dependency Injection, Aufteilung des Codes in Pakete usw.), so dass es nur schwer herausgezogen werden kann. Wenn du den Code bei der Erstellung eines Projekts von Grund auf abstrahierst, ist es viel \u00fcberschaubarer.<\/p>\n<h3>Code f\u00fcr mehrere Plattformen programmieren<\/h3>\n<p>Indem wir 90% des Codes in ein CMS-agnostisches Paket extrahieren, k\u00f6nnen wir eine Bibliotheksversion erstellen, die f\u00fcr ein anderes CMS oder Framework funktioniert, indem wir nur 10% der gesamten Codebasis ersetzen.<\/p>\n<h3>Migrieren auf eine andere Plattform<\/h3>\n<p>Wenn wir ein Projekt von <a href=\"https:\/\/kinsta.com\/de\/blog\/wordpress-vs-drupal\/\">Drupal zu WordPress<\/a>, WordPress zu <a href=\"https:\/\/kinsta.com\/de\/blog\/laravel-9\/\">Laravel<\/a> oder einer anderen Kombination migrieren m\u00fcssen, m\u00fcssen nur 10% des Codes neu geschrieben werden &#8211; eine erhebliche Einsparung.<\/p>\n<h2>Bew\u00e4hrte Praktiken<\/h2>\n<p>W\u00e4hrend wir die Vertr\u00e4ge so gestalten, dass sie unseren Code abstrahieren, gibt es mehrere Verbesserungen, die wir an der Codebasis vornehmen k\u00f6nnen.<\/p>\n<h3>PSR-12 einhalten<\/h3>\n<p>Bei der Definition der Schnittstelle f\u00fcr den Zugriff auf die WordPress-Methoden sollten wir uns an die <a href=\"https:\/\/www.php-fig.org\/psr\/psr-12\/\">PSR-12<\/a> halten. Diese neue Spezifikation zielt darauf ab, die kognitive Reibung beim Scannen von Code verschiedener Autoren zu verringern. Wenn wir uns an PSR-12 halten, m\u00fcssen wir die WordPress-Funktionen umbenennen.<\/p>\n<p>WordPress benennt Funktionen mit <strong>snake_case<\/strong>, w\u00e4hrend PSR-12 <strong>camelCase<\/strong> verwendet. Daher wird die Funktion <code>get_posts<\/code> zu <code>getPosts<\/code>:<\/p>\n<pre><code class=\"language-php\">interface PostAPIInterface\n{\n  <span id=\"urn:enhancement-432a8654-92b5-4c3a-bfa1-447349b9fe7e\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-386ecf65-2a3a-4cf3-bb3a-6472e5585961\" class=\"textannotation\">function<\/span> getPosts(array $<span id=\"urn:enhancement-d0647aa1-7fb6-4329-8759-0a0f0a1eddd4\" class=\"textannotation\">args<\/span> = null): PostInterface[]|int[];\n}\n<\/code><\/pre>\n<p>&#8230;und:<\/p>\n<pre><code class=\"language-php\"><span id=\"urn:enhancement-bb6adddb-2807-4352-8b27-5e05527e16fc\" class=\"textannotation\">class<\/span> PostAPI <span id=\"urn:enhancement-6005ff59-e691-4dd1-89fe-709e193594a1\" class=\"textannotation\">implements<\/span> PostAPIInterface\n{\n  <span id=\"urn:enhancement-3c692c36-40a7-495e-9af1-e722b916ae91\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-dd041cce-4484-4127-a3d5-208a8cfbcf06\" class=\"textannotation\">function<\/span> getPosts(array $<span id=\"urn:enhancement-31d252b5-37c8-4eaa-828c-c4e1d45c92d9\" class=\"textannotation\">args<\/span> = null): PostInterface[]|int[]\n  {\n    \/\/ This var <span id=\"urn:enhancement-af886065-ca0d-4787-acff-18ec13a54962\" class=\"textannotation\">will<\/span> contain <span id=\"urn:enhancement-c3a8e249-0123-4626-b563-a14175a69f72\" class=\"textannotation\">WP<\/span>_Post[] or int[]\n    $wpPosts = \\get_posts($<span id=\"urn:enhancement-bee47fce-8dde-4174-bdde-ff363899684c\" class=\"textannotation\">args<\/span>);\n\n    \/\/ Rest of the code\n    \/\/ ...\n  }\n}\n<\/code><\/pre>\n<h3>Aufgeteilte Methoden<\/h3>\n<p>Die Methoden in der Schnittstelle m\u00fcssen nicht eine Kopie der Methoden aus WordPress sein. Wir k\u00f6nnen sie umwandeln, wann immer es sinnvoll ist. Die WordPress-Funktion <code>get_user_by($field, $value)<\/code> wei\u00df zum Beispiel, wie man den Benutzer aus der Datenbank \u00fcber den Parameter $field abruft, der die Werte <code>\"id\"<\/code>, <code>\"ID\"<\/code>, <code>\"slug\"<\/code>, <code>\"email\"<\/code> oder <code>\"login\"<\/code> akzeptiert. Dieses Design hat ein paar Probleme:<\/p>\n<ul>\n<li>Es wird bei der Kompilierung nicht fehlschlagen, wenn wir einen falschen String \u00fcbergeben<\/li>\n<li>Der Parameter <code>$value<\/code> muss alle verschiedenen Typen f\u00fcr alle Optionen akzeptieren, auch wenn er bei der \u00dcbergabe von <code>\"ID\"<\/code> einen <code>int<\/code> erwartet, w\u00e4hrend er bei der \u00dcbergabe von <code>\"e-mail\"<\/code> nur einen <code>string<\/code> empfangen kann.<\/li>\n<\/ul>\n<p>Wir k\u00f6nnen diese Situation verbessern, indem wir die Funktion in mehrere Funktionen aufteilen:<\/p>\n<pre><code class=\"language-php\"><span id=\"urn:enhancement-f14842d3-131e-42b2-80da-6044420ff22a\" class=\"textannotation\">namespace<\/span> Owner\\MyApp\\<span id=\"urn:enhancement-f673f832-a339-4483-9f0a-2f247a6b8c56\" class=\"textannotation\">Contracts<\/span>;\n\ninterface UserAPIInterface\n{\n  <span id=\"urn:enhancement-27cefcaa-f50f-4324-bf34-f0155e7fc719\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-b08f93fa-66b9-47b2-a3be-cc294eead339\" class=\"textannotation\">function<\/span> getUserById(int $id): ?UserInterface;\n  <span id=\"urn:enhancement-8f10ede7-39d0-41ea-ae16-f596e5a914c8\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-68cab47a-c9c5-422c-8f22-06afbdbcaf39\" class=\"textannotation\">function<\/span> getUserByEmail(string $<span id=\"urn:enhancement-77b415a9-35eb-4496-b883-05e04f2fe0ac\" class=\"textannotation\">email<\/span>): ?UserInterface;\n  <span id=\"urn:enhancement-77e1e4ef-f38f-4a3f-9416-5556796378a3\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-bb9bd26c-d78f-4f8e-9ed8-1e6bb4a4e57d\" class=\"textannotation\">function<\/span> getUserBySlug(string $slug): ?UserInterface;\n  <span id=\"urn:enhancement-fc3ae05e-9a66-4b30-b2ea-7f665a6ffab3\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-e5b01d54-cca1-4b19-9f0a-a76bcf2d0fa1\" class=\"textannotation\">function<\/span> getUserByLogin(string $<span id=\"urn:enhancement-c9357715-59c4-4cdb-92f0-966f5c482984\" class=\"textannotation\">login<\/span>): ?UserInterface;\n}\n<\/code><\/pre>\n<p>Der Vertrag wird f\u00fcr WordPress wie folgt aufgel\u00f6st (vorausgesetzt, wir haben <code>UserWrapper<\/code> und <code>UserInterface<\/code> erstellt, wie weiter oben erkl\u00e4rt):<\/p>\n<pre><code class=\"language-php\"><span id=\"urn:enhancement-ef3f5299-23f2-41fd-a301-750738fe9685\" class=\"textannotation\">namespace<\/span> Owner\\MyAppForWP\\ContractImplementations;\n\nuse Owner\\MyApp\\<span id=\"urn:enhancement-6de762b2-949f-40df-a3aa-b8cb2d176723\" class=\"textannotation\">Contracts<\/span>\\UserAPIInterface;\n\n<span id=\"urn:enhancement-10a8acd0-d313-42a1-8d0c-6dae60e889da\" class=\"textannotation\">class<\/span> UserAPI <span id=\"urn:enhancement-4646fa02-cefc-4f50-a843-6a686fb23572\" class=\"textannotation\">implements<\/span> UserAPIInterface\n{\n  <span id=\"urn:enhancement-04ac6aa2-a935-407d-8c57-51ed8cf35bee\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-5dfed395-0741-446b-8c1a-0be396c753be\" class=\"textannotation\">function<\/span> getUserById(int $id): ?UserInterface\n  {\n    <span id=\"urn:enhancement-7c4bcf6f-58d5-4962-96cf-34e857b0f262\" class=\"textannotation\">return<\/span> $this-&gt;getUserByProp('id', $id);\n  }\n\n  <span id=\"urn:enhancement-b6162c61-f0da-4e45-b1e2-33bf47c08c1d\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-fd6cf5cb-026b-464c-8022-a6a1cd72b48e\" class=\"textannotation\">function<\/span> getUserByEmail(string $<span id=\"urn:enhancement-b364659e-8c1d-4545-9a8f-9b1fbd34159c\" class=\"textannotation\">email<\/span>): ?UserInterface\n  {\n    <span id=\"urn:enhancement-a01cae5f-5998-438f-a5b9-a028e3411296\" class=\"textannotation\">return<\/span> $this-&gt;getUserByProp('<span id=\"urn:enhancement-dbf60372-e3ff-4152-9140-902e39c749ef\" class=\"textannotation\">email<\/span>', $<span id=\"urn:enhancement-949b5ee7-4137-4f13-bc7e-18e49b864690\" class=\"textannotation\">email<\/span>);\n  }\n\n  <span id=\"urn:enhancement-7f983570-e463-4c9d-8536-fb1ec2fb6dec\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-dabfb165-0cf7-4ef7-b946-2a7cd11ad5ad\" class=\"textannotation\">function<\/span> getUserBySlug(string $slug): ?UserInterface\n  {\n    <span id=\"urn:enhancement-ba973600-d194-4320-ae1c-67dc4c6458ed\" class=\"textannotation\">return<\/span> $this-&gt;getUserByProp('slug', $slug);\n  }\n\n  <span id=\"urn:enhancement-76596c7b-1b37-444d-9e33-fda3ac598ecf\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-03880878-c95b-45e6-bd2d-955b817095be\" class=\"textannotation\">function<\/span> getUserByLogin(string $<span id=\"urn:enhancement-b467af2f-5417-4c93-97a1-12f242452918\" class=\"textannotation\">login<\/span>): ?UserInterface\n  {\n    <span id=\"urn:enhancement-c48a250e-b389-4597-88a4-4418c41dcc7a\" class=\"textannotation\">return<\/span> $this-&gt;getUserByProp('<span id=\"urn:enhancement-b0bc026e-8adb-48aa-a9d2-6165ecd9cc36\" class=\"textannotation\">login<\/span>', $<span id=\"urn:enhancement-935b5314-7953-4979-b446-8cc47f469d4c\" class=\"textannotation\">login<\/span>);\n  }\n\n  private <span id=\"urn:enhancement-5f6b52b4-38d9-47c8-8433-9afd18807bdf\" class=\"textannotation\">function<\/span> getUserByProp(string $prop, int|string $<span id=\"urn:enhancement-febdb871-3c53-4652-813f-7f06283eef3b\" class=\"textannotation\">value<\/span>): ?UserInterface\n  {\n    if ($<span id=\"urn:enhancement-2e85f8c9-4b6a-45b8-af2a-5afc8cdb9c5a\" class=\"textannotation\">user<\/span> = \\get_<span id=\"urn:enhancement-f879a0bd-b00e-42f6-af8c-f165493847e0\" class=\"textannotation\">user<\/span>_by($prop, $<span id=\"urn:enhancement-3d124b42-606c-4b4b-abd3-82410a61de5a\" class=\"textannotation\">value<\/span>)) {\n      <span id=\"urn:enhancement-1c149c9c-3089-410e-9ffc-b730b64021cc\" class=\"textannotation\">return<\/span> <span id=\"urn:enhancement-cb18f69f-4453-4b2e-be9b-3539b9d4d90a\" class=\"textannotation\">new<\/span> UserWrapper($<span id=\"urn:enhancement-56df38b6-9fa9-451c-be04-5b182eb6d4c7\" class=\"textannotation\">user<\/span>);\n    }\n    <span id=\"urn:enhancement-21785882-9e54-4e5a-8e1c-cb674949f2a6\" class=\"textannotation\">return<\/span> null;\n  }\n}\n<\/code><\/pre>\n<h3>Implementierungsdetails aus der Funktionssignatur entfernen<\/h3>\n<p>Funktionen in WordPress k\u00f6nnen in ihrer eigenen Signatur Informationen dar\u00fcber bieten, wie sie implementiert sind. Diese Informationen k\u00f6nnen entfernt werden, wenn die Funktion aus einer abstrakten Perspektive bewertet wird. Zum Beispiel wird der Nachname des Benutzers in WordPress durch den Aufruf von <code>get_the_author_meta<\/code> ermittelt, wodurch klar wird, dass der Nachname eines Benutzers als &#8222;Meta&#8220;-Wert gespeichert wird (in der Tabelle <code>wp_usermeta<\/code>):<\/p>\n<pre><code class=\"language-php\">$userLastname = get_the_<span id=\"urn:enhancement-8a06e2e2-8f86-4f3c-ad79-7cbc40a85d2e\" class=\"textannotation\">author<\/span>_meta(\"<span id=\"urn:enhancement-2eb17fc8-95d8-46e8-913f-5b1183853842\" class=\"textannotation\">user<\/span>_lastname\", $<span id=\"urn:enhancement-7d934543-aec0-40e4-865c-cf92fb2f1aca\" class=\"textannotation\">user<\/span>_id);\n<\/code><\/pre>\n<p>Du musst diese Informationen nicht an den Vertrag weitergeben. Interfaces interessieren sich nur f\u00fcr das Was, nicht f\u00fcr das Wie. Daher kann der Vertrag stattdessen eine Methode <code>getUserLastname<\/code> enthalten, die keine Informationen dar\u00fcber liefert, wie sie implementiert wird:<\/p>\n<pre><code class=\"language-php\">interface UserAPIInterface\n{\n  <span id=\"urn:enhancement-f295a50b-9747-4904-8e33-41f40d273311\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-d8a368f8-8ce7-4fdb-960c-246da6fb1b37\" class=\"textannotation\">function<\/span> getUserLastname(UserWrapper $userWrapper): string;\n  ...\n}\n<\/code><\/pre>\n<h3>Strengere Typen hinzuf\u00fcgen<\/h3>\n<p>Einige WordPress-Funktionen k\u00f6nnen Parameter auf unterschiedliche Weise entgegennehmen, was zu Mehrdeutigkeit f\u00fchrt. Zum Beispiel kann die Funktion <code>add_query_arg<\/code> entweder einen einzelnen Schl\u00fcssel und einen Wert erhalten:<\/p>\n<pre><code class=\"language-php\">$url = add_query_arg('id', 5, $url);\n<\/code><\/pre>\n<p>&#8230; oder ein Array aus\u00a0 <code>key =&gt; <span id=\"urn:enhancement-f670f89f-32d4-4edf-8da4-b200c91b4c9e\" class=\"textannotation\">value<\/span><\/code>:<\/p>\n<pre><code class=\"language-php\">$url = add_query_arg(['id' =&gt; 5], $url);\n<\/code><\/pre>\n<p>Unsere Schnittstelle kann eine verst\u00e4ndlichere Absicht definieren, indem sie solche Funktionen in mehrere separate Funktionen aufteilt, von denen jede eine einzigartige Kombination von Eingaben akzeptiert:<\/p>\n<pre><code class=\"language-php\"><span id=\"urn:enhancement-587d35e3-fb1a-4bf6-9b7d-cca2420bf6ad\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-b2015f63-677c-4e46-8dfd-9c60b0febd1b\" class=\"textannotation\">function<\/span> addQueryArg(string $key, string $<span id=\"urn:enhancement-b367fa97-3d1c-44f4-8f0b-4f5c966a82d0\" class=\"textannotation\">value<\/span>, string $url);\n<span id=\"urn:enhancement-08b75a60-0d11-4cd4-b161-93d518a3e54c\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-6336d40d-a79d-481c-aeab-9386ffe04554\" class=\"textannotation\">function<\/span> addQueryArgs(array $keyValues, string $url);\n<\/code><\/pre>\n<h3>Technische Schuld beseitigen<\/h3>\n<p>Die WordPress-Funktion <code>get_posts<\/code> gibt nicht nur &#8222;posts&#8220;, sondern auch &#8222;pages&#8220; oder jede Entit\u00e4t vom Typ &#8222;custom posts&#8220; zur\u00fcck, und diese Entit\u00e4ten sind nicht austauschbar. Sowohl Beitr\u00e4ge als auch Seiten sind benutzerdefinierte Beitr\u00e4ge, aber eine Seite ist weder ein Beitrag noch eine Seite. Daher kann die Ausf\u00fchrung von <code>get_posts<\/code> Seiten zur\u00fcckgeben. Dieses Verhalten ist eine konzeptionelle Diskrepanz.<\/p>\n<p>Um es richtig zu machen, sollte <code>get_posts<\/code> stattdessen <code>get_customposts<\/code> hei\u00dfen, aber es wurde im WordPress-Kern nie umbenannt. Das ist ein h\u00e4ufiges Problem bei langlebiger Software und wird als &#8222;technische Schuld&#8220; bezeichnet &#8211; Code, der Probleme hat, aber nie behoben wird, weil er brechende \u00c4nderungen mit sich bringt.<\/p>\n<p>Wenn wir unsere Vertr\u00e4ge erstellen, haben wir jedoch die M\u00f6glichkeit, diese Art von technischer Schuld zu vermeiden. In diesem Fall k\u00f6nnen wir eine neue Schnittstelle <code>ModelAPIInterface<\/code> erstellen, die mit Entit\u00e4ten verschiedener Typen umgehen kann, und wir erstellen mehrere Methoden, die jeweils einen anderen Typ behandeln:<\/p>\n<pre><code class=\"language-php\">interface ModelAPIInterface\n{\n  <span id=\"urn:enhancement-c68aa5f6-7746-4465-b616-580966c70989\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-b13997c6-fd43-4c6b-afc8-c3d87c86b6f0\" class=\"textannotation\">function<\/span> getPosts(array $<span id=\"urn:enhancement-6e1034a0-5df4-464d-9914-73bceb5e74ba\" class=\"textannotation\">args<\/span>): array;\n  <span id=\"urn:enhancement-15c43048-ea1a-49de-a266-bd1b75421924\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-bc589f2e-8a6c-432c-b77f-9a97c73be30e\" class=\"textannotation\">function<\/span> getPages(array $<span id=\"urn:enhancement-f9522007-5c8a-4b05-bc01-c3e5f5ab4ac8\" class=\"textannotation\">args<\/span>): array;\n  <span id=\"urn:enhancement-54ba6784-d2d5-4db9-b97e-5399d468fa7b\" class=\"textannotation\">public<\/span> <span id=\"urn:enhancement-f49a5bd4-f545-43ed-9165-afc8bd1986b8\" class=\"textannotation\">function<\/span> getCustomPosts(array $<span id=\"urn:enhancement-74f2248e-8901-478a-9867-4d9db4b8d427\" class=\"textannotation\">args<\/span>): array;\n}\n<\/code><\/pre>\n<p>Auf diese Weise wird die Diskrepanz nicht mehr auftreten und du wirst diese Ergebnisse sehen:<\/p>\n<ul>\n<li><code>getPosts<\/code> gibt nur Beitr\u00e4ge zur\u00fcck<\/li>\n<li><code>getPages<\/code> gibt nur Seiten zur\u00fcck<\/li>\n<li><code>getCustomPosts<\/code> gibt sowohl Beitr\u00e4ge als auch Seiten zur\u00fcck<\/li>\n<\/ul>\n<h2>Vorteile des Abstrahierens von Code<\/h2>\n<p>Die wichtigsten Vorteile der Abstraktion des Anwendungscodes sind:<\/p>\n<ul>\n<li>Tools, die auf Paketen laufen, die nur Business-Code enthalten, sind einfacher einzurichten und ben\u00f6tigen weniger Zeit (und Geld).<\/li>\n<li>Wir k\u00f6nnen Tools verwenden, die nicht mit WordPress funktionieren, z. B. das Scoping eines Plugins mit PHP-Scoper.<\/li>\n<li>Die von uns erstellten Pakete k\u00f6nnen problemlos in anderen Anwendungen eingesetzt werden.<\/li>\n<li>Die Migration einer Anwendung auf andere Plattformen wird einfacher.<\/li>\n<li>Wir k\u00f6nnen unsere Denkweise von WordPress auf unsere Gesch\u00e4ftslogik umstellen.<\/li>\n<li>Die Vertr\u00e4ge beschreiben den Zweck der Anwendung und machen sie verst\u00e4ndlicher.<\/li>\n<li>Die Anwendung wird in Pakete gegliedert, so dass eine schlanke Anwendung entsteht, die nur das N\u00f6tigste enth\u00e4lt und je nach Bedarf schrittweise erweitert wird.<\/li>\n<li>Wir k\u00f6nnen technische Schulden abbauen.<\/li>\n<\/ul>\n<h2>Probleme beim Abstrahieren von Code<\/h2>\n<p>Die Nachteile der Abstraktion des Codes einer Anwendung sind:<\/p>\n<ul>\n<li>Anfangs ist es mit einem erheblichen Arbeitsaufwand verbunden.<\/li>\n<li>Der Code wird umfangreicher; du musst zus\u00e4tzliche Schichten von Code hinzuf\u00fcgen, um das gleiche Ergebnis zu erzielen.<\/li>\n<li>Am Ende kannst du <a href=\"https:\/\/graphql-api.com\/blog\/why-to-support-cms-agnosticism-the-graphql-api-split-to-around-90-packages\/\">Dutzende von Paketen<\/a> erstellen, die dann verwaltet und gepflegt werden m\u00fcssen.<\/li>\n<li>M\u00f6glicherweise ben\u00f6tigst du eine Monorepo, um alle Pakete gemeinsam zu verwalten.<\/li>\n<li>Dependency Injection k\u00f6nnte f\u00fcr einfache Anwendungen ein Overkill sein (abnehmender Nutzen).<\/li>\n<li>Die Abstrahierung des Codes wird nie vollst\u00e4ndig abgeschlossen sein, da die Architektur des CMS in der Regel eine allgemeine Pr\u00e4ferenz impliziert.<\/li>\n<\/ul>\n<h2>WordPress abstrahieren Plugin-Optionen<\/h2>\n<p>Obwohl es in der Regel am kl\u00fcgsten ist, deinen Code in eine <a href=\"https:\/\/kinsta.com\/de\/blog\/wordpress-lokal-installieren\/\">lokale Umgebung<\/a> zu extrahieren, bevor du daran arbeitest, k\u00f6nnen dir einige WordPress-Plugins helfen, deine Abstraktionsziele zu erreichen. Dies sind unsere Top-Tipps.<\/p>\n<h3>1. WPide<\/h3>\n<p>Das beliebte <a href=\"https:\/\/wordpress.org\/plugins\/wpide\/\">Plugin WPide<\/a> von WebFactory Ltd. erweitert die Funktionen des standardm\u00e4\u00dfigen Code Editors von WordPress erheblich. Es dient als abstraktes WordPress-Plugin, indem es dir erm\u00f6glicht, deinen Code an Ort und Stelle zu betrachten, um besser zu erkennen, worauf du achten musst.<\/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=\"Das WPide Plugin\" width=\"900\" height=\"291\"><figcaption class=\"wp-caption-text\">Das WPide Plugin<\/figcaption><\/figure><\/figure>\n<p>WPide verf\u00fcgt au\u00dferdem \u00fcber eine Such- und Ersetzungsfunktion, mit der du veralteten oder abgelaufenen Code schnell aufsp\u00fcren und durch eine \u00fcberarbeitete Version ersetzen kannst.<\/p>\n<p>Dar\u00fcber hinaus bietet WPide eine Menge zus\u00e4tzlicher Funktionen, darunter:<\/p>\n<ul>\n<li>Syntax- und Blockhervorhebung<\/li>\n<li><a href=\"https:\/\/kinsta.com\/de\/docs\/wordpress-hosting\/wordpress-backups\/#wordpress-backup\">Automatische Backups<\/a><\/li>\n<li>Erstellung von Dateien und Ordnern<\/li>\n<li>Umfassender Dateibaum-Browser<\/li>\n<li>Zugriff auf die WordPress-Dateisystem-API<\/li>\n<\/ul>\n<h3>2. Ultimate DB Manager<\/h3>\n<p>Das <a href=\"https:\/\/wordpress.org\/plugins\/ultimate-db-manager-lite\/\">Plugin Ultimate WP DB Manager<\/a> von WPHobby bietet dir eine schnelle M\u00f6glichkeit, deine Datenbanken vollst\u00e4ndig herunterzuladen, um sie zu extrahieren und zu \u00fcberarbeiten.<\/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=\"Das ultimative DB Manager Plugin\" width=\"900\" height=\"250\"><figcaption class=\"wp-caption-text\">Das ultimative DB Manager Plugin<\/figcaption><\/figure><\/figure>\n<p>Nat\u00fcrlich sind Plugins dieser Art f\u00fcr Kinsta-Nutzer nicht notwendig, da Kinsta allen Kunden <a href=\"https:\/\/kinsta.com\/de\/docs\/wordpress-hosting\/datenbank-verwaltung\/wordpress-datenbank-zugriff\/\">direkten Datenbankzugang bietet<\/a>. Wenn du jedoch keinen ausreichenden Datenbankzugriff \u00fcber deinen Hosting-Provider hast, kann Ultimate DB Manager als WordPress-Plugin zum abstrahieren sehr n\u00fctzlich sein.<\/p>\n<h3>3. Dein eigenes WordPress-Plugin zum abstrahieren<\/h3>\n<p>Am Ende ist es immer die beste Wahl, ein eigenes Plugin zu erstellen. Das mag wie ein gro\u00dfes Unterfangen erscheinen, aber wenn du nur begrenzte M\u00f6glichkeiten hast, deine WordPress-Kerndateien direkt zu verwalten, ist das eine abstraktionsfreundliche L\u00f6sung.<\/p>\n<p>Diese Vorgehensweise hat klare Vorteile:<\/p>\n<ul>\n<li>Abstrahiert deine Funktionen von deinen Theme-Dateien<\/li>\n<li>Dein Code bleibt bei Theme-\u00c4nderungen und Datenbank-Updates erhalten<\/li>\n<\/ul>\n<p>Wie du dein abstraktes WordPress-Plugin erstellst, erf\u00e4hrst du im <a href=\"https:\/\/developer.wordpress.org\/plugins\/\">Plugin-Entwicklerhandbuch von WordPress<\/a>.<\/p>\n\n<h2>Zusammenfassung<\/h2>\n<p>Sollten wir den Code in unseren Anwendungen abstrahieren? Wie bei allem gibt es auch hier keine vordefinierte &#8222;richtige Antwort&#8220;, da es von Projekt zu Projekt abh\u00e4ngt. Diejenigen Projekte, die einen enormen Zeitaufwand f\u00fcr die Analyse mit PHPUnit oder PHPStan erfordern, k\u00f6nnen am meisten davon profitieren, aber der Aufwand, der daf\u00fcr betrieben werden muss, ist es nicht immer wert.<\/p>\n<p>Du hast alles gelernt, was du wissen musst, um mit der Abstraktion von WordPress-Code zu beginnen.<\/p>\n<p><em>Hast du vor, diese Strategie in deinem Projekt umzusetzen? Wenn ja, wirst du ein WordPress-Plugin verwenden? Lass es uns in den Kommentaren wissen!<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>WordPress ist ein altes CMS, aber auch das meistgenutzte. Da es in der Vergangenheit veraltete PHP-Versionen und Legacy-Code unterst\u00fctzt hat, mangelt es immer noch an der &#8230;<\/p>\n","protected":false},"author":196,"featured_media":43466,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kinsta_gated_content":false,"_kinsta_gated_content_redirect":"","footnotes":""},"tags":[361,276],"topic":[999,1006],"class_list":["post-43462","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-code","tag-web-development","topic-wordpress-entwicklung","topic-wordpress-plugins"],"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>WordPress-Abstraktion: Bew\u00e4hrte Praktiken und Plugins<\/title>\n<meta name=\"description\" content=\"Lerne, wie du mit Code-Snippets oder einem abstrakten WordPress-Plugin feste Abh\u00e4ngigkeiten aus dem Code entfernen und interagierende Pakete erstellen kannst.\" \/>\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\/de\/blog\/wordpress-abstraktions-plugins\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"WordPress-Abstraktion: Bew\u00e4hrte Praktiken und WordPress-Abstraktions-Plugins\" \/>\n<meta property=\"og:description\" content=\"Lerne, wie du mit Code-Snippets oder einem abstrakten WordPress-Plugin feste Abh\u00e4ngigkeiten aus dem Code entfernen und interagierende Pakete erstellen kannst.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/\" \/>\n<meta property=\"og:site_name\" content=\"Kinsta\u00ae\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Kinsta-Deutschland-207459890108303\/\" \/>\n<meta property=\"article:published_time\" content=\"2021-09-12T12:53:32+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-10-03T14:23:55+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.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=\"Lerne, wie du mit Code-Snippets oder einem abstrakten WordPress-Plugin feste Abh\u00e4ngigkeiten aus dem Code entfernen und interagierende Pakete erstellen kannst.\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.jpeg\" \/>\n<meta name=\"twitter:creator\" content=\"@losoviz\" \/>\n<meta name=\"twitter:site\" content=\"@Kinsta_DE\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Leonardo Losoviz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"16\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/\"},\"author\":{\"name\":\"Leonardo Losoviz\",\"@id\":\"https:\/\/kinsta.com\/de\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238\"},\"headline\":\"WordPress-Abstraktion: Bew\u00e4hrte Praktiken und WordPress-Abstraktions-Plugins\",\"datePublished\":\"2021-09-12T12:53:32+00:00\",\"dateModified\":\"2023-10-03T14:23:55+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/\"},\"wordCount\":2970,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/de\/#organization\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.jpeg\",\"keywords\":[\"code\",\"web development\"],\"articleSection\":[\"Die besten WordPress Tutorials\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/\",\"url\":\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/\",\"name\":\"WordPress-Abstraktion: Bew\u00e4hrte Praktiken und Plugins\",\"isPartOf\":{\"@id\":\"https:\/\/kinsta.com\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.jpeg\",\"datePublished\":\"2021-09-12T12:53:32+00:00\",\"dateModified\":\"2023-10-03T14:23:55+00:00\",\"description\":\"Lerne, wie du mit Code-Snippets oder einem abstrakten WordPress-Plugin feste Abh\u00e4ngigkeiten aus dem Code entfernen und interagierende Pakete erstellen kannst.\",\"breadcrumb\":{\"@id\":\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#primaryimage\",\"url\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.jpeg\",\"width\":1460,\"height\":730},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/kinsta.com\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"WordPress-Plugins\",\"item\":\"https:\/\/kinsta.com\/de\/thema\/wordpress-plugins\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"WordPress-Abstraktion: Bew\u00e4hrte Praktiken und WordPress-Abstraktions-Plugins\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/kinsta.com\/de\/#website\",\"url\":\"https:\/\/kinsta.com\/de\/\",\"name\":\"Kinsta\u00ae\",\"description\":\"Schnelle, sichere und hochwertige Hosting-L\u00f6sungen\",\"publisher\":{\"@id\":\"https:\/\/kinsta.com\/de\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/kinsta.com\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/kinsta.com\/de\/#organization\",\"name\":\"Kinsta\",\"url\":\"https:\/\/kinsta.com\/de\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/kinsta.com\/de\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/12\/kinsta-logo.jpeg\",\"contentUrl\":\"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/12\/kinsta-logo.jpeg\",\"width\":500,\"height\":500,\"caption\":\"Kinsta\"},\"image\":{\"@id\":\"https:\/\/kinsta.com\/de\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/Kinsta-Deutschland-207459890108303\/\",\"https:\/\/x.com\/Kinsta_DE\",\"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\/de\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238\",\"name\":\"Leonardo Losoviz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/kinsta.com\/de\/#\/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\/de\/blog\/author\/leonardolosoviz\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"WordPress-Abstraktion: Bew\u00e4hrte Praktiken und Plugins","description":"Lerne, wie du mit Code-Snippets oder einem abstrakten WordPress-Plugin feste Abh\u00e4ngigkeiten aus dem Code entfernen und interagierende Pakete erstellen kannst.","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\/de\/blog\/wordpress-abstraktions-plugins\/","og_locale":"de_DE","og_type":"article","og_title":"WordPress-Abstraktion: Bew\u00e4hrte Praktiken und WordPress-Abstraktions-Plugins","og_description":"Lerne, wie du mit Code-Snippets oder einem abstrakten WordPress-Plugin feste Abh\u00e4ngigkeiten aus dem Code entfernen und interagierende Pakete erstellen kannst.","og_url":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/","og_site_name":"Kinsta\u00ae","article_publisher":"https:\/\/www.facebook.com\/Kinsta-Deutschland-207459890108303\/","article_published_time":"2021-09-12T12:53:32+00:00","article_modified_time":"2023-10-03T14:23:55+00:00","og_image":[{"width":1460,"height":730,"url":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.jpeg","type":"image\/jpeg"}],"author":"Leonardo Losoviz","twitter_card":"summary_large_image","twitter_description":"Lerne, wie du mit Code-Snippets oder einem abstrakten WordPress-Plugin feste Abh\u00e4ngigkeiten aus dem Code entfernen und interagierende Pakete erstellen kannst.","twitter_image":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.jpeg","twitter_creator":"@losoviz","twitter_site":"@Kinsta_DE","twitter_misc":{"Verfasst von":"Leonardo Losoviz","Gesch\u00e4tzte Lesezeit":"16\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#article","isPartOf":{"@id":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/"},"author":{"name":"Leonardo Losoviz","@id":"https:\/\/kinsta.com\/de\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238"},"headline":"WordPress-Abstraktion: Bew\u00e4hrte Praktiken und WordPress-Abstraktions-Plugins","datePublished":"2021-09-12T12:53:32+00:00","dateModified":"2023-10-03T14:23:55+00:00","mainEntityOfPage":{"@id":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/"},"wordCount":2970,"commentCount":0,"publisher":{"@id":"https:\/\/kinsta.com\/de\/#organization"},"image":{"@id":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.jpeg","keywords":["code","web development"],"articleSection":["Die besten WordPress Tutorials"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/","url":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/","name":"WordPress-Abstraktion: Bew\u00e4hrte Praktiken und Plugins","isPartOf":{"@id":"https:\/\/kinsta.com\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#primaryimage"},"image":{"@id":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#primaryimage"},"thumbnailUrl":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.jpeg","datePublished":"2021-09-12T12:53:32+00:00","dateModified":"2023-10-03T14:23:55+00:00","description":"Lerne, wie du mit Code-Snippets oder einem abstrakten WordPress-Plugin feste Abh\u00e4ngigkeiten aus dem Code entfernen und interagierende Pakete erstellen kannst.","breadcrumb":{"@id":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#primaryimage","url":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.jpeg","contentUrl":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2021\/09\/wordpress-abstraktions-plugins.jpeg","width":1460,"height":730},{"@type":"BreadcrumbList","@id":"https:\/\/kinsta.com\/de\/blog\/wordpress-abstraktions-plugins\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kinsta.com\/de\/"},{"@type":"ListItem","position":2,"name":"WordPress-Plugins","item":"https:\/\/kinsta.com\/de\/thema\/wordpress-plugins\/"},{"@type":"ListItem","position":3,"name":"WordPress-Abstraktion: Bew\u00e4hrte Praktiken und WordPress-Abstraktions-Plugins"}]},{"@type":"WebSite","@id":"https:\/\/kinsta.com\/de\/#website","url":"https:\/\/kinsta.com\/de\/","name":"Kinsta\u00ae","description":"Schnelle, sichere und hochwertige Hosting-L\u00f6sungen","publisher":{"@id":"https:\/\/kinsta.com\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kinsta.com\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/kinsta.com\/de\/#organization","name":"Kinsta","url":"https:\/\/kinsta.com\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/kinsta.com\/de\/#\/schema\/logo\/image\/","url":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/12\/kinsta-logo.jpeg","contentUrl":"https:\/\/kinsta.com\/de\/wp-content\/uploads\/sites\/5\/2023\/12\/kinsta-logo.jpeg","width":500,"height":500,"caption":"Kinsta"},"image":{"@id":"https:\/\/kinsta.com\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Kinsta-Deutschland-207459890108303\/","https:\/\/x.com\/Kinsta_DE","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\/de\/#\/schema\/person\/c382de1885cc21b079ec1e71d7faf238","name":"Leonardo Losoviz","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/kinsta.com\/de\/#\/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\/de\/blog\/author\/leonardolosoviz\/"}]}},"acf":[],"_links":{"self":[{"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/posts\/43462","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/users\/196"}],"replies":[{"embeddable":true,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/comments?post=43462"}],"version-history":[{"count":12,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/posts\/43462\/revisions"}],"predecessor-version":[{"id":43510,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/posts\/43462\/revisions\/43510"}],"alternate":[{"embeddable":true,"hreflang":"en","title":"English","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/43462\/translations\/en"},{"embeddable":true,"hreflang":"it","title":"Italian","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/43462\/translations\/it"},{"embeddable":true,"hreflang":"fr","title":"French","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/43462\/translations\/fr"},{"embeddable":true,"hreflang":"es","title":"Spanish","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/43462\/translations\/es"},{"embeddable":true,"hreflang":"pt","title":"Portuguese","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/43462\/translations\/pt"},{"embeddable":true,"hreflang":"de","title":"German","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/43462\/translations\/de"},{"embeddable":true,"hreflang":"nl","title":"Dutch","href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/43462\/translations\/nl"},{"href":"https:\/\/kinsta.com\/de\/wp-json\/kinsta\/v1\/posts\/43462\/tree"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/media\/43466"}],"wp:attachment":[{"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/media?parent=43462"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/tags?post=43462"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/kinsta.com\/de\/wp-json\/wp\/v2\/topic?post=43462"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}