Dies ist eine Fortsetzung meines letzten Artikels über „Rendern externer API-Daten in WordPress-Blöcken am Frontend“. In letzterem haben wir gelernt, wie man eine externe API nimmt und sie in einen Block integriert, der die abgerufenen Daten auf dem Front-End einer WordPress-Site rendert.
Die Sache ist die, dass wir dies auf eine Weise erreicht haben, die uns daran hindert, die Daten im WordPress Block Editor zu sehen. Mit anderen Worten, wir können den Block auf einer Seite einfügen, erhalten aber keine Vorschau davon. Wir sehen den Block erst, wenn er veröffentlicht ist.
Sehen wir uns noch einmal das Beispiel-Block-Plugin an, das wir im letzten Artikel erstellt haben. Nur dieses Mal werden wir das JavaScript- und React-Ökosystem von WordPress nutzen, um diese Daten auch im Back-End-Blockeditor abzurufen und zu rendern.
Wo wir aufgehört haben
Während wir das starten, Hier ist eine Demo wo wir im letzten Artikel gelandet sind, auf den Sie verweisen können. Sie haben vielleicht bemerkt, dass ich a verwendet habe render_callback
-Methode im letzten Artikel, damit ich die Attribute in der PHP-Datei verwenden und den Inhalt rendern kann.
Nun, das kann in Situationen nützlich sein, in denen Sie möglicherweise eine native WordPress- oder PHP-Funktion verwenden müssen, um dynamische Blöcke zu erstellen. Wenn Sie jedoch nur das JavaScript- und React-Ökosystem (insbesondere JSX) von WordPress verwenden möchten, um das statische HTML zusammen mit den in der Datenbank gespeicherten Attributen zu rendern, müssen Sie sich nur auf das konzentrieren Edit
und Save
Funktionen des Block-Plugins.
- Das
Edit
Die Funktion rendert den Inhalt basierend auf dem, was Sie im Blockeditor sehen möchten. Sie können hier interaktive React-Komponenten haben. - Das
Save
Die Funktion rendert den Inhalt basierend auf dem, was Sie auf dem Frontend sehen möchten. Sie können hier nicht die regulären React-Komponenten oder die Hooks haben. Es wird verwendet, um das statische HTML zurückzugeben, das zusammen mit den Attributen in Ihrer Datenbank gespeichert wird.
Das Save
Funktion ist, wo wir heute abhängen. Wir können interaktive Komponenten im Front-End erstellen, aber dafür müssen wir sie manuell einschließen und außerhalb von zugreifen Save
Funktion in einer Datei, wie wir es im letzten Artikel getan haben.
Ich werde also den gleichen Bereich behandeln wie im letzten Artikel, aber dieses Mal können Sie die Vorschau im Blockeditor sehen Bevor Sie veröffentlichen es im Frontend.
Die Blockrequisiten
Ich habe absichtlich auf Erklärungen zum Thema verzichtet edit
die Requisiten der Funktion im letzten Artikel, da dies den Fokus vom Hauptpunkt, dem Rendern, abgelenkt hätte.
Wenn Sie aus einem React-Hintergrund kommen, werden Sie wahrscheinlich verstehen, wovon ich spreche, aber wenn Sie neu in diesem Bereich sind, würde ich empfehlen Überprüfen Sie die Komponenten und Requisiten in der React-Dokumentation.
Wenn wir die protokollieren props
Objekt an die Konsole, gibt es eine Liste von WordPress-Funktionen und -Variablen zurück, die sich auf unseren Block beziehen:
Wir brauchen nur die attributes
Objekt und die setAttributes
Funktion, die ich von der destrukturieren werde props
Objekt in meinem Code. Im letzten Artikel hatte ich den Code von RapidAPI so modifiziert, dass ich die API-Daten durch speichern kann setAttributes()
. Requisiten sind nur lesbar, daher können wir sie nicht direkt ändern.
Block Props ähneln Zustandsvariablen und setState
in React, aber React funktioniert auf der Client-Seite und setAttributes()
wird verwendet, um die Attribute nach dem Speichern des Beitrags dauerhaft in der WordPress-Datenbank zu speichern. Also müssen wir sie retten attributes.data
und nennen Sie das dann als Anfangswert für die useState()
variabel.
edit
Funktion
Das Ich werde den HTML-Code, den wir verwendet haben, kopieren und einfügen football-rankings.php
im letzten Artikel und bearbeiten Sie ihn ein wenig, um zum JavaScript-Hintergrund zu wechseln. Erinnern Sie sich, wie wir im letzten Artikel zwei zusätzliche Dateien für das Frontend-Styling und die Skripte erstellt haben? Bei der Art und Weise, wie wir heute an die Dinge herangehen, besteht keine Notwendigkeit, diese Dateien zu erstellen. Stattdessen können wir alles in die verschieben Edit
Funktion.
Vollständiger Code
import { useState } from "@wordpress/element";
export default function Edit(props) {
const { attributes, setAttributes } = props;
const [apiData, setApiData] = useState(null);
function fetchData() {
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 }; // Deep clone the response data
setAttributes({ data: newData }); // Store the data in WordPress attributes
setApiData(newData); // Modify the state with the new data
})
.catch((err) => console.error(err));
}
return (
{apiData && (
Rank
Logo
Team name
GP
GW
GD
GL
GF
GA
Pts
Form history
{/* Usage of [0] might be weird but that is how the API structure is. */}
{apiData.response[0].league.standings[0].map((el) => {
{/* Destructure the required data from all */}
const { played, win, draw, lose, goals } = el.all;
return (
{el.rank}
{el.team.name}
{played}
{win}
{draw}
{lose}
{goals.for}
{goals.against}
{el.points}
{el.form.split("").map((result) => {
return (
{result}
);
})}
);
}
)}
)}
);
}
Ich habe den React-Hook eingefügt useState()
für @wordpress/element
anstatt es aus der React-Bibliothek zu verwenden. Das liegt daran, dass, wenn ich auf die normale Weise laden würde, React für jeden Block heruntergeladen würde, den ich verwende. Aber wenn ich benutze @wordpress/element
Es wird aus einer einzigen Quelle geladen, dh der WordPress-Schicht über React.
Dieses Mal habe ich den Code auch nicht eingepackt useEffect()
sondern innerhalb einer Funktion, die nur aufgerufen wird, wenn auf eine Schaltfläche geklickt wird, sodass wir eine Live-Vorschau der abgerufenen Daten haben. Ich habe eine Zustandsvariable namens verwendet apiData
die Ligatabelle bedingt zu rendern. Sobald also auf die Schaltfläche geklickt und die Daten abgerufen wurden, stelle ich ein apiData
zu den neuen Daten innerhalb der fetchData()
und es ist ein Rerender mit dem HTML der Fußball-Rangliste verfügbar.
Sie werden feststellen, dass die Ligatabelle verschwunden ist, sobald der Beitrag gespeichert und die Seite aktualisiert wurde. Das liegt daran, dass wir einen leeren Zustand verwenden (null
) für apiData
Der Anfangswert von . Wenn der Beitrag gespeichert wird, werden die Attribute in gespeichert attributes.data
Objekt und wir nennen es den Anfangswert für die useState()
variabel wie folgt:
const [apiData, setApiData] = useState(attributes.data);
save
Funktion
Das Wir werden fast genau dasselbe mit dem tun save
funktionieren, aber ein wenig modifizieren. Beispielsweise entfällt die Schaltfläche „Daten abrufen“ am Frontend und die apiData
state-Variable ist auch unnötig, da wir sie bereits in der überprüfen edit
Funktion. Aber wir brauchen eine zufällige apiData
Variable, die überprüft attributes.data
um den JSX bedingt zu rendern, sonst werden undefinierte Fehler ausgegeben und die Benutzeroberfläche des Blockeditors wird leer.
Vollständiger Code
export default function save(props) {
const { attributes, setAttributes } = props;
let apiData = attributes.data;
return (
{/* Only render if apiData is available */}
{apiData && (
Rank
Logo
Team name
GP
GW
GD
GL
GF
GA
Pts
Form history
{/* Usage of [0] might be weird but that is how the API structure is. */}
{apiData.response[0].league.standings[0].map((el) => {
const { played, win, draw, lose, goals } = el.all;
return (
{el.rank}
{el.team.name}
{played}
{win}
{draw}
{lose}
{goals.for}
{goals.against}
{el.points}
{el.form.split("").map((result) => {
return (
{result}
);
})}
);
})}
)}
);
}
Wenn Sie die modifizieren save
Funktion, nachdem ein Block bereits im Blockeditor vorhanden ist, würde es einen Fehler wie diesen anzeigen:
Das liegt daran, dass sich das Markup im gespeicherten Inhalt vom Markup in unserem neuen unterscheidet save
Funktion. Da wir uns im Entwicklungsmodus befinden, ist es einfacher, den Block von der aktuellen Seite zu entfernen und als neuen Block wieder einzufügen – auf diese Weise wird stattdessen der aktualisierte Code verwendet und die Dinge sind wieder synchron.
Diese Situation des Entfernens und erneuten Hinzufügens kann vermieden werden, wenn wir die verwendet hätten render_callback
-Methode, da die Ausgabe dynamisch ist und von PHP statt von der Speicherfunktion gesteuert wird. Jede Methode hat also ihre eigenen Vor- und Nachteile.
Tom Nowell erklärt ausführlich, was in a nicht zu tun ist save
Funktion in dieser Stapelüberlauf beantworten.
Styling des Blocks im Editor und im Frontend
Was das Styling betrifft, wird es fast dasselbe sein, was wir uns im letzten Artikel angesehen haben, aber mit einigen geringfügigen Änderungen, die ich in den Kommentaren erklärt habe. Ich stelle hier lediglich die vollständigen Stile bereit, da dies nur ein Proof of Concept ist und nicht etwas, das Sie kopieren und einfügen möchten (es sei denn, Sie benötigen wirklich einen Block, um Fußballranglisten in diesem Stil anzuzeigen). Und beachten Sie, dass ich immer noch SCSS verwende, das beim Build zu CSS kompiliert wird.
Editor-Stile
/* Target all the blocks with the data-title="Football Rankings" */
.block-editor-block-list__layout
.block-editor-block-list__block.wp-block[data-title="Football Rankings"] {
/* By default, the blocks are constrained within 650px max-width plus other design specific code */
max-width: unset;
background: linear-gradient(to right, #8f94fb, #4e54c8);
display: grid;
place-items: center;
padding: 60px 0;
/* Button CSS - From: https://getcssscan.com/css-buttons-examples - Some properties really not needed :) */
button.fetch-data {
align-items: center;
background-color: #ffffff;
border: 1px solid rgb(0 0 0 / 0.1);
border-radius: 0.25rem;
box-shadow: rgb(0 0 0 / 0.02) 0 1px 3px 0;
box-sizing: border-box;
color: rgb(0 0 0 / 0.85);
cursor: pointer;
display: inline-flex;
font-family: system-ui, -apple-system, system-ui, "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 16px;
font-weight: 600;
justify-content: center;
line-height: 1.25;
margin: 0;
min-height: 3rem;
padding: calc(0.875rem - 1px) calc(1.5rem - 1px);
position: relative;
text-decoration: none;
transition: all 250ms;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
vertical-align: baseline;
width: auto;
&:hover,
&:focus {
border-color: rgb(0, 0, 0, 0.15);
box-shadow: rgb(0 0 0 / 0.1) 0 4px 12px;
color: rgb(0, 0, 0, 0.65);
}
&:hover {
transform: translateY(-1px);
}
&:active {
background-color: #f0f0f1;
border-color: rgb(0 0 0 / 0.15);
box-shadow: rgb(0 0 0 / 0.06) 0 2px 4px;
color: rgb(0 0 0 / 0.65);
transform: translateY(0);
}
}
}
Front-End-Stile
/* Front-end block styles */
.wp-block-post-content .wp-block-football-rankings-league-table {
background: linear-gradient(to right, #8f94fb, #4e54c8);
max-width: unset;
display: grid;
place-items: center;
}
#league-standings {
width: 900px;
margin: 60px 0;
max-width: unset;
font-size: 16px;
.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-color: transparent;
background-repeat: no-repeat;
background-size: contain;
background-position: right;
.stats {
display: flex;
gap: 15px;
& > 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;
top: 3px;
position: relative;
}
.stats {
display: flex;
gap: 15px;
& > div {
width: 30px;
text-align: center;
}
}
.last-5-games {
display: flex;
gap: 5px;
& > div {
width: 25px;
height: 25px;
text-align: center;
border-radius: 3px;
font-size: 15px;
& .result-W {
background: #347d39;
color: white;
}
& .result-D {
background: gray;
color: white;
}
& .result-L {
background: lightcoral;
color: white;
}
}
}
Wir ergänzen dies src/style.scss
die sich sowohl im Editor als auch im Frontend um das Styling kümmert. Ich kann die Demo-URL nicht teilen, da dafür ein Editorzugriff erforderlich wäre, aber ich habe ein Video aufgenommen, damit Sie die Demo sehen können:
Ziemlich ordentlich, oder? Jetzt haben wir einen voll funktionsfähigen Block, der nicht nur am Frontend rendert, sondern auch API-Daten abruft und direkt im Blockeditor rendert – mit einer Aktualisierungsschaltfläche zum Booten!
Aber wenn wir nehmen wollen voller Vorteil des WordPress-Block-Editors, sollten wir erwägen, einige der UI-Elemente des Blocks zuzuordnen Steuerelemente blockieren für Dinge wie das Festlegen von Farbe, Typografie und Abständen. Das ist ein netter nächster Schritt in der Lernreise zur Blockentwicklung.