Dette er en fortsettelse av min siste artikkel om "Å gjengi eksterne API-data i WordPress-blokker på grensesnittet". I den siste lærte vi å ta en ekstern API og integrere den med en blokk som gjengir de hentede dataene på frontenden av et WordPress-nettsted.
Saken er at vi oppnådde dette på en måte som hindrer oss i å se dataene i WordPress Block Editor. Med andre ord, vi kan sette inn blokken på en side, men vi får ingen forhåndsvisning av den. Vi får først se blokken når den er publisert.
La oss se på eksempelblokkpluginen vi laget i forrige artikkel. Bare denne gangen skal vi bruke JavaScript og React-økosystemet til WordPress for å hente og gjengi disse dataene også i back-end Block Editor.
Der vi slapp
Når vi starter dette, her er en demo hvor vi landet i den siste artikkelen som du kan referere til. Du har kanskje lagt merke til at jeg brukte en render_callback
metoden i den siste artikkelen slik at jeg kan bruke attributtene i PHP-filen og gjengi innholdet.
Vel, det kan være nyttig i situasjoner der du kanskje må bruke en innfødt WordPress- eller PHP-funksjon for å lage dynamiske blokker. Men hvis du bare vil bruke JavaScript og React (JSX, spesifikt) økosystemet til WordPress for å gjengi statisk HTML sammen med attributtene som er lagret i databasen, trenger du bare å fokusere på Edit
og Save
funksjonene til blokkeringspluginen.
- De
Edit
funksjonen gjengir innholdet basert på hva du ønsker å se i Block Editor. Du kan ha interaktive React-komponenter her. - De
Save
funksjonen gjengir innholdet basert på hva du vil se på grensesnittet. Du kan ikke ha de vanlige React-komponentene eller krokene her. Den brukes til å returnere den statiske HTML-koden som er lagret i databasen sammen med attributtene.
De Save
funksjonen er der vi henger ut i dag. Vi kan lage interaktive komponenter på front-end, men for det må vi manuelt inkludere og få tilgang til dem utenfor Save
funksjon i en fil som vi gjorde i forrige artikkel.
Så, jeg skal dekke det samme området som vi gjorde i forrige artikkel, men denne gangen kan du se forhåndsvisningen i Block Editor før du du publiserer den til frontend.
Blokkrekvisittene
Jeg har med vilje utelatt noen forklaringer om edit
funksjonens rekvisitter i den siste artikkelen fordi det ville ha fjernet fokuset fra hovedpoenget, gjengivelsen.
Hvis du kommer fra en React-bakgrunn, vil du sannsynligvis forstå hva jeg snakker om, men hvis du er ny på dette, vil jeg anbefale sjekke ut komponenter og rekvisitter i React-dokumentasjonen.
Hvis vi logger props
objekt til konsollen, returnerer den en liste over WordPress-funksjoner og variabler relatert til blokken vår:
Vi trenger bare attributes
objektet og setAttributes
funksjon som jeg skal destrukturere fra props
objekt i koden min. I den siste artikkelen hadde jeg modifisert RapidAPIs kode slik at jeg kan lagre API-dataene gjennom setAttributes()
. Rekvisitter er kun lesbare, så vi kan ikke endre dem direkte.
Blokkrekvisitter ligner på tilstandsvariabler og setState
i React, men React fungerer på klientsiden og setAttributes()
brukes til å lagre attributtene permanent i WordPress-databasen etter lagring av innlegget. Så det vi må gjøre er å redde dem til attributes.data
og kall det deretter som startverdien for useState()
variabel.
edit
funksjon
De Jeg skal kopiere og lime inn HTML-koden som vi brukte i football-rankings.php
i den siste artikkelen og rediger den litt for å skifte til JavaScript-bakgrunnen. Husker du hvordan vi opprettet to ekstra filer i den siste artikkelen for frontend-styling og skript? Med måten vi nærmer oss ting i dag, er det ikke nødvendig å lage disse filene. I stedet kan vi flytte alt til Edit
funksjon.
Full kode
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}
);
})}
);
}
)}
)}
);
}
Jeg har inkludert React-kroken useState()
fra @wordpress/element
i stedet for å bruke den fra React-biblioteket. Det er fordi hvis jeg skulle laste den vanlige måten, ville den laste ned React for hver blokk jeg bruker. Men hvis jeg bruker @wordpress/element
det laster fra en enkelt kilde, dvs. WordPress-laget på toppen av React.
Denne gangen har jeg heller ikke pakket inn koden useEffect()
men inne i en funksjon som kalles kun når du klikker på en knapp slik at vi har en live forhåndsvisning av de hentede dataene. Jeg har brukt en tilstandsvariabel kalt apiData
å gjengi ligatabellen betinget. Så når knappen er klikket og dataene er hentet, setter jeg apiData
til de nye dataene i fetchData()
og det er en gjengivelse med HTML-koden til fotballrankingstabellen tilgjengelig.
Du vil legge merke til at når innlegget er lagret og siden er oppdatert, er ligatabellen borte. Det er fordi vi bruker en tom tilstand (null
) for apiData
sin opprinnelige verdi. Når innlegget lagres, lagres attributtene til attributes.data
objekt og vi kaller det som startverdien for useState()
variabel som dette:
const [apiData, setApiData] = useState(attributes.data);
save
funksjon
De Vi kommer til å gjøre nesten det samme med save
funksjon, men endre den litt. For eksempel er det ikke behov for "Hent data"-knappen på fronten, og apiData
tilstandsvariabel er også unødvendig fordi vi allerede sjekker den i edit
funksjon. Men vi trenger en tilfeldighet apiData
variabel som sjekker etter attributes.data
for å betinget gjengi JSX, ellers vil det gi udefinerte feil og Block Editor-grensesnittet blir tomt.
Full kode
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}
);
})}
);
})}
)}
);
}
Hvis du endrer save
funksjon etter at en blokk allerede er til stede i blokkredigeringsprogrammet, vil den vise en feil som dette:
Det er fordi markeringen i det lagrede innholdet er forskjellig fra markeringen i vår nye save
funksjon. Siden vi er i utviklingsmodus, er det lettere å fjerne blokken fra den gjeldende siden og sette den inn på nytt som en ny blokk – på den måten brukes den oppdaterte koden i stedet og ting er tilbake synkronisert.
Denne situasjonen med å fjerne den og legge den til igjen kan unngås hvis vi hadde brukt render_callback
metode siden utgangen er dynamisk og kontrollert av PHP i stedet for lagringsfunksjonen. Så hver metode har sine egne fordeler og ulemper.
Tom Nowell gir en grundig forklaring på hva du ikke skal gjøre i en save
fungere i denne Stack Overflow besvare.
Styling av blokken i editoren og frontend
Når det gjelder stylingen, kommer det til å være nesten det samme som vi så på i forrige artikkel, men med noen mindre endringer som jeg har forklart i kommentarfeltet. Jeg gir bare de fullstendige stilene her siden dette bare er et bevis på konseptet i stedet for noe du vil kopiere og lime inn (med mindre du virkelig trenger en blokk for å vise fotballrankinger stilt akkurat som dette). Og merk at jeg fortsatt bruker SCSS som kompilerer til CSS på build.
Redaktørstiler
/* 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 stiler
/* 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;
}
}
}
Vi legger dette til src/style.scss
som tar seg av stylingen i både editoren og frontend. Jeg vil ikke være i stand til å dele demo-URL siden den vil kreve redaktørtilgang, men jeg har tatt opp en video slik at du kan se demoen:
Ganske ryddig, ikke sant? Nå har vi en fullt fungerende blokk som ikke bare gjengir på frontend, men også henter API-data og gjengir rett der i Block Editor - med en oppdateringsknapp for å starte opp!
Men hvis vi vil ta fullt Fordelen med WordPress Block Editor, bør vi vurdere å kartlegge noen av blokkens brukergrensesnittelementer til blokkkontroller for ting som å angi farge, typografi og avstand. Det er et fint neste steg i læringsreisen for blokkutvikling.