Headless WordPress: Die Höhen und Tiefen beim Erstellen eines entkoppelten WordPress
Veröffentlicht: 2022-03-10WordPress hat von seinen Anfängen als einfaches Tool zum Schreiben von Blogs einen langen Weg zurückgelegt. Lange 15 Jahre später wurde es zur CMS-Wahl Nummer eins für Entwickler und Nicht-Entwickler gleichermaßen. WordPress betreibt jetzt etwa 30 % der Top-10-Millionen-Websites im Web.
Seit die REST-API im WordPress-Kern gebündelt wurde, können Entwickler experimentieren und sie auf entkoppelte Weise verwenden, dh den Frontend-Teil mithilfe von JavaScript-Frameworks oder -Bibliotheken schreiben. Bei Infinum nutzten (und tun) wir WordPress „klassisch“: PHP sowohl für das Frontend als auch für das Backend. Nach einer Weile wollten wir den entkoppelten Ansatz ausprobieren. In diesem Artikel gebe ich einen Überblick darüber, was wir erreichen wollten und was uns bei der Umsetzung unserer Ziele begegnet ist.
Es gibt mehrere Arten von Projekten, die von diesem Ansatz profitieren können. Beispielsweise sind einfache Präsentationsseiten oder Seiten, die WordPress als Backend verwenden, die Hauptkandidaten für den entkoppelten Ansatz.
In den letzten Jahren hat die Branche glücklicherweise begonnen, der Leistung mehr Aufmerksamkeit zu schenken. Als benutzerfreundliche, umfassende und vielseitige Software bietet WordPress jedoch eine Fülle von Optionen, die nicht unbedingt in jedem einzelnen Projekt verwendet werden. Infolgedessen kann die Leistung der Website leiden.
Empfohlene Lektüre : So verwenden Sie Heatmaps, um Klicks auf Ihrer WordPress-Website zu verfolgen
Wenn lange Antwortzeiten von Websites Sie nachts wach halten, ist dies eine Anleitung für Sie. Ich werde die Grundlagen der Erstellung eines entkoppelten WordPress und einige gelernte Lektionen behandeln, darunter:
- Die Bedeutung eines „entkoppelten WordPress“
- Arbeiten mit der standardmäßigen WordPress-REST-API
- Verbesserung der Leistung mit dem entkoppelten JSON-Ansatz
- Sicherheitsbedenken
Also, was genau ist ein entkoppeltes WordPress?
Wenn es um die Programmierung von WordPress geht, steht fest: Es folgt nicht dem Model-View- Controller ( MVC ) -Entwurfsmuster , das viele Entwickler kennen. Aufgrund seiner Geschichte und weil es eine Art Fork einer alten Blogging-Plattform namens „b2“ ist (mehr Details hier), ist es weitgehend prozedural geschrieben (unter Verwendung von funktionsbasiertem Code). WordPress-Core-Entwickler verwendeten ein System von Hooks, das es anderen Entwicklern ermöglichte, bestimmte Funktionalitäten zu ändern oder zu erweitern.
Es ist ein All-in-One-System, das mit einer funktionierenden Admin-Oberfläche ausgestattet ist; Es verwaltet die Datenbankverbindung und stellt eine Reihe nützlicher APIs zur Verfügung, die Benutzerauthentifizierung, Routing und mehr handhaben.
Aber dank der REST-API können Sie das WordPress-Backend als eine Art Modell und gebündelten Controller trennen, der die Datenmanipulation und Datenbankinteraktion handhabt, und den REST-API-Controller verwenden, um mit einer separaten Ansichtsebene über verschiedene API-Endpunkte zu interagieren. Zusätzlich zur MVC-Trennung können wir (aus Sicherheitsgründen oder Geschwindigkeitsverbesserungen) die JS-App auf einem separaten Server wie im folgenden Schema platzieren:

Vorteile der Verwendung des entkoppelten Ansatzes
Ein Grund, warum Sie diesen Ansatz möglicherweise verwenden möchten, ist die Gewährleistung einer Trennung von Bedenken. Das Frontend und das Backend interagieren über Endpunkte; Jeder kann sich auf einem separaten Server befinden, der speziell für die jeweilige Aufgabe optimiert werden kann, dh eine PHP-App und eine Node.js-App separat ausführen.
Indem Sie Ihr Frontend vom Backend trennen, ist es einfacher, es in Zukunft neu zu gestalten, ohne das CMS zu ändern. Außerdem müssen sich Frontend-Entwickler nur darum kümmern, was sie mit den Daten tun, die ihnen das Backend zur Verfügung stellt. Auf diese Weise können sie kreativ werden und moderne Bibliotheken wie ReactJS, Vue oder Angular verwenden, um hochdynamische Webanwendungen bereitzustellen. Beispielsweise ist es einfacher, eine progressive Web-App zu erstellen, wenn Sie die oben genannten Bibliotheken verwenden.
Ein weiterer Vorteil zeigt sich in der Sicherheit der Website. Die Nutzung der Website über das Backend wird schwieriger, da sie weitgehend vor der Öffentlichkeit verborgen ist.
Empfohlene Lektüre : WordPress-Sicherheit als Prozess
Mängel bei der Verwendung des entkoppelten Ansatzes
Erstens bedeutet ein entkoppeltes WordPress, zwei separate Instanzen zu unterhalten:
- WordPress für das Backend;
- Eine separate Frontend-App, einschließlich zeitnaher Sicherheitsupdates.
Zweitens haben einige der Front-End-Bibliotheken eine steilere Lernkurve. Es wird entweder viel Zeit in Anspruch nehmen, eine neue Sprache zu lernen (wenn Sie nur an HTML und CSS für die Vorlagenerstellung gewöhnt sind), oder Sie müssen zusätzliche JavaScript-Experten in das Projekt einbeziehen.
Drittens verlieren Sie durch die Trennung des Frontends die Leistungsfähigkeit des WYSIWYG-Editors, und die Schaltfläche „Live-Vorschau“ in WordPress funktioniert auch nicht.
Arbeiten mit der WordPress-REST-API
Bevor wir tiefer in den Code eintauchen, noch ein paar Dinge über die WordPress REST API. Die volle Leistungsfähigkeit der REST-API in WordPress kam mit Version 4.7 am 6. Dezember 2016.
Mit der WordPress REST API können Sie remote mit Ihrer WordPress-Installation interagieren, indem Sie JSON-Objekte senden und empfangen.
Einrichten eines Projekts
Da es zusammen mit der neuesten WordPress-Installation geliefert wird, werden wir am Twenty Seventeen-Thema arbeiten. Ich arbeite an Varying Vagrant Vagrants und habe eine Testseite mit einer URL https://dev.wordpress.test/
. Diese URL wird im gesamten Artikel verwendet. Wir werden auch Beiträge aus dem WordPress.org Theme Review Teams-Repository importieren, damit wir einige Testdaten haben, mit denen wir arbeiten können. Aber zuerst machen wir uns mit der Arbeit mit Standardendpunkten vertraut, und dann erstellen wir unseren eigenen benutzerdefinierten Endpunkt.
Greifen Sie auf den Standard-REST-Endpunkt zu
Wie bereits erwähnt, verfügt WordPress über mehrere integrierte Endpunkte, die Sie untersuchen können, indem Sie zur /wp-json/
gehen:
https://dev.wordpress.test/wp-json/
Entweder indem Sie diese URL direkt in Ihren Browser eingeben oder in der Postboten-App hinzufügen, erhalten Sie eine JSON-Antwort von der WordPress-REST-API, die etwa so aussieht:
{ "name": "Test dev site", "description": "Just another WordPress site", "url": "https://dev.wordpress.test", "home": "https://dev.wordpress.test", "gmt_offset": "0", "timezone_string": "", "namespaces": [ "oembed/1.0", "wp/v2" ], "authentication": [], "routes": { "/": { "namespace": "", "methods": [ "GET" ], "endpoints": [ { "methods": [ "GET" ], "args": { "context": { "required": false, "default": "view" } } } ], "_links": { "self": "https://dev.wordpress.test/wp-json/" } }, "/oembed/1.0": { "namespace": "oembed/1.0", "methods": [ "GET" ], "endpoints": [ { "methods": [ "GET" ], "args": { "namespace": { "required": false, "default": "oembed/1.0" }, "context": { "required": false, "default": "view" } } } ], "_links": { "self": "https://dev.wordpress.test/wp-json/oembed/1.0" } }, ... "wp/v2": { ...
Um also alle Beiträge auf unserer Website mithilfe von REST zu erhalten, müssten wir zu https://dev.wordpress.test/wp-json/wp/v2/posts
gehen. Beachten Sie, dass wp/v2/
die reservierten Kernendpunkte wie Posts, Seiten, Medien, Taxonomien, Kategorien usw. markiert.
Wie fügen wir also einen benutzerdefinierten Endpunkt hinzu?
Erstellen Sie einen benutzerdefinierten REST-Endpunkt
Angenommen, wir möchten einen neuen Endpunkt oder ein zusätzliches Feld zum vorhandenen Endpunkt hinzufügen. Es gibt mehrere Möglichkeiten, wie wir das tun können. Erstens kann dies automatisch beim Erstellen eines benutzerdefinierten Beitragstyps erfolgen. Beispielsweise möchten wir einen Dokumentationsendpunkt erstellen. Lassen Sie uns ein kleines Test-Plugin erstellen. Erstellen Sie einen Testdokumentationsordner im Ordner wp-content/plugins und fügen Sie die Datei documentation.php hinzu, die so aussieht:
<?php /** * Test plugin * * @since 1.0.0 * @package test_plugin * * @wordpress-plugin * Plugin Name: Test Documentation Plugin * Plugin URI: * Description: The test plugin that adds rest functionality * Version: 1.0.0 * Author: Infinum <[email protected]> * Author URI: https://infinum.co/ * License: GPL-2.0+ * License URI: https://www.gnu.org/licenses/gpl-2.0.txt * Text Domain: test-plugin */ namespace Test_Plugin; // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } /** * Class that holds all the necessary functionality for the * documentation custom post type * * @since 1.0.0 */ class Documentation { /** * The custom post type slug * * @var string * * @since 1.0.0 */ const PLUGIN_NAME = 'documentation-plugin'; /** * The custom post type slug * * @var string * * @since 1.0.0 */ const POST_TYPE_SLUG = 'documentation'; /** * The custom taxonomy type slug * * @var string * * @since 1.0.0 */ const TAXONOMY_SLUG = 'documentation-category'; /** * Register custom post type * * @since 1.0.0 */ public function register_post_type() { $args = array( 'label' => esc_html( 'Documentation', 'test-plugin' ), 'public' => true, 'menu_position' => 47, 'menu_icon' => 'dashicons-book', 'supports' => array( 'title', 'editor', 'revisions', 'thumbnail' ), 'has_archive' => false, 'show_in_rest' => true, 'publicly_queryable' => false, ); register_post_type( self::POST_TYPE_SLUG, $args ); } /** * Register custom tag taxonomy * * @since 1.0.0 */ public function register_taxonomy() { $args = array( 'hierarchical' => false, 'label' => esc_html( 'Documentation tags', 'test-plugin' ), 'show_ui' => true, 'show_admin_column' => true, 'update_count_callback' => '_update_post_term_count', 'show_in_rest' => true, 'query_var' => true, ); register_taxonomy( self::TAXONOMY_SLUG, [ self::POST_TYPE_SLUG ], $args ); } } $documentation = new Documentation(); add_action( 'init', [ $documentation, 'register_post_type' ] ); add_action( 'init', [ $documentation, 'register_taxonomy' ] );
Durch Registrieren des neuen Beitragstyps und der neuen Taxonomie und Setzen des Arguments show_in_rest
auf true
hat WordPress automatisch eine REST-Route im Namespace /wp/v2/
erstellt. Sie haben jetzt https://dev.wordpress.test/wp-json/wp/v2/documentation
und https://dev.wordpress.test/wp-json/wp/v2/documentation-category
Endpunkte zur Verfügung. Wenn wir einen Beitrag in unserem neu erstellten benutzerdefinierten Dokumentationsbeitrag hinzufügen, der zu https://dev.wordpress.test/?post_type=documentation
geht, erhalten wir eine Antwort, die wie folgt aussieht:
[ { "id": 4, "date": "2018-06-11T19:48:51", "date_gmt": "2018-06-11T19:48:51", "guid": { "rendered": "https://dev.wordpress.test/?post_type=documentation&p=4" }, "modified": "2018-06-11T19:48:51", "modified_gmt": "2018-06-11T19:48:51", "slug": "test-documentation", "status": "publish", "type": "documentation", "link": "https://dev.wordpress.test/documentation/test-documentation/", "title": { "rendered": "Test documentation" }, "content": { "rendered": "
Dies ist etwas Dokumentationsinhalt
\n", "geschützt": falsch }, "featured_media": 0, "Vorlage": "", "Dokumentationskategorie": [ 2 ], "_links": { "selbst": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4" } ], "Sammlung": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation" } ], "Über": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/types/documentation" } ], "Versionsgeschichte": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4/revisions" } ], "wp:attachment": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/media?parent=4" } ], "wp:term": [ { "Taxonomie": "Dokumentationskategorie", "einbettbar": wahr, "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation-category?post=4" } ], "Curies": [ { "name": "wp", "href": "https://api.w.org/{rel}", "Vorlage": wahr } ] } } ]
Dies ist ein guter Ausgangspunkt für unsere Single-Page-Anwendung. Eine andere Möglichkeit, einen benutzerdefinierten Endpunkt hinzuzufügen, besteht darin, sich in den rest_api_init
Hook einzuklinken und selbst einen Endpunkt zu erstellen. Lassen Sie uns einen custom-documentation
hinzufügen, der sich etwas von dem unterscheidet, den wir registriert haben. Wir arbeiten immer noch im selben Plugin und können hinzufügen:
/** * Create a custom endpoint * * @since 1.0.0 */ public function create_custom_documentation_endpoint() { register_rest_route( self::PLUGIN_NAME . '/v1', '/custom-documentation', array( 'methods' => 'GET', 'callback' => [ $this, 'get_custom_documentation' ], ) ); } /** * Create a callback for the custom documentation endpoint * * @return string JSON that indicates success/failure of the update, * or JSON that indicates an error occurred. * @since 1.0.0 */ public function get_custom_documentation() { /* Some permission checks can be added here. */ // Return only documentation name and tag name. $doc_args = array( 'post_type' => self::POST_TYPE_SLUG, 'post_status' => 'publish', 'perm' => 'readable' ); $query = new \WP_Query( $doc_args ); $response = []; $counter = 0; // The Loop if ( $query->have_posts() ) { while ( $query->have_posts() ) { $query->the_post(); $post_id = get_the_ID(); $post_tags = get_the_terms( $post_id, self::TAXONOMY_SLUG ); $response[ $counter ]['title'] = get_the_title(); foreach ( $post_tags as $tags_key => $tags_value ) { $response[ $counter ]['tags'][] = $tags_value->name; } $counter++; } } else { $response = esc_html__( 'There are no posts.', 'documentation-plugin' ); } /* Restore original Post Data */ wp_reset_postdata(); return rest_ensure_response( $response ); }
Und verknüpfen Sie die Methode create_custom_documentation_endpoint()
wie folgt mit dem Hook rest_api_init
:
add_action( 'rest_api_init', [ $documentation, 'create_custom_documentation_endpoint' ] );
Dadurch wird eine benutzerdefinierte Route in https://dev.wordpress.test/wp-json/documentation-plugin/v1/custom-documentation
wobei der Rückruf die Antwort für diese Route zurückgibt.
[{ "title": "Another test documentation", "tags": ["Another tag"] }, { "title": "Test documentation", "tags": ["REST API", "test tag"] }]
Es gibt viele andere Dinge, die Sie mit der REST-API tun können (weitere Details finden Sie im REST-API-Handbuch).
Umgehung langer Antwortzeiten bei Verwendung der Standard-REST-API
Für jeden, der versucht hat, eine entkoppelte WordPress-Site zu erstellen, ist dies nichts Neues – die REST-API ist langsam.
Mein Team und ich stießen zum ersten Mal auf die seltsame REST-API mit WordPress-Verzögerung auf einer Client-Site (nicht entkoppelt), wo wir die benutzerdefinierten Endpunkte verwendeten, um die Liste der Standorte auf einer Google-Karte zusammen mit anderen Metainformationen zu erhalten, die mit Advanced Custom Fields Pro erstellt wurden Plugin. Es stellte sich heraus, dass die Zeit des ersten Bytes (TTFB) – das als Hinweis auf die Reaktionsfähigkeit eines Webservers oder einer anderen Netzwerkressource verwendet wird – mehr als 3 Sekunden dauerte.
Nach einigem Nachforschen stellten wir fest, dass die standardmäßigen REST-API-Aufrufe tatsächlich sehr langsam waren, insbesondere wenn wir die Website mit zusätzlichen Plugins „belasteten“. Also haben wir einen kleinen Test gemacht. Wir haben ein paar beliebte Plugins installiert und sind auf einige interessante Ergebnisse gestoßen. Die Postboten-App gab die Ladezeit von 1,97 Sekunden für 41,9 KB Antwortgröße an. Die Ladezeit von Chrome betrug 1,25 s (TTFB war 1,25 s, Inhalt wurde in 3,96 ms heruntergeladen). Nur um eine einfache Liste von Beiträgen abzurufen. Keine Taxonomie, keine Benutzerdaten, keine zusätzlichen Metafelder.

Warum ist das passiert?
Es stellt sich heraus, dass der Zugriff auf die REST-API auf dem Standard-WordPress den gesamten WordPress-Kern lädt, um die Endpunkte zu bedienen, auch wenn er nicht verwendet wird. Außerdem wird es umso schlimmer, je mehr Plugins Sie hinzufügen. Der Standard-REST-Controller WP_REST_Controller
ist eine wirklich große Klasse, die beim Erstellen einer einfachen Webseite viel mehr leistet als nötig. Es behandelt die Registrierung von Routen, Berechtigungsprüfungen, das Erstellen und Löschen von Elementen und so weiter.
Es gibt zwei allgemeine Problemumgehungen für dieses Problem:
- Das Laden der Plugins abfangen und verhindern, dass sie alle geladen werden, wenn Sie eine einfache REST-Antwort liefern müssen;
- Laden Sie nur das Nötigste an WordPress und speichern Sie die Daten in einem Transienten, aus dem wir die Daten dann über eine benutzerdefinierte Seite abrufen.
Verbesserung der Leistung mit dem entkoppelten JSON-Ansatz
Wenn Sie mit einfachen Präsentationsseiten arbeiten, benötigen Sie nicht alle Funktionen, die Ihnen die REST-API bietet. Natürlich ist hier eine gute Planung entscheidend. Sie möchten Ihre Website wirklich nicht ohne REST-API erstellen und dann nach Jahren sagen, dass Sie eine Verbindung zu Ihrer Website herstellen oder vielleicht eine mobile App erstellen möchten, die die REST-API-Funktionalität verwenden muss. Tust du?
Aus diesem Grund haben wir zwei WordPress-Funktionen verwendet, die Ihnen beim Bereitstellen einfacher JSON-Daten helfen können:
- Transienten-API für Caching,
- Laden des mindestens erforderlichen WordPress mit der Konstante
SHORTINIT
.
Erstellen eines einfachen Endpunkts für entkoppelte Seiten
Lassen Sie uns ein kleines Plugin erstellen, das den Effekt demonstriert, über den wir sprechen. Fügen Sie zuerst eine wp-config-simple.php- Datei in Ihrem json-transient
Plugin hinzu, die so aussieht:
<?php /** * Create simple wp configuration for the routes * * @since 1.0.0 * @package json-transient */ define( 'SHORTINIT', true ); $parse_uri = explode( 'wp-content', $_SERVER['SCRIPT_FILENAME'] ); require_once filter_var( $parse_uri[0] . 'wp-load.php', FILTER_SANITIZE_STRING );
Das define( 'SHORTINIT', true );
verhindert, dass die meisten WordPress-Core-Dateien geladen werden, wie in der Datei wp-settings.php zu sehen ist.
Möglicherweise benötigen wir noch einige der WordPress-Funktionen, sodass wir die Datei (wie wp-load.php ) manuell anfordern können. Da sich wp-load.php im Stammverzeichnis unserer WordPress-Installation befindet, werden wir es abrufen, indem wir den Pfad unserer Datei mit $_SERVER['SCRIPT_FILENAME']
und diese Zeichenfolge dann nach wp-content
Zeichenfolge auflösen. Dies gibt ein Array mit zwei Werten zurück:
- Die Wurzel unserer Installation;
- Der Rest des Dateipfads (der für uns nicht von Interesse ist).
Denken Sie daran, dass wir die Standardinstallation von WordPress verwenden und keine modifizierte, wie zum Beispiel in der Bedrock-Boilerplate, die WordPress in eine andere Dateiorganisation aufteilt.
Schließlich benötigen wir aus Sicherheitsgründen die Datei wp-load.php mit ein wenig Bereinigung.
In unserer Datei init.php fügen wir Folgendes hinzu:
* Author URI: https://infinum.co/ * License: GPL-2.0+ * License URI: https://www.gnu.org/licenses/gpl-2.0.txt * Text Domain: json-transient */ namespace Json_Transient; // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } class Init { /** * Get the array of allowed types to do operations on. * * @return array * * @since 1.0.0 */ public function get_allowed_post_types() { return array( 'post', 'page' ); } /** * Check if post type is allowed to be save in transient. * * @param string $post_type Get post type. * @return boolean * * @since 1.0.0 */ public function is_post_type_allowed_to_save( $post_type = null ) { if( ! $post_type ) { return false; } $allowed_types = $this->get_allowed_post_types(); if ( in_array( $post_type, $allowed_types, true ) ) { return true; } return false; } /** * Get Page cache name for transient by post slug and type. * * @param string $post_slug Page Slug to save. * @param string $post_type Page Type to save. * @return string * * @since 1.0.0 */ public function get_page_cache_name_by_slug( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } $post_slug = str_replace( '__trashed', '', $post_slug ); return 'jt_data_' . $post_type . '_' . $post_slug; } /** * Get full post data by post slug and type. * * @param string $post_slug Page Slug to do Query by. * @param string $post_type Page Type to do Query by. * @return array * * @since 1.0.0 */ public function get_page_data_by_slug( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } $page_output = ''; $args = array( 'name' => $post_slug, 'post_type' => $post_type, 'posts_per_page' => 1, 'no_found_rows' => true ); $the_query = new \WP_Query( $args ); if ( $the_query->have_posts() ) { while ( $the_query->have_posts() ) { $the_query->the_post(); $page_output = $the_query->post; } wp_reset_postdata(); } return $page_output; } /** * Return Page in JSON format * * @param string $post_slug Page Slug. * @param string $post_type Page Type. * @return json * * @since 1.0.0 */ public function get_json_page( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } return wp_json_encode( $this->get_page_data_by_slug( $post_slug, $post_type ) ); } /** * Update Page to transient for caching on action hooks save_post. * * @param int $post_id Saved Post ID provided by action hook. * * @since 1.0.0 */ public function update_page_transient( $post_id ) { $post_status = get_post_status( $post_id ); $post = get_post( $post_id ); $post_slug = $post->post_name; $post_type = $post->post_type; $cache_name = $this->get_page_cache_name_by_slug( $post_slug, $post_type ); if( ! $cache_name ) { return false; } if( $post_status === 'auto-draft' || $post_status === 'inherit' ) { return false; } else if( $post_status === 'trash' ) { delete_transient( $cache_name ); } else { if( $this->is_post_type_allowed_to_save( $post_type ) ) { $cache = $this->get_json_page( $post_slug, $post_type ); set_transient( $cache_name, $cache, 0 ); } } } } $init = new Init(); add_action( 'save_post', [ $init, 'update_page_transient' ] );
Die Hilfsmethoden im obigen Code ermöglichen uns das Caching:
-
get_allowed_post_types()
Diese Methode teilt Beitragstypen mit, dass wir die Anzeige in unserem benutzerdefinierten „Endpunkt“ aktivieren möchten. Sie können dies erweitern, und das Plugin, mit dem wir diese Methode tatsächlich filterbar gemacht haben, sodass Sie einfach einen Filter verwenden können, um zusätzliche Elemente hinzuzufügen. -
is_post_type_allowed_to_save()
Diese Methode überprüft einfach, ob der Beitragstyp, von dem wir versuchen, die Daten abzurufen, sich in dem zulässigen Array befindet, das von der vorherigen Methode angegeben wurde. -
get_page_cache_name_by_slug()
Diese Methode gibt den Namen des Transienten zurück, von dem die Daten abgerufen werden. -
get_page_data_by_slug()
Diese Methode ist die Methode, die dieWP_Query
für den Beitrag über seinen Slug- und Beitragstyp ausführt und den Inhalt des Beitrags-Arrays zurückgibt, das wir mit JSON mithilfe der Methodeget_json_page()
konvertieren. -
update_page_transient()
Dies wird auf demsave_post
Hook ausgeführt und überschreibt den Transienten in der Datenbank mit den JSON-Daten unseres Beitrags. Diese letzte Methode ist als „Schlüssel-Caching-Methode“ bekannt.
Lassen Sie uns Transienten genauer erklären.
Transienten-API
Die Transients-API wird verwendet, um Daten für einen bestimmten Zeitraum in der Optionstabelle Ihrer WordPress-Datenbank zu speichern. Es handelt sich um einen dauerhaften Objektcache, was bedeutet, dass Sie einige Objekte speichern, z. B. Ergebnisse großer und langsamer Abfragen oder vollständige Seiten, die über Seitenladevorgänge hinweg beibehalten werden können. Es ähnelt dem regulären WordPress-Objekt-Cache, aber im Gegensatz zu WP_Cache
werden Transienten Daten über Seitenladevorgänge hinweg beibehalten, wobei WP_Cache
(Speichern der Daten im Speicher) die Daten nur für die Dauer einer Anfrage hält.
Es ist ein Schlüsselwertspeicher, was bedeutet, dass wir die gewünschten Daten einfach und schnell abrufen können, ähnlich wie es in-memory caching systems
wie Memcached oder Redis tun. Der Unterschied besteht darin, dass Sie diese normalerweise separat auf dem Server installieren müssen (was auf gemeinsam genutzten Servern ein Problem sein kann), während Transienten in WordPress integriert sind.
Wie auf der Codex-Seite erwähnt, werden Transienten von Natur aus durch Caching-Plugins beschleunigt. Da sie Transienten im Speicher statt in einer Datenbank speichern können. Als allgemeine Regel gilt, dass Sie nicht davon ausgehen sollten, dass Transienten immer in der Datenbank vorhanden sind – weshalb es sich empfiehlt, vor dem Abrufen auf Existenz zu prüfen
$transient_name = get_transient( 'transient_name' ); if ( $transient_name === false ) { set_transient( 'transient_name', $transient_data, $transient_expiry ); }
Sie können es ohne Ablaufdatum verwenden (wie wir es tun), und deshalb haben wir eine Art "Cache-Busting" beim Post-Save implementiert. Zusätzlich zu all den großartigen Funktionen, die sie bieten, können sie bis zu 4 GB an Daten speichern, aber wir empfehlen nicht, etwas so Großes in einem einzigen Datenbankfeld zu speichern.
Empfohlene Lektüre : Seien Sie wachsam: PHP- und WordPress-Funktionen, die Ihre Website unsicher machen können
Endgültiger Endpunkt: Testen und Verifizieren
Das letzte Puzzleteil, das wir brauchen, ist ein „Endpunkt“. Ich verwende hier den Begriff Endpunkt, obwohl es kein Endpunkt ist, da wir direkt eine bestimmte Datei aufrufen, um unsere Ergebnisse abzurufen. So können wir eine test.php -Datei erstellen, die so aussieht:
get_page_cache_name_by_slug( $post_slug, $post_type ) ); // Return error on false. if ( $cache === false ) { wp_send_json( 'Error, the page does not exist or it is not cached correctly. Please try rebuilding cache and try again!' ); } // Decode json for output. wp_send_json( json_decode( $cache ) );
Wenn wir zu https://dev.wordpress.test/wp-content/plugins/json-transient/test.php
gehen, sehen wir diese Nachricht:
Fehler, Seiten-Slug oder Typ fehlt!
Wir müssen also den Post-Typ und den Post-Slug angeben. Wenn wir jetzt zu https://dev.wordpress.test/wp-content/plugins/json-transient/test.php?slug=hello-world&type=post
gehen, sehen wir:
Fehler, die Seite existiert nicht oder sie ist nicht korrekt zwischengespeichert. Bitte versuchen Sie, den Cache neu aufzubauen, und versuchen Sie es erneut!
Oh, Moment mal! Wir müssen unsere Seiten und Beiträge zuerst neu speichern. Wenn Sie also anfangen, kann dies einfach sein. Aber wenn Sie bereits über 100 Seiten oder Beiträge haben, kann dies eine herausfordernde Aufgabe sein. Aus diesem Grund haben wir eine Möglichkeit implementiert, die Transienten im Decoupled JSON Content-Plugin zu löschen und sie in einem Stapel neu zu erstellen.
Aber mach weiter und speichere den Hello World- Beitrag erneut und öffne dann den Link erneut. Was Sie jetzt haben sollten, sieht so aus:
{ "ID": 1, "post_author": "1", "post_date": "2018-06-26 18:28:57", "post_date_gmt": "2018-06-26 18:28:57", "post_content": "Welcome to WordPress. This is your first post. Edit or delete it, then start writing!", "post_title": "Hello world!", "post_excerpt": "", "post_status": "publish", "comment_status": "open", "ping_status": "open", "post_password": "", "post_name": "hello-world", "to_ping": "", "pinged": "", "post_modified": "2018-06-30 08:34:52", "post_modified_gmt": "2018-06-30 08:34:52", "post_content_filtered": "", "post_parent": 0, "guid": "http:\/\/dev.wordpress.test\/?p=1", "menu_order": 0, "post_type": "post", "post_mime_type": "", "comment_count": "1", "filter": "raw" }
Und das ist es. Das von uns erstellte Plugin hat einige zusätzliche Funktionen, die Sie verwenden können, aber kurz gesagt, so können Sie die JSON-Daten viel schneller aus Ihrem WordPress abrufen als mit der REST-API.
Vorher und nachher: Verbesserte Reaktionszeit
Wir haben Tests in Chrome durchgeführt, wo wir die Gesamtantwortzeit und die TTFB separat sehen konnten. Wir haben die Antwortzeiten zehnmal hintereinander getestet: zuerst ohne Plugins und dann mit den hinzugefügten Plugins. Außerdem haben wir die Antwort für eine Liste von Posts und für einen einzelnen Post getestet.
Die Ergebnisse des Tests sind in den folgenden Tabellen dargestellt:


Wie Sie sehen können, ist der Unterschied drastisch.
Sicherheitsbedenken
Es gibt einige Vorbehalte, die Sie sich gut ansehen müssen. Zunächst einmal laden wir WordPress-Core-Dateien manuell, was in der WordPress-Welt ein großes Tabu ist. Warum? Abgesehen davon, dass das manuelle Abrufen von Kerndateien schwierig sein kann (insbesondere wenn Sie nicht standardmäßige Installationen wie Bedrock verwenden), könnte dies einige Sicherheitsbedenken aufwerfen.
Wenn Sie sich für die in diesem Artikel beschriebene Methode entscheiden, stellen Sie sicher, dass Sie wissen, wie Sie Ihre Serversicherheit verstärken können.
Fügen Sie zuerst HTML-Header wie in der Datei test.php hinzu :
header( 'Access-Control-Allow-Origin: your-front-end-app.url' ); header( 'Content-Type: application/json' );
Der erste Header ist eine Möglichkeit, die CORS-Sicherheitsmaßnahme zu umgehen, sodass nur Ihre Front-End-App den Inhalt abrufen kann, wenn Sie zur angegebenen Datei wechseln.
Deaktivieren Sie zweitens die Verzeichnisdurchquerung Ihrer App. Sie können dies tun, indem Sie die nginx
-Einstellungen ändern oder Options -Indexes
zu Ihrer .htaccess -Datei hinzufügen, wenn Sie sich auf einem Apache-Server befinden.
Das Hinzufügen einer Token-Prüfung zur Antwort ist ebenfalls eine gute Maßnahme, um unerwünschte Zugriffe zu verhindern. Wir arbeiten derzeit an einer Möglichkeit, unser entkoppeltes JSON-Plug-in so zu ändern, dass wir diese Sicherheitsmaßnahmen standardmäßig integrieren können.
Eine Prüfung auf einen von der Frontend-App gesendeten Authorization-Header könnte so aussehen:
if ( ! isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) { return; } $auth_header = $_SERVER['HTTP_AUTHORIZATION'];
Dann können Sie überprüfen, ob das spezifische Token (ein Geheimnis, das nur von den Front- und Back-End-Apps geteilt wird) bereitgestellt wird und korrekt ist.
Fazit
Die REST-API ist großartig, weil sie zum Erstellen vollwertiger Apps verwendet werden kann – zum Erstellen, Abrufen, Aktualisieren und Löschen der Daten. Der Nachteil bei der Verwendung ist seine Geschwindigkeit.
Offensichtlich unterscheidet sich die Erstellung einer App von der Erstellung einer klassischen Website. Sie werden wahrscheinlich nicht alle Plugins benötigen, die wir installiert haben. Aber wenn Sie die Daten nur zu Präsentationszwecken benötigen, scheint das Zwischenspeichern von Daten und das Bereitstellen in einer benutzerdefinierten Datei im Moment die perfekte Lösung zu sein, wenn Sie mit entkoppelten Websites arbeiten.
Sie denken vielleicht, dass die Erstellung eines benutzerdefinierten Plugins zur Beschleunigung der Antwortzeit der Website ein Overkill ist, aber wir leben in einer Welt, in der jede Sekunde zählt. Jeder weiß, dass Benutzer eine langsame Website verlassen werden. Es gibt viele Studien, die den Zusammenhang zwischen Website-Performance und Konversionsraten belegen. Aber wenn Sie noch Überzeugungsarbeit brauchen, bestraft Google langsame Websites.
Die in diesem Artikel erläuterte Methode löst das Geschwindigkeitsproblem, auf das die WordPress-REST-API stößt, und gibt Ihnen einen zusätzlichen Schub, wenn Sie an einem entkoppelten WordPress-Projekt arbeiten. Da wir auf unserer nie endenden Suche sind, die letzte Millisekunde aus jeder Anfrage und Antwort herauszuholen, planen wir, das Plugin noch weiter zu optimieren. Teilen Sie in der Zwischenzeit bitte Ihre Ideen zur Beschleunigung von entkoppeltem WordPress mit!