این ادامه آخرین مقاله من در مورد است ارائه داده های API خارجی در بلوک های وردپرس در فرانت اند. در آخرین مورد، ما یاد گرفتیم که چگونه یک API خارجی بگیریم و آن را با بلوکی ادغام کنیم که دادههای واکشی شده را در قسمت جلویی یک سایت وردپرس ارائه میکند.
مسئله این است که ما این کار را به گونه ای انجام دادیم که از دیدن داده ها در ویرایشگر بلاک وردپرس جلوگیری کنیم. به عبارت دیگر، میتوانیم بلوک را در یک صفحه وارد کنیم، اما هیچ پیشنمایش آن را دریافت نمیکنیم. ما فقط وقتی بلوک را می بینیم که منتشر شود.
بیایید نمونه پلاگین بلوک را که در مقاله گذشته ساختیم، دوباره مرور کنیم. فقط این بار، میخواهیم از اکوسیستم جاوا اسکریپت و React وردپرس برای واکشی و ارائه آن دادهها در ویرایشگر بلاک پشتی نیز استفاده کنیم.
جایی که ما متوقف شدیم
همانطور که ما این را شروع می کنیم، در اینجا یک نسخه ی نمایشی است جایی که در آخرین مقاله ای که می توانید به آن مراجعه کنید، فرود آمدیم. شاید متوجه شده باشید که من از a استفاده کردم render_callback
روش در مقاله آخر بود تا بتوانم از ویژگی های موجود در فایل PHP استفاده کنم و محتوا را رندر کنم.
خوب، این ممکن است در شرایطی مفید باشد که ممکن است مجبور شوید از برخی از عملکردهای بومی وردپرس یا PHP برای ایجاد بلوک های پویا استفاده کنید. اما اگر می خواهید فقط از اکوسیستم جاوا اسکریپت و واکنش (به طور خاص JSX) وردپرس برای ارائه HTML ایستا همراه با ویژگی های ذخیره شده در پایگاه داده استفاده کنید، فقط باید بر روی Edit
و Save
عملکردهای پلاگین بلوک
- La
Edit
تابع محتوا را بر اساس آنچه می خواهید در ویرایشگر بلوک ببینید، ارائه می دهد. در اینجا می توانید کامپوننت های تعاملی React داشته باشید. - La
Save
تابع محتوا را بر اساس آنچه می خواهید در قسمت جلویی ببینید، ارائه می کند. در اینجا نمی توانید کامپوننت های معمولی React یا هوک ها را داشته باشید. برای برگرداندن HTML ایستا که به همراه ویژگی ها در پایگاه داده شما ذخیره شده است استفاده می شود.
La Save
عملکرد جایی است که ما امروز در آن قرار داریم. ما میتوانیم اجزای تعاملی را در قسمت جلویی ایجاد کنیم، اما برای این کار باید بهطور دستی آنها را در خارج از بخش قرار داده و به آنها دسترسی داشته باشیم. Save
مانند آنچه در مقاله قبلی انجام دادیم در یک فایل عمل کنید.
بنابراین، من قصد دارم همان زمینه ای را که در مقاله گذشته انجام دادیم پوشش دهم، اما این بار می توانید پیش نمایش آن را در ویرایشگر Block مشاهده کنید. قبل از شما آن را در قسمت جلو منتشر می کنید.
پایه های بلوک
من عمداً هیچ توضیحی در مورد آن را حذف کردم edit
ویژگیهای تابع در مقاله آخر، زیرا این امر تمرکز را از نقطه اصلی یعنی رندر خارج میکرد.
اگر از یک پسزمینه React میآیید، احتمالاً متوجه خواهید شد که من در مورد چه چیزی صحبت میکنم، اما اگر در این زمینه تازه کار هستید، توصیه میکنم بررسی کامپوننت ها و قطعات در مستندات React.
اگر ما وارد شوید props
شی به کنسول، لیستی از توابع و متغیرهای وردپرس مربوط به بلوک ما را برمی گرداند:
ما فقط نیاز داریم attributes
شی و setAttributes
تابعی که قصد دارم از آن حذف کنم props
شیء در کد من در آخرین مقاله، کد RapidAPI را تغییر داده بودم تا بتوانم داده های API را از طریق آن ذخیره کنم setAttributes()
. پروپوزالها فقط قابل خواندن هستند، بنابراین ما نمیتوانیم مستقیماً آنها را تغییر دهیم.
Block props شبیه متغیرهای حالت و setState
در React، اما React در سمت مشتری کار می کند و setAttributes()
برای ذخیره ویژگی ها به طور دائم در پایگاه داده وردپرس پس از ذخیره پست استفاده می شود. بنابراین، کاری که ما باید انجام دهیم این است که آنها را ذخیره کنیم attributes.data
و سپس آن را به عنوان مقدار اولیه برای useState()
متغیر.
edit
تابع
La من قصد دارم کد HTML را که در آن استفاده کردهایم کپی-پیست کنم football-rankings.php
در آخرین مقاله و کمی آن را ویرایش کنید تا به پس زمینه جاوا اسکریپت بروید. به یاد دارید که چگونه دو فایل اضافی را در آخرین مقاله برای استایل و اسکریپت های جلویی ایجاد کردیم؟ با روشی که امروز به مسائل نزدیک می شویم، نیازی به ایجاد آن فایل ها نیست. در عوض، ما می توانیم همه آن را به 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
از یک منبع واحد بارگیری می شود، یعنی لایه وردپرس در بالای React.
این بار نیز کد را داخل آن قرار نداده ام useEffect()
اما در داخل تابعی که فقط با کلیک روی یک دکمه فراخوانی می شود تا پیش نمایشی زنده از داده های واکشی شده داشته باشیم. من از یک متغیر حالت به نام استفاده کرده ام apiData
جدول لیگ را به صورت مشروط ارائه کنیم. بنابراین، هنگامی که دکمه کلیک می شود و داده ها واکشی می شوند، من در حال تنظیم هستم apiData
به داده های جدید در داخل fetchData()
و یک رندر با HTML جدول رده بندی فوتبال موجود است.
متوجه خواهید شد که پس از ذخیره پست و رفرش صفحه، جدول لیگ از بین می رود. این به این دلیل است که ما از یک حالت خالی استفاده می کنیم (null
) برای apiData
مقدار اولیه هنگامی که پست ذخیره می شود، ویژگی ها در آن ذخیره می شوند attributes.data
شی و ما آن را به عنوان مقدار اولیه برای useState()
متغیر مانند این:
const [apiData, setApiData] = useState(attributes.data);
save
تابع
La ما تقریباً دقیقاً همان کار را با آن انجام خواهیم داد save
عملکرد، اما آن را کمی تغییر دهید. برای مثال، نیازی به دکمه «واکشی داده» در قسمت جلویی نیست و apiData
متغیر state نیز غیرضروری است زیرا ما در حال بررسی آن هستیم edit
عملکرد. اما ما به یک تصادفی نیاز داریم apiData
متغیری که بررسی می کند attributes.data
به صورت مشروط JSX را رندر کنید وگرنه خطاهای تعریف نشده ای ایجاد می کند و رابط کاربری ویرایشگر Block خالی می شود.
کد کامل
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
عملکرد. از آنجایی که ما در حالت توسعه هستیم، حذف bock از صفحه فعلی و درج مجدد آن به عنوان یک بلوک جدید آسان تر است - به این ترتیب، کد به روز شده به جای آن استفاده می شود و همه چیز دوباره همگام می شود.
اگر از آن استفاده کرده بودیم، می توان از این وضعیت حذف و اضافه کردن مجدد آن جلوگیری کرد render_callback
از آنجایی که خروجی پویا است و به جای تابع ذخیره توسط PHP کنترل می شود. بنابراین هر روشی مزایا و معایب خاص خود را دارد.
تام ناول توضیح کاملی در مورد کارهایی که نباید انجام داد را ارائه می دهد 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 را واکشی میکند و همانجا در ویرایشگر Block رندر میشود - با یک دکمه رفرش برای بوت کردن!
اما اگر بخواهیم بگیریم کامل از مزایای ویرایشگر بلاک وردپرس، ما باید نگاشت برخی از عناصر رابط کاربری بلوک را در نظر بگیریم کنترل های بلوک برای مواردی مانند تنظیم رنگ، تایپوگرافی و فاصله. این یک گام بعدی خوب در سفر یادگیری توسعه بلوک است.