นี่เป็นความต่อเนื่องของบทความล่าสุดของฉันเกี่ยวกับ “การเรนเดอร์ข้อมูล API ภายนอกในบล็อก WordPress ที่ส่วนหน้า”. ในอันสุดท้ายนี้ เราได้เรียนรู้วิธีใช้ API ภายนอกและรวมเข้ากับบล็อกที่แสดงข้อมูลที่ดึงมาที่ส่วนหน้าของไซต์ WordPress
สิ่งนั้นคือ เราทำสำเร็จในลักษณะที่ป้องกันไม่ให้เรามองเห็นข้อมูลใน WordPress Block Editor กล่าวอีกนัยหนึ่ง เราสามารถแทรกบล็อกบนหน้าได้ แต่จะไม่มีการแสดงตัวอย่าง เราจะได้เห็นบล็อกเมื่อเผยแพร่เท่านั้น
มาทบทวนตัวอย่างบล็อกปลั๊กอินที่เราทำในบทความที่แล้วกัน เฉพาะครั้งนี้ เราจะใช้ JavaScript และ React ระบบนิเวศของ WordPress เพื่อดึงและแสดงผลข้อมูลนั้นใน Back-end Block Editor เช่นกัน
ที่เราเลิกกัน
เมื่อเราเริ่มต้นสิ่งนี้ นี่คือตัวอย่าง ที่เราไปถึงบทความล่าสุดที่คุณสามารถอ้างอิงได้ คุณอาจสังเกตเห็นว่าฉันใช้ a render_callback
ในบทความที่แล้ว เพื่อที่ฉันจะได้ใช้แอตทริบิวต์ในไฟล์ PHP และแสดงเนื้อหา
นั่นอาจเป็นประโยชน์ในสถานการณ์ที่คุณอาจต้องใช้ฟังก์ชัน WordPress หรือ PHP ดั้งเดิมเพื่อสร้างบล็อกแบบไดนามิก แต่ถ้าคุณต้องการใช้ประโยชน์จากระบบนิเวศ JavaScript และ React (JSX โดยเฉพาะ) ของ WordPress เพื่อแสดง HTML แบบคงที่พร้อมกับแอตทริบิวต์ที่จัดเก็บไว้ในฐานข้อมูล คุณจะต้องเน้นที่ Edit
และ Save
หน้าที่ของบล็อกปลั๊กอิน
- พื้นที่
Edit
ฟังก์ชั่นแสดงเนื้อหาตามสิ่งที่คุณต้องการเห็นในตัวแก้ไขบล็อก คุณสามารถมีส่วนประกอบ React แบบโต้ตอบได้ที่นี่ - พื้นที่
Save
ฟังก์ชั่นแสดงเนื้อหาตามสิ่งที่คุณต้องการดูในส่วนหน้า คุณไม่สามารถมีส่วนประกอบ React ปกติหรือ hooks ที่นี่ ใช้เพื่อส่งคืน 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 hook ไว้ด้วย 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 UI จะว่างเปล่า
รหัสเต็ม
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
ฟังก์ชันมา กองนี้ล้น คำตอบ.
การจัดรูปแบบบล็อกในตัวแก้ไขและส่วนหน้า
เกี่ยวกับการจัดสไตล์ เกือบจะเหมือนกับที่เราดูในบทความที่แล้ว แต่มีการเปลี่ยนแปลงเล็กน้อยซึ่งฉันได้อธิบายไว้ในความคิดเห็น ฉันแค่นำเสนอสไตล์เต็มรูปแบบที่นี่ เนื่องจากนี่เป็นเพียงการพิสูจน์แนวคิดมากกว่าสิ่งที่คุณต้องการคัดลอกและวาง (เว้นแต่ว่าคุณต้องการบล็อกสำหรับการแสดงอันดับฟุตบอลที่มีสไตล์เช่นนี้จริงๆ) และโปรดทราบว่าฉันยังคงใช้ 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 Block Editor เราควรพิจารณาจับคู่องค์ประกอบ UI ของบล็อกกับ การควบคุมบล็อก สำหรับสิ่งต่างๆ เช่น การตั้งค่าสี การออกแบบตัวอักษร และการเว้นวรรค นั่นเป็นขั้นตอนต่อไปที่ดีในเส้นทางการเรียนรู้การพัฒนาบล็อก