Rendering External API Data in WordPress Blocks on the Front End

Avatar of Manoj Kumar
Manoj Kumar am

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

Es sind einige neue Tutorials zu WordPress-Blöcken auf CSS-Tricks erschienen. Eines davon ist eine Einführung in die Entwicklung von WordPress-Blöcken und ein guter Ort, um zu lernen, was Blöcke sind und wie man sie in WordPress für die Verwendung in Seiten und Beiträgen registriert.

Während die Grundlagen der Blöcke in diesem Beitrag gut abgedeckt sind, möchte ich noch einen Schritt weiter gehen. Wie Sie wissen, haben wir in diesem Artikel den Unterschied zwischen dem Rendern von Blöcken im WordPress Block Editor im Backend und dem Rendern im Frontend-Theme kennengelernt. Das Beispiel war ein einfacher Pullquote-Block, der auf jeder Seite unterschiedliche Inhalte und Stile rendert.

Lassen Sie uns weitergehen und sehen, wie wir **dynamische Inhalte** in einem WordPress-Block verwenden. Genauer gesagt, rufen wir Daten von einer externen API ab und rendern sie im Frontend, wenn ein bestimmter Block in den Block Editor gezogen wird.

Dies ist Teil einer größeren Reihe, in der ich alle Punkte zur Arbeit mit externen API-Daten in einem benutzerdefinierten WordPress-Block abdecken möchte.

Arbeiten mit externen APIs in WordPress-Blöcken

Wir werden einen Block erstellen, der Daten ausgibt, die Fußball (äh, Fußball) -Ranglisten von Api-Football abruft.

An ordered set of football team rankings showing team logos, names, and game results.
Das ist es, worauf wir gemeinsam hinarbeiten.

Es gibt mehr als eine Möglichkeit, eine API mit einem WordPress-Block zu integrieren! Da der Artikel über Block-Grundlagen bereits den Prozess der Erstellung eines Blocks von Grund auf durchlaufen hat, werden wir die Dinge vereinfachen, indem wir das Paket @wordpress/create-block verwenden, um unsere Arbeit zu starten und unser Projekt zu strukturieren.

Initialisieren unseres Block-Plugins

Zuerst einmal: Starten wir ein neues Projekt über die Kommandozeile

npx @wordpress/create-block football-rankings

Normalerweise würde ich ein Projekt wie dieses starten, indem ich die Dateien von Grund auf erstelle, aber Kudos an das WordPress Core-Team für dieses praktische Werkzeug!

Sobald der Projektordner durch den Befehl erstellt wurde, haben wir technisch gesehen einen voll funktionsfähigen WordPress-Block, der als Plugin registriert ist. Also, fahren wir fort und legen den Projektordner in das Verzeichnis wp-content/plugins, in dem Sie WordPress installiert haben (am besten arbeiten Sie in einer lokalen Umgebung), loggen Sie sich dann in den WordPress-Admin ein und aktivieren Sie ihn auf der Plugin-Seite.

Jetzt, da unser Block initialisiert, installiert und aktiviert ist, öffnen Sie den Projektordner unter /wp-content/plugins/football-rankings. Sie müssen von der Kommandozeile dorthin wechseln (cd), um sicherzustellen, dass wir die Entwicklung fortsetzen können.

Das sind die einzigen Dateien, auf die wir uns im Moment konzentrieren müssen

  • edit.js
  • index.js
  • football-rankings.php

Die anderen Dateien im Projekt sind natürlich wichtig, aber zu diesem Zeitpunkt unwesentlich.

Überprüfung der API-Quelle

Wir wissen bereits, dass wir Api-Football verwenden, das uns freundlicherweise von RapidAPI zur Verfügung gestellt wird. Glücklicherweise bietet RapidAPI ein Dashboard, das automatisch die erforderlichen Skripte generiert, die wir benötigen, um die API-Daten für die Premier League-Rangliste 2021 abzurufen.

A dashboard interface with three columns showing code and data from an API source.
Das RapidAPI-Dashboard

Wenn Sie sich die JSON-Struktur ansehen möchten, können Sie mit JSONCrack eine visuelle Darstellung generieren.

Daten aus der Datei edit.js abrufen

Ich werde den RapidAPI-Code in einen React useEffect() Hook mit einem leeren Abhängigkeitsarray einpacken, damit er nur einmal ausgeführt wird, wenn die Seite geladen wird. So verhindern wir, dass WordPress die API jedes Mal aufruft, wenn der Block Editor neu gerendert wird. Sie können dies mit wp.data.subscribe() überprüfen, wenn Sie möchten.

Hier ist der Code, in dem ich useEffect() importiere und ihn dann um den von RapidAPI bereitgestellten fetch()-Code wickle

/**
* The edit function describes the structure of your block in the context of the
* editor. This represents what the editor will render when the block is used.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit
*
* @return {WPElement} Element to render.
*/

import { useEffect } from "@wordpress/element";

export default function Edit(props) {
  const { attributes, setAttributes } = props;

  useEffect(() => {
    const options = {
      method: "GET",
      headers: {
        "X-RapidAPI-Key": "Your Rapid API key",
        "X-RapidAPI-Host": "api-football-v1.p.rapidapi.com",
      },
    };

    fetch("https://api-football-v1.p.rapidapi.com/v3/standings?season=2021&league=39", options)
      .then( ( response ) => response.json() )
      .then( ( response ) => {
        let newData = { ...response };
        setAttributes( { data: newData } );
        console.log( "Attributes", attributes );
      })
      .catch((err) => console.error(err));
}, []);

  return (
    <p { ...useBlockProps() }>
      { __( "Standings loaded on the front end", "external-api-gutenberg" ) }
    </p>
  );
}

Beachten Sie, dass ich die return-Funktion weitgehend unverändert gelassen habe, aber eine Notiz hinzugefügt habe, die bestätigt, dass die Fußballranglisten im Frontend gerendert werden. Auch hier konzentrieren wir uns in diesem Artikel nur auf das Frontend – wir könnten die Daten auch im Block Editor rendern, aber das überlassen wir einem anderen Artikel, um den Fokus zu behalten.

API-Daten in WordPress speichern

Nachdem wir nun Daten abrufen, müssen wir sie irgendwo in WordPress speichern. Hier kommt das attributes.data-Objekt ins Spiel. Wir definieren data.type als object, da die Daten als JSON abgerufen und formatiert werden. Stellen Sie sicher, dass Sie keinen anderen Typ haben, sonst speichert WordPress die Daten nicht und gibt auch keine Fehlermeldung zur Fehlerbehebung aus.

Das alles definieren wir in unserer index.js-Datei

registerBlockType( metadata.name, {
  edit: Edit,
  attributes: {
    data: {
      type: "object",
    },
  },
  save,
} );

OK, WordPress weiß jetzt, dass die von uns abgerufenen RapidAPI-Daten ein Objekt sind. Wenn wir einen neuen Entwurfsbeitrag im WordPress Block Editor öffnen und den Beitrag speichern, werden die Daten nun in der Datenbank gespeichert. Tatsächlich können wir sie im Feld wp_posts.post_content sehen, wenn wir die Datenbank der Website in phpMyAdmin, Sequel Pro, Adminer oder einem anderen von Ihnen verwendeten Tool öffnen.

Showing a large string of JSON output in a database table.
API-Ausgabe in der WordPress-Datenbank gespeichert

JSON-Daten im Frontend ausgeben

Es gibt mehrere Möglichkeiten, die Daten im Frontend auszugeben. Die Methode, die ich Ihnen zeigen werde, nimmt die Attribute, die in der Datenbank gespeichert sind, und übergibt sie als Parameter über die render_callback-Funktion in unserer football-rankings.php-Datei.

Ich lege Wert auf eine Trennung der Zuständigkeiten, daher füge ich zwei neue Dateien zum build-Ordner des Block-Plugins hinzu: frontend.js und frontend.css (Sie können eine frontend.scss-Datei im src-Verzeichnis erstellen, die zu CSS im build-Verzeichnis kompiliert wird). Auf diese Weise sind die Backend- und Frontend-Codes getrennt und die football-rankings.php-Datei ist etwas leichter zu lesen.

Wenn wir auf die Einführung in die Entwicklung von WordPress-Blöcken zurückkommen, gibt es editor.css- und style.css-Dateien für Backend- und gemeinsame Stile zwischen Frontend und Backend. Durch das Hinzufügen von frontend.scss (das zu frontend.css kompiliert wird, kann ich Stile isolieren, die nur für das Frontend bestimmt sind.

Bevor wir uns um diese neuen Dateien kümmern, rufen wir sie so in football-rankings.php auf

/**
* Registers the block using the metadata loaded from the `block.json` file.
* Behind the scenes, it registers also all assets so they can be enqueued
* through the block editor in the corresponding context.
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
function create_block_football_rankings_block_init() {
  register_block_type( __DIR__ . '/build', array(
    'render_callback' => 'render_frontend'
  ));
}
add_action( 'init', 'create_block_football_rankings_block_init' );

function render_frontend($attributes) {
  if( !is_admin() ) {
    wp_enqueue_script( 'football_rankings', plugin_dir_url( __FILE__ ) . '/build/frontend.js');
    wp_enqueue_style( 'football_rankings', plugin_dir_url( __FILE__ ) . '/build/frontend.css' ); // HIGHLIGHT 15,16,17,18
  }
  
  ob_start(); ?>

  <div class="football-rankings-frontend" id="league-standings">
    <div class="data">
      <pre>
        <?php echo wp_json_encode( $attributes ) ?>
      </pre>
    </div>
    <div class="header">
      <div class="position">Rank</div>
      <div class="team-logo">Logo</div>
      <div class="team-name">Team name</div>
      <div class="stats">
        <div class="games-played">GP</div>
        <div class="games-won">GW</div>
        <div class="games-drawn">GD</div>
        <div class="games-lost">GL</div>
        <div class="goals-for">GF</div>
        <div class="goals-against">GA</div>
        <div class="points">Pts</div>
      </div>
      <div class="form-history">Last 5 games</div>
    </div>
    <div class="league-table"></div>
  </div>

  <?php return ob_get_clean();
}

Da ich die render_callback()-Methode für die Attribute verwende, werde ich das Enqueueing manuell durchführen, wie es das Block Editor Handbook vorschlägt. Dies ist in der Bedingung !is_admin() enthalten und enqueue't die beiden Dateien, um zu vermeiden, dass sie beim Verwenden des Editor-Bildschirms enqueued werden.

Da wir nun zwei neue Dateien aufrufen, müssen wir sicherstellen, dass wir npm anweisen, sie zu kompilieren. Tun Sie dies also in package.json im Abschnitt scripts

"scripts": {
  "build": "wp-scripts build src/index.js src/frontend.js",
  "format": "wp-scripts format",
  "lint:css": "wp-scripts lint-style",
  "lint:js": "wp-scripts lint-js",
  "packages-update": "wp-scripts packages-update",
  "plugin-zip": "wp-scripts plugin-zip",
  "start": "wp-scripts start src/index.js src/frontend.js"
},

Eine andere Möglichkeit, die Dateien einzubinden, ist die Definition in den Block-Metadaten in unserer block.json-Datei, wie in der Einführung in die Block-Entwicklung erwähnt.

"viewScript": [ "file:./frontend.js", "example-shared-view-script" ],
"style": [ "file:./frontend.css", "example-shared-style" ],

Der einzige Grund, warum ich die package.json-Methode wähle, ist, dass ich bereits die render_callback()-Methode verwende.

Rendern der JSON-Daten

Beim Rendern konzentriere ich mich nur auf einen einzigen Block. Im Allgemeinen möchten Sie mehrere Blöcke im Frontend ansprechen. In diesem Fall müssen Sie document.querySelectorAll() mit der spezifischen ID des Blocks verwenden.

Ich warte im Grunde darauf, dass das Fenster geladen wird, und rufe Daten für einige Schlüsselobjekte aus JSON ab und wende sie auf Markup an, das sie im Frontend rendert. Ich werde auch die attributes-Daten in ein JSON-Objekt konvertieren, damit sie im JavaScript leichter zu lesen sind, und die Details aus JSON in HTML für Dinge wie das Logo der Fußballliga, Teamlogos und Statistiken setzen.

Die Spalte „Letzte 5 Spiele“ zeigt das Ergebnis der letzten fünf Spiele eines Teams. Ich muss die Daten dafür manuell ändern, da die API-Daten im String-Format vorliegen. Die Konvertierung in ein Array kann helfen, es im HTML als separates Element für jedes der letzten fünf Spiele eines Teams zu verwenden.

import "./frontend.scss";

// Wait for the window to load
window.addEventListener( "load", () => {
  // The code output
  const dataEl = document.querySelector( ".data pre" ).innerHTML;
  // The parent rankings element
  const tableEl = document.querySelector( ".league-table" );
  // The table headers
  const tableHeaderEl = document.querySelector( "#league-standings .header" );
  // Parse JSON for the code output
  const dataJSON = JSON.parse( dataEl );
  // Print a little note in the console
  console.log( "Data from the front end", dataJSON );
  
  // All the teams 
  let teams = dataJSON.data.response[ 0 ].league.standings[ 0 ];
  // The league logo
  let leagueLogoURL = dataJSON.data.response[ 0 ].league.logo;
  // Apply the league logo as a background image inline style
  tableHeaderEl.style.backgroundImage = `url( ${ leagueLogoURL } )`;
  
  // Loop through the teams
  teams.forEach( ( team, index ) => {
    // Make a div for each team
    const teamDiv = document.createElement( "div" );
    // Set up the columns for match results
    const { played, win, draw, lose, goals } = team.all;

    // Add a class to the parent rankings element
    teamDiv.classList.add( "team" );
    // Insert the following markup and data in the parent element
    teamDiv.innerHTML = `
      <div class="position">
        ${ index + 1 }
      </div>
      <div class="team-logo">
        <img src="${ team.team.logo }" />
      </div>
      <div class="team-name">${ team.team.name }</div>
      <div class="stats">
        <div class="games-played">${ played }</div>
        <div class="games-won">${ win }</div>
        <div class="games-drawn">${ draw }</div>
        <div class="games-lost">${ lose }</div>
        <div class="goals-for">${ goals.for }</div>
        <div class="goals-against">${ goals.against }</div>
        <div class="points">${ team.points }</div>
      </div>
      <div class="form-history"></div>
    `;
    
    // Stringify the last five match results for a team
    const form = team.form.split( "" );
    
    // Loop through the match results
    form.forEach( ( result ) => {
      // Make a div for each result
      const resultEl = document.createElement( "div" );
      // Add a class to the div
      resultEl.classList.add( "result" );
      // Evaluate the results
      resultEl.innerText = result;
      // If the result a win
      if ( result === "W" ) {
        resultEl.classList.add( "win" );
      // If the result is a draw
      } else if ( result === "D" ) {
        resultEl.classList.add( "draw" );
      // If the result is a loss
      } else {
        resultEl.classList.add( "lost" );
      }
      // Append the results to the column
      teamDiv.querySelector( ".form-history" ).append( resultEl );
    });

    tableEl.append( teamDiv );
  });
});

Was das Styling angeht, können Sie tun, was Sie wollen! Wenn Sie etwas zum Arbeiten haben möchten, habe ich einen vollständigen Satz von Stilen, die Sie als Ausgangspunkt verwenden können.

Ich habe die Stile in SCSS gestaltet, da das @wordpress/create-block-Paket sie direkt unterstützt. Führen Sie npm run start in der Kommandozeile aus, um die SCSS-Dateien zu beobachten und sie beim Speichern nach CSS zu kompilieren. Alternativ können Sie npm run build bei jedem Speichern verwenden, um SCSS zu kompilieren und den Rest des Plugin-Bundles zu erstellen.

SCSS anzeigen
body {
  background: linear-gradient(to right, #8f94fb, #4e54c8);
}

.data pre {
  display: none;
}

.header {
  display: grid;
  gap: 1em;
  padding: 10px;
  grid-template-columns: 1fr 1fr 3fr 4fr 3fr;
  align-items: center;
  color: white;
  font-size: 16px;
  font-weight: 600;
  background-repeat: no-repeat;
  background-size: contain;
  background-position: right;
}

.frontend#league-standings {
  width: 900px;
  margin: 60px 0;
  max-width: unset;
  font-size: 16px;

  .header {
    .stats {
      display: flex;
      gap: 15px;

      &amp; &gt; div {
        width: 30px;
      }
    }
  }
}

.league-table {
  background: white;
  box-shadow:
    rgba(50, 50, 93, 0.25) 0px 2px 5px -1px,
    rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
  padding: 1em;

  .position {
    width: 20px;
  }

  .team {
    display: grid;
    gap: 1em;
    padding: 10px 0;
    grid-template-columns: 1fr 1fr 3fr 4fr 3fr;
    align-items: center;
  }

  .team:not(:last-child) {
    border-bottom: 1px solid lightgray;
  }

  .team-logo img {
    width: 30px;
  }

  .stats {
    display: flex;
    gap: 15px;
  }

  .stats &gt; div {
    width: 30px;
    text-align: center;
  }

  .form-history {
    display: flex;
    gap: 5px;
  }

  .form-history &gt; div {
    width: 25px;
    height: 25px;
    text-align: center;
    border-radius: 3px;
    font-size: 15px;
  }

  .form-history .win {
    background: #347d39;
    color: white;
  }

  .form-history .draw {
    background: gray;
    color: white;
  }

  .form-history .lost {
    background: lightcoral;
    color: white;
  }
}

Hier ist die Demo!

Schauen Sie sich das an – wir haben gerade ein Block-Plugin erstellt, das Daten abruft und sie im Frontend einer WordPress-Website rendert.

Wir haben eine API gefunden, Daten von ihr mit fetch() abgerufen, sie in der WordPress-Datenbank gespeichert, sie geparst und sie auf HTML-Markup angewendet, um sie im Frontend anzuzeigen. Nicht schlecht für ein einzelnes Tutorial, oder?

Auch hier können wir dasselbe tun, damit die Ranglisten im Block Editor zusätzlich zum Frontend des Themes gerendert werden. Aber hoffentlich zeigt die Konzentration auf das Frontend, wie das Abrufen von Daten in einem WordPress-Block funktioniert und wie die Daten strukturiert und für die Anzeige gerendert werden können.