Aceasta este o continuare a ultimului articol despre „Redarea datelor API externe în blocuri WordPress pe front end”. În ultimul, am învățat cum să luăm un API extern și să îl integrăm cu un bloc care redă datele preluate pe front-end-ul unui site WordPress.
Chestia este că am realizat acest lucru într-un mod care ne împiedică să vedem datele în Editorul de blocuri WordPress. Cu alte cuvinte, putem insera blocul pe o pagină, dar nu obținem o previzualizare a acestuia. Putem vedea blocul doar când este publicat.
Să revedem exemplul de plugin de bloc pe care l-am creat în ultimul articol. Numai de această dată, vom folosi ecosistemul JavaScript și React al WordPress pentru a prelua și reda acele date și în editorul de blocuri back-end.
De unde am plecat
Când începem asta, iată un demo unde am aterizat în ultimul articol pe care îl puteți referi. Poate ați observat că am folosit a render_callback
metoda din ultimul articol, astfel încât să pot folosi atributele din fișierul PHP și să reda conținutul.
Ei bine, asta poate fi util în situațiile în care ar putea fi necesar să utilizați o funcție nativă WordPress sau PHP pentru a crea blocuri dinamice. Dar dacă doriți să utilizați doar ecosistemul JavaScript și React (JSX, în special) al WordPress pentru a reda HTML-ul static împreună cu atributele stocate în baza de date, trebuie să vă concentrați doar pe Edit
și Save
funcțiile plugin-ului bloc.
-
Edit
funcția redă conținutul pe baza a ceea ce doriți să vedeți în Editorul de blocuri. Puteți avea componente interactive React aici. -
Save
funcția redă conținutul pe baza a ceea ce doriți să vedeți pe front end. Nu puteți avea aici componentele obișnuite React sau cârligele. Este folosit pentru a returna codul HTML static care este salvat în baza de date împreună cu atributele.
Save
Funcția este locul în care petrecem azi. Putem crea componente interactive pe front-end, dar pentru asta trebuie să le includem și să le accesăm manual în afara Save
funcția într-un fișier așa cum am făcut-o în ultimul articol.
Deci, voi acoperi același teren pe care l-am făcut în ultimul articol, dar de data aceasta puteți vedea previzualizarea în Editorul de blocuri înainte îl publicați pe front-end.
Recuzita blocului
Am omis în mod intenționat orice explicație despre edit
elementele de recuzită ale funcției din ultimul articol, deoarece asta ar fi scos accentul de pe punctul principal, randarea.
Dacă vii dintr-un mediu React, probabil vei înțelege despre ce vorbesc, dar dacă ești nou în acest domeniu, aș recomanda verificarea componentelor și elementelor de recuzită în documentația React.
Dacă înregistrăm props
obiect la consolă, returnează o listă de funcții și variabile WordPress legate de blocul nostru:
Avem nevoie doar de attributes
obiect şi cel setAttributes
funcția pe care o voi destructura din props
obiect din codul meu. În ultimul articol, am modificat codul RapidAPI, astfel încât să pot stoca datele API setAttributes()
. Recuzitele sunt doar lizibile, așa că nu le putem modifica direct.
Blocurile de recuzită sunt similare cu variabilele de stare și setState
în React, dar React funcționează pe partea clientului și setAttributes()
este folosit pentru a stoca permanent atributele în baza de date WordPress după salvarea postării. Deci, ceea ce trebuie să facem este să-i salvăm attributes.data
și apoi numiți asta ca valoare inițială pentru useState()
variabilă.
edit
funcţie
Voi copia și lipi codul HTML pe care l-am folosit football-rankings.php
în ultimul articol și editați-l puțin pentru a trece la fundalul JavaScript. Vă amintiți cum am creat două fișiere suplimentare în ultimul articol pentru stilul și scripturile frontale? Cu modul în care abordăm lucrurile astăzi, nu este nevoie să creăm acele fișiere. În schimb, putem muta totul în Edit
Funcția.
Cod complet
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}
);
})}
);
}
)}
)}
);
}
Am inclus cârligul React useState()
din @wordpress/element
mai degrabă decât să-l folosească din biblioteca React. Asta pentru că, dacă ar fi să încarc modul obișnuit, ar descărca React pentru fiecare bloc pe care îl folosesc. Dar dacă folosesc @wordpress/element
se încarcă dintr-o singură sursă, adică stratul WordPress de deasupra lui React.
De data aceasta, nici nu am împachetat codul înăuntru useEffect()
dar în interiorul unei funcții care este apelată doar când faceți clic pe un buton, astfel încât să avem o previzualizare live a datelor preluate. Am folosit o variabilă de stare numită apiData
pentru a reda tabelul ligii în mod condiționat. Deci, odată ce se face clic pe butonul și datele sunt preluate, setez apiData
la noile date din interiorul fetchData()
și există o redare cu HTML-ul tabelului de clasament al fotbalului disponibil.
Veți observa că odată ce postarea este salvată și pagina este reîmprospătată, clasamentul a dispărut. Asta pentru că folosim o stare goală (null
) pentru apiData
valoarea initiala a lui. Când postarea se salvează, atributele sunt salvate în attributes.data
obiect și îl numim ca valoare inițială pentru useState()
variabila astfel:
const [apiData, setApiData] = useState(attributes.data);
save
funcţie
Vom face aproape același lucru cu save
funcția, dar modificați-o puțin. De exemplu, nu este nevoie de butonul „Preluare date” de pe partea frontală, iar butonul apiData
variabila de stat este, de asemenea, inutilă, deoarece o verificăm deja în edit
funcţie. Dar avem nevoie de o întâmplare apiData
variabilă care verifică attributes.data
pentru a reda condiționat JSX-ul, altfel va arunca erori nedefinite și interfața de utilizare a editorului de blocuri va rămâne goală.
Cod complet
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}
);
})}
);
})}
)}
);
}
Dacă modificați save
după ce un bloc este deja prezent în Editorul de blocuri, ar afișa o eroare ca aceasta:
Acest lucru se datorează faptului că marcajul din conținutul salvat este diferit de marcajul din noul nostru save
funcţie. Deoarece ne aflăm în modul de dezvoltare, este mai ușor să scoatem bock-ul din pagina curentă și să îl reinserăm ca bloc nou - în acest fel, codul actualizat este folosit și lucrurile sunt din nou sincronizate.
Această situație de a-l elimina și de a-l adăuga din nou poate fi evitată dacă am fi folosit render_callback
metoda deoarece ieșirea este dinamică și controlată de PHP în loc de funcția de salvare. Deci, fiecare metodă are propriile avantaje și dezavantaje.
Tom Nowell oferă o explicație amănunțită despre ce să nu faci într-un save
funcția în acest Stack Overflow răspunde.
Stilizarea blocului în editor și front-end
În ceea ce privește stilul, va fi aproape același lucru la care ne-am uitat în ultimul articol, dar cu câteva modificări minore pe care le-am explicat în comentarii. Vă ofer doar stilurile complete aici, deoarece aceasta este doar o dovadă a conceptului, mai degrabă decât ceva ce doriți să copiați și lipiți (cu excepția cazului în care aveți într-adevăr nevoie de un bloc pentru a afișa clasamentele de fotbal în stilul acesta). Și rețineți că încă folosesc SCSS care se compilează în CSS la build.
Stiluri de editor
/* 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);
}
}
}
Stiluri front-end
/* 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;
}
}
}
Adăugăm asta la src/style.scss
care se ocupă de stilul atât în editor, cât și în frontend. Nu voi putea partaja adresa URL a demonstrației, deoarece ar necesita acces la editor, dar am un videoclip înregistrat pentru ca tu să vezi demonstrația:
Destul de îngrijit, nu? Acum avem un bloc pe deplin funcțional care nu numai că se redă pe front-end, dar preia și datele API și se redă chiar acolo în Editorul de blocuri - cu un buton de reîmprospătare pentru a porni!
Dar dacă vrem să luăm Complet avantajul Editorului de blocuri WordPress, ar trebui să luăm în considerare maparea unora dintre elementele UI ale blocului către bloc de controale pentru lucruri precum setarea culorii, tipografiei și spațierea. Acesta este un următor pas frumos în călătoria de învățare a dezvoltării blocurilor.