Gedanken zu einem API-First WordPress

Avatar of Eduardo Bouças
Eduardo Bouças am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Der folgende Beitrag ist ein Gastbeitrag von Eduardo Bouças. Wir alle kennen WordPress als CMS, aber hier denkt Eduardo darüber nach, es nur als API für Inhalte zu verwenden. Gar keine Frontend-Oberfläche, nur URL-Endpunkte, die JSON für die Verwendung anderswo zurückgeben. Dies beschreibt keine umfassende Lösung dafür, sondern ist Stoff zum Nachdenken mit einigen Beispielcodes, um Ihnen den Einstieg in eine benutzerdefinierte Lösung zu erleichtern. Wenn Sie sofort mit der Entwicklung auf einem solchen System beginnen möchten, ist WP REST API das robusteste Projekt mit der größten Dynamik.

Vor kurzem wurde ich gebeten, eine CMS-Lösung für eine Digitalagentur auszuwählen und zu implementieren, um mehrere Websites in einer einzigen Installation zu verwalten. Aus einer Vielzahl von Gründen war der Hauptkandidat WordPress. Es ist kostenlos und Open Source, hat eine riesige Benutzergemeinschaft, ist einfach zu bedienen und verfügt über eine Multisite-Funktion. Es ist zweifellos ein kommerziell erprobtes und ausgereiftes Produkt. Aber ich hatte meine Bedenken.

WordPress auf herkömmliche Weise zu verwenden bedeutet, eine Installation vorzunehmen, ein Theme zu erstellen (oder ein bestehendes zu modifizieren) und zu akzeptieren, dass jede weitere Anpassung ihren Platz im vom CMS geschaffenen Ökosystem finden muss: die Programmiersprachen und Technologien (PHP und MySQL) sowie die clevere – aber ziemlich komplexe – Welt der Plugins, Themes, Aktionen, Filter und was weiß ich noch.

Ich habe mir immer Inhalte als Zentrum von allem auf einer Website vorgestellt. Die Natur und das kreative Konzept jedes einzelnen Projekts sollten diktieren, welches Medium und welche Technologien die Inhalte am besten liefern können, nicht das CMS.

Ich möchte meine Technologieauswahl für ein Projekt nicht auf PHP beschränken, nur weil WordPress darauf basiert, und ich möchte, dass Entwickler die Freiheit haben, jeden beliebigen Technologiestack zu wählen, den sie für die Erstellung unabhängiger und in sich geschlossener Websites als geeignet erachten, nicht nur WordPress-Plugins und -Themes.

Einen Mittelsmann schaffen

Eine API-first-Lösung mit einer Zwischenschicht, die zwischen der Website und dem CMS sitzt, kann WordPress von jeglicher Frontend-Geschäftstätigkeit befreien und ihm den alleinigen Zweck der Verwaltung und Bereitstellung von Inhalten überlassen.

Diese "Mittelsmann"-Schicht kann eine universelle Sprache (JSON ist meine Präferenz) sprechen, die verschiedene Endplattformen verstehen und auf eine Weise verarbeiten können, die zum Projekt passt.

Ich denke so etwas wie dies

Beispiel einer Multisite-WordPress-Installation, die eine API versorgt

WordPress anpassen

In der normalen WordPress-Welt würden die Leute über einen menschenfreundlichen Domainnamen auf die Website zugreifen, die Inhalte würden aus der Datenbank abgerufen und ein Theme würde sie dann formatieren und auf einer HTML-Seite anzeigen. Diese Seite hätte wahrscheinlich auch eine visuelle Benutzeroberfläche, damit Benutzer Beiträge und Seiten durchsuchen und Inhalte nach Kategorien, Tags oder anderen Taxonomien filtern können.

Unser API-first WordPress wird nichts davon haben. Die einzige Eingabe, die wir von Benutzern akzeptieren, kommt über die URL der Anfragen, die sie senden. Diese müssen wir parsen, um die Art der Daten, die wir liefern müssen, das Format und die Filter, durch die sie geleitet werden, zu extrahieren.

Ein Plugin erstellen

Es gibt gute und schlechte Wege, Funktionalitäten in WordPress hinzuzufügen und zu ändern. Kurz gesagt, das Herumfummeln am Kerncode ist keine gute Idee, Sie sollten stattdessen ein Plugin erstellen.

Aber wie wird unser Plugin genau funktionieren? Wie kann es die Standardereigniskette ändern, die vom CMS befolgt wird, um eine Anfrage zu lesen, Dinge aus der Datenbank zu holen und etwas zurückzusenden? Das kann mit einem Hook – genauer gesagt mit einer Aktion – geschehen, die es uns ermöglicht, einzugreifen und die Anfrage abzufangen, um die volle Kontrolle darüber zu übernehmen, was von diesem Zeitpunkt an geschieht.

Legen wir also die Grundlagen für unser Plugin.

class API {
  public function __construct() {
    add_action('template_redirect', array($this, 'hijackRequests'), -100);
  }

  public function hijackRequests() {
    $entries = get_posts($_GET['filter']);

    $this->writeJsonResponse($entries);
  }

  protected function writeJsonResponse($message, $status = 200) {
    header('content-type: application/json; charset=utf-8', true, $status);
    echo(json_encode($message) . "\n");
    exit;
  }
}

new API();

Es ist eine gute Praxis, das Plugin in eine Klassenstruktur zu verpacken, um zu vermeiden, dass der globale Namensraum mit losen Funktionen verschmutzt wird, was zu Namenskonflikten führen kann.

Wir beginnen dann damit, eine Funktion mit der Aktion template_redirect zu registrieren, die nach der Initialisierungsroutine ausgeführt wird und kurz bevor WordPress entscheidet, welches Template zum Rendern der Seite verwendet werden soll.

Dann rufen wir get_posts() auf, das ein Array von Filtern als Argument akzeptiert und ein Array von passenden Einträgen zurückgibt (der Funktionsname kann irreführend sein; er kann sowohl Beiträge als auch Seiten zurückgeben).

Nach dem Speichern der Datei und der Aktivierung des Plugins sollte der Aufruf von http://your-WP/index.php?filter[post_type]=post&filter[posts_per_page]=1 eine JSON-Darstellung Ihres neuesten Beitrags liefern. Super!

Multiplexing von Anfragen

Zu diesem Zeitpunkt haben wir eine sehr einfache API, die es uns ermöglicht, Einträge aus WordPress basierend auf einer Reihe von Filtern abzurufen, was für ein sehr einfaches Projekt ausreichen mag. Aber was passiert, wenn wir mehrere Datensätze benötigen, um verschiedene Elemente auf einer Seite darzustellen? Es scheint nicht vernünftig, mehrere HTTP-Anfragen zu senden.

Nehmen wir zum Beispiel die Forumseite von CSS-Tricks. Neben einigen Metadaten, die wir wahrscheinlich benötigen, gibt es mindestens drei verschiedene Inhaltssätze, die aus dem CMS abgerufen werden müssen: die Elemente in der Navigationsleiste, die neuesten Beiträge und die Tipps.

Verschiedene Inhaltgruppen auf einer CSS-Tricks-Seite

Wir können unsere eigene benutzerdefinierte Syntax für die API definieren, sodass sie die Definition von "Inhaltscontainern" bei Bedarf akzeptiert und diese als JSON-Array in der Antwort aufgeteilt zurückgibt.

Anstatt die Filter als einfaches Array in der URL zu übergeben, können wir jedem Label zuweisen, dass es zu einem bestimmten Container gehört. Zurück zum obigen Beispiel könnte die URL für eine Multiplex-Anfrage so aussehen

?navigation:filter[category]=navigation
&latestPosts:filter[type]=post
&tips:filter[slug]=tips

Was eine JSON-Struktur wie diese zurückgeben würde

{
  "navigation": [
    {
      "ID": 1
      (...)
    },
    {
      "ID": 2
      (...)
    }
  ],
  "latestPosts": [
    (...)
  ],
  "tips": [
    (...)
  ]
}

Dies gibt den API-Konsumenten einfachen Zugriff auf die verschiedenen benötigten Inhaltsteile, ohne zusätzlichen Aufwand.

Die Funktion hijackRequests kann modifiziert werden, um diese Funktion zu implementieren.

public function hijackRequests() {
  $usingBuckets = false;
  $buckets = array();
  $entries = array();

  foreach ($_GET as $variable => $value) {
    if (($separator = strpos($variable, ':')) !== false) {
      $usingBuckets = true;
      $bucket = substr($variable, 0, $separator);
      $filter = substr($variable, $separator + 1);
    } else {
      $bucket = 0;
      $filter = $variable;
    }

    $buckets[$bucket][$filter] = $value;
  }

  if ($usingBuckets) {
    foreach ($buckets as $name => $content) {
      $entries[$name] = get_posts($content['filter']);
    }
  } else {
    $entries = get_posts($buckets[0]['filter']);
  }

  $this->writeJsonResponse($entries);
}
Update vom Herausgeber: Eduardo hat ein Erweiterungs-Plugin für WP-API erstellt, um dies zu tun! Schauen Sie sich das GitHub-Repository an.

Galerien und benutzerdefinierte Felder hinzufügen

Unsere JSON-Darstellung von Beiträgen basiert auf den von get_posts() zurückgegebenen Informationen, aber dort fehlen einige Dinge, die Sie wahrscheinlich in Ihrem Feed haben möchten, wie z. B. Bildergalerien und benutzerdefinierte Felder. Wir können diese Informationen mit Hilfe der Funktionen get_post_galleries_images() und get_post_meta() selbst an den JSON-Feed anhängen.

for ($i = 0, $numEntries = count($entries); $i < $numEntries; $i++) {
    $metaFields = get_post_meta($entries[$i]->ID);

  $galleriesImages = get_post_galleries_images($entries[$i]->ID);
  $entries[$i]->galleries = $galleriesImages;

  foreach ($metaFields as $field => $value) {
    // Discarding private meta fields (that begin with an underscore)
    if (strpos($field, '_') === 0) {
      continue;
    }

    if (is_array($value) && (count($value) == 1)) {
      $entries[$i]->$field = $value[0];
    } else {
      $entries[$i]->$field = $value;
    }
  }
}

Abschließende Gedanken

Die in diesem Artikel beschriebene Lösung kratzt kaum an der Oberfläche dessen, was der Aufbau einer API beinhaltet. Wir haben uns noch nicht mit Dingen wie Authentifizierung, Anfragetypen für Schreibzugriff (POST, PUT, DELETE), mehreren Endpunkten für verschiedene Inhaltstypen (Benutzer, Kategorien, Einstellungen), API-Versioning oder JSONP-Unterstützung beschäftigt.

Anstatt ein produktionsfertiges Produkt bereitzustellen, soll diese Lösung die inneren Abläufe einer WordPress-API aufzeigen, was hoffentlich dazu inspiriert, benutzerdefinierte Lösungen zu erstellen oder bestehende zu erweitern, um ihre spezifischen Bedürfnisse zu erfüllen.

Ehrlich gesagt ist die Erstellung einer maßgeschneiderten API-Lösung nicht jedermanns Sache. WP REST API ist ein etabliertes und ausgereiftes Produkt und wird bald Teil des WordPress-Kerns sein, sodass die Verwendung von etwas wie diesem wahrscheinlich eine klügere Wahl ist.

Vor allem soll dieser Artikel die Idee beleuchten, ein weit verbreitetes, kommerziell erprobtes und ausgereiftes Produkt wie WordPress zu nehmen und es als API-first Content-Management-System zu verwenden. Das bedeutet, einen Hauptteil von WordPress zu entfernen und die Vorteile von Dingen wie SEO-Plugins und einfachem Theming zu verlieren, aber man gewinnt die Freiheit eines plattformunabhängigen Systems.

Was denken Sie?