هذا استمرار لمقالتي الأخيرة حول "عرض بيانات واجهة برمجة التطبيقات الخارجية في قوالب WordPress على الواجهة الأمامية". في ذلك الأخير ، تعلمنا كيفية استخدام واجهة برمجة تطبيقات خارجية ودمجها مع كتلة تعرض البيانات التي تم جلبها في الواجهة الأمامية لموقع WordPress.
الشيء هو أننا أنجزنا هذا بطريقة تمنعنا من رؤية البيانات في محرر قوالب WordPress. بمعنى آخر ، يمكننا إدراج الكتلة في صفحة لكننا لا نحصل على معاينة لها. لا يمكننا رؤية الكتلة إلا عندما يتم نشرها.
دعنا نعيد النظر في مثال المكون الإضافي للكتلة الذي أنشأناه في المقالة الأخيرة. هذه المرة فقط ، سنستفيد من نظام JavaScript و React البيئي في WordPress لجلب هذه البيانات وعرضها في محرر Block الخلفي أيضًا.
حيث توقفنا
عندما نبدأ هذا ، هنا عرض حيث وصلنا في المقال الأخير الذي يمكنك الرجوع إليه. ربما لاحظت أنني استخدمت ملف render_callback
في المقالة الأخيرة حتى أتمكن من الاستفادة من السمات في ملف PHP وعرض المحتوى.
حسنًا ، قد يكون ذلك مفيدًا في المواقف التي قد تضطر فيها إلى استخدام بعض وظائف WordPress أو PHP الأصلية لإنشاء كتل ديناميكية. ولكن إذا كنت ترغب في الاستفادة من النظام البيئي JavaScript و React (JSX على وجه التحديد) من WordPress لعرض HTML الثابت جنبًا إلى جنب مع السمات المخزنة في قاعدة البيانات ، فأنت تحتاج فقط إلى التركيز على Edit
و Save
وظائف البرنامج المساعد بلوك.
- •
Edit
تعرض الوظيفة المحتوى بناءً على ما تريد رؤيته في محرر القوالب. يمكنك الحصول على مكونات تفاعلية هنا. - •
Save
تعرض الوظيفة المحتوى بناءً على ما تريد رؤيته في الواجهة الأمامية. لا يمكنك الحصول على مكونات React العادية أو الخطافات هنا. يتم استخدامه لإرجاع HTML الثابت الذي تم حفظه في قاعدة البيانات الخاصة بك مع السمات.
• Save
الوظيفة هي المكان الذي نتسكع فيه اليوم. يمكننا إنشاء مكونات تفاعلية في الواجهة الأمامية ، ولكن من أجل ذلك نحتاج إلى تضمينها يدويًا والوصول إليها خارج نطاق Save
تعمل في ملف كما فعلنا في المقال الأخير.
لذلك ، سأقوم بتغطية نفس الأرضية التي قمنا بها في المقالة الأخيرة ، ولكن هذه المرة يمكنك مشاهدة المعاينة في Block Editor قبل تنشره في الواجهة الأمامية.
الدعائم الكتلة
لقد تركت عمدا أي تفسيرات حول 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 بشكل مشروط وإلا ستظهر أخطاء غير محددة وستصبح واجهة مستخدم Block Editor فارغة.
كود كامل
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 بدلاً من وظيفة الحفظ. لذلك كل طريقة لها مزاياها وعيوبها.
يقدم Tom Nowell شرحًا شاملاً لما لا يجب فعله في ملف save
وظيفة في هذا Stack Overflow إجابة.
تصميم الكتلة في المحرر والواجهة الأمامية
فيما يتعلق بالتصميم ، سيكون نفس الشيء تقريبًا الذي نظرنا إليه في المقالة الأخيرة ، ولكن مع بعض التغييرات الطفيفة التي شرحتها في التعليقات. أنا فقط أقدم الأنماط الكاملة هنا لأن هذا مجرد دليل على المفهوم وليس شيئًا تريد نسخه ولصقه (إلا إذا كنت بحاجة فعلاً إلى كتلة لعرض تصنيفات كرة القدم على غرار هذا تمامًا). ولاحظ أنني ما زلت أستخدم 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 Editor - مع زر تحديث للتمهيد!
ولكن إذا أردنا أن نأخذ بالإضافة إلى الاستفادة من محرر قوالب WordPress ، يجب أن نفكر في تعيين بعض عناصر واجهة المستخدم الخاصة بالكتلة إلى ضوابط الكتلة لأشياء مثل تعيين اللون والطباعة والتباعد. هذه خطوة تالية لطيفة في رحلة تعلم تطوير الكتلة.