Це продовження моєї минулої статті про «Відтворення зовнішніх даних API у блоках WordPress на передній частині». У цьому останньому ми навчилися використовувати зовнішній API та інтегрувати його з блоком, який рендерить отримані дані у передній частині сайту WordPress.
Справа в тому, що ми зробили це таким чином, що не дозволяє нам бачити дані в редакторі блоків WordPress. Іншими словами, ми можемо вставити блок на сторінку, але не отримаємо його попереднього перегляду. Ми можемо побачити блок лише після його публікації.
Давайте повернемося до прикладу плагіна блоку, який ми створили в попередній статті. Тільки цього разу ми збираємося використовувати екосистему JavaScript і React WordPress, щоб також отримати та відобразити ці дані у внутрішньому редакторі блоків.
Де ми зупинилися
Коли ми починаємо це, ось демо де ми приземлилися в останній статті, на яку ви можете посилатися. Можливо, ви помітили, що я використав a render_callback
в останній статті, щоб я міг використовувати атрибути у файлі PHP і відтворювати вміст.
Що ж, це може бути корисним у ситуаціях, коли вам, можливо, доведеться використовувати деякі власні функції WordPress або PHP для створення динамічних блоків. Але якщо ви хочете використовувати екосистему WordPress лише JavaScript і React (зокрема JSX) для відтворення статичного HTML разом із атрибутами, що зберігаються в базі даних, вам потрібно лише зосередитися на Edit
та Save
функції плагіна блоку.
- Команда
Edit
функція рендерить вміст на основі того, що ви хочете бачити в редакторі блоків. Тут ви можете мати інтерактивні компоненти React. - Команда
Save
функція рендерить вміст на основі того, що ви хочете бачити на інтерфейсі. Ви не можете мати тут звичайні компоненти React або хуки. Він використовується для повернення статичного HTML, який зберігається у вашій базі даних разом із атрибутами.
Команда Save
функція - це місце, де ми сьогодні проводимо час. Ми можемо створювати інтерактивні компоненти на інтерфейсі, але для цього нам потрібно вручну включити їх і отримати до них доступ за межами Save
функціонувати у файлі, як ми робили в попередній статті.
Отже, я збираюся охопити те саме, що й у попередній статті, але цього разу ви можете переглянути попередній перегляд у редакторі блоків перед тим ви опублікуєте його на передній частині.
Реквізит блоку
Я навмисно пропустив будь-які пояснення щодо edit
реквізити функції в останній статті, тому що це звело б увагу з головного, візуалізації.
Якщо ви працюєте з React, ви, ймовірно, зрозумієте, про що я говорю, але якщо ви новачок у цьому, я рекомендую перевірка компонентів і реквізитів у документації React.
Якщо ми зареєструємо props
об’єкт на консоль, він повертає список функцій WordPress і змінних, пов’язаних з нашим блоком:
Нам потрібно лише attributes
об'єкт і setAttributes
функцію, яку я збираюся деструктурувати з props
об'єкт у моєму коді. У минулій статті я змінив код RapidAPI, щоб я міг зберігати дані API setAttributes()
. Реквізити доступні лише для читання, тому ми не можемо змінювати їх безпосередньо.
Реквізити блоку подібні до змінних стану та setState
у React, але React працює на стороні клієнта та setAttributes()
використовується для постійного збереження атрибутів у базі даних WordPress після збереження публікації. Отже, що нам потрібно зробити, це зберегти їх attributes.data
а потім викликати це як початкове значення для useState()
змінна.
edit
функція
Команда Я збираюся скопіювати та вставити HTML-код, який ми використовували football-rankings.php
в останній статті та трохи відредагуйте його, щоб перейти до фону JavaScript. Пам’ятаєте, як у попередній статті ми створили два додаткові файли для стилів і сценаріїв інтерфейсу? З тим, як ми сьогодні підходимо до речей, немає потреби створювати ці файли. Натомість ми можемо перемістити все це до Edit
функції.
Повний код
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}
);
})}
);
}
)}
)}
);
}
Я включив хук React useState()
від @wordpress/element
а не використовувати його з бібліотеки React. Це тому, що якби я завантажував звичайний спосіб, він завантажував би React для кожного блоку, який я використовую. Але якщо я використовую @wordpress/element
він завантажується з одного джерела, тобто з рівня WordPress поверх React.
Цього разу я також не загорнув код усередину useEffect()
але всередині функції, яка викликається лише під час натискання кнопки, щоб у нас був попередній перегляд отриманих даних. Я використовував змінну стану під назвою apiData
умовно подати турнірну таблицю. Отже, після натискання кнопки та отримання даних я встановлюю налаштування apiData
до нових даних усередині fetchData()
і доступна повторна візуалізація з HTML таблиці футбольних рейтингів.
Ви помітите, що після збереження публікації та оновлення сторінки таблиця ліги зникає. Це тому, що ми використовуємо порожній стан (null
) Для apiData
початкове значення. Коли публікація зберігається, атрибути зберігаються в attributes.data
і ми називаємо його початковим значенням для useState()
змінна така:
const [apiData, setApiData] = useState(attributes.data);
save
функція
Команда Ми збираємося зробити майже те ж саме з save
функцію, але трохи змініть її. Наприклад, немає потреби в кнопці «Отримати дані» на передній панелі, і apiData
змінна стану також непотрібна, оскільки ми вже перевіряємо її в edit
функція. Але нам потрібен рандом apiData
змінна, яка перевіряє attributes.data
для умовного рендерингу JSX, інакше виникнуть невизначені помилки, а інтерфейс редактора блоків стане порожнім.
Повний код
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}
);
})}
);
})}
)}
);
}
Якщо ви змінюєте save
після того, як блок уже присутній у редакторі блоків, він показуватиме таку помилку:
Це тому, що розмітка в збереженому вмісті відрізняється від розмітки в нашому новому save
функція. Оскільки ми перебуваємо в режимі розробки, простіше видалити блок із поточної сторінки та знову вставити його як новий блок — таким чином натомість буде використано оновлений код і все буде синхронізовано.
Цієї ситуації видалення та повторного додавання можна уникнути, якби ми використовували render_callback
оскільки вихід є динамічним і контролюється PHP замість функції збереження. Тому кожен метод має свої переваги та недоліки.
Том Ноуелл надає докладне пояснення, чого не можна робити в a save
функція в це переповнення стека відповідь.
Стилізація блоку в редакторі та передній частині
Що стосується стилю, то це буде майже те саме, що ми розглядали в минулій статті, але з деякими незначними змінами, які я пояснив у коментарях. Я просто надаю тут повні стилі, оскільки це лише доказ концепції, а не те, що ви хочете скопіювати та вставити (якщо вам справді не потрібен блок для показу футбольних рейтингів у такому стилі). І зауважте, що я все ще використовую SCSS, який компілюється в CSS під час збірки.
Стилі редактора
/* 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 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;
}
}
}
Ми додаємо це до src/style.scss
який піклується про стиль як у редакторі, так і в інтерфейсі. Я не зможу поділитися URL-адресою демонстрації, оскільки для цього потрібен доступ редактора, але я записав відео, щоб ви могли переглянути демонстрацію:
Досить акуратно, правда? Тепер у нас є повністю функціональний блок, який не тільки рендериться на інтерфейсі, але також отримує дані API та рендериться прямо в редакторі блоків — із кнопкою оновлення для завантаження!
Але якщо ми хочемо взяти Повний переваг редактора блоків WordPress, ми повинні розглянути можливість відображення деяких елементів інтерфейсу користувача блоку елементи керування блоком для таких речей, як налаштування кольору, типографіки та інтервалів. Це чудовий наступний крок у навчанні розробки блоків.