สร้างประสบการณ์การแก้ไข WordPress ที่ยอดเยี่ยมและประหยัดเวลาด้วย Gutenberg InnerBlocks
เผยแพร่แล้ว: 2023-02-12อย่าทำซ้ำตัวเอง
สำหรับนักพัฒนา ความเกียจคร้านอาจเป็นคุณงามความดี ส่วนประกอบที่ทำขึ้นอย่างดีและใช้ซ้ำได้ช่วยประหยัดเวลาและช่วยให้สามารถใช้ซ้ำได้อย่างมีประสิทธิภาพและสม่ำเสมอ สิ่งนี้ช่วยสร้างประสบการณ์การแก้ไขใน WordPress ได้ดี เนื่องจากความสม่ำเสมอทำให้เกิดความคุ้นเคยและความรู้สำหรับผู้ที่ใช้เว็บไซต์ในแต่ละวัน
WordPress สร้างเสียงรบกวนอย่างมากด้วยการเปิดตัวตัวแก้ไขบล็อก Gutenberg ซึ่งปัจจุบันรู้จักกันในชื่อ “The Editor” สำหรับการแก้ไขเนื้อหา การร่าง และการเผยแพร่ เนื้อหาจะมอบประสบการณ์ที่ยอดเยี่ยม ดีกว่า WYSIWYG แบบเก่ามาก ในฐานะนักพัฒนา ฉันต้องการมอบประสบการณ์การแก้ไขที่ดีที่สุดให้กับลูกค้าของฉัน ฉันต้องการใช้ประโยชน์จากฟังก์ชันการทำงานหลัก และฉันไม่ต้องการคิดค้นสิ่งใหม่ๆ โชคดีที่ WordPress ช่วยให้เราทำสิ่งเหล่านี้ได้ด้วยบล็อกแบบกำหนดเอง
ใส่ InnerBlocks
InnerBlocks เป็นฟีเจอร์ที่ยอดเยี่ยมในตัวแก้ไข WordPress นักพัฒนาสามารถใช้บล็อกหลัก เช่น ย่อหน้า หัวเรื่อง และปุ่มเพื่อสร้างประสบการณ์ที่สอดคล้องกันสำหรับลูกค้า แทนที่จะเขียนส่วนข้อความใหม่และประกาศฟิลด์ใหม่ ลูกค้าจะได้รับประสบการณ์ที่พวกเขาคุ้นเคย แก้ไขและรวมบล็อกเดียวกัน มาดูบล็อกที่เราอาจต้องสร้างสำหรับลูกค้า และดูว่า InnerBlocks ช่วยให้เราบรรลุเป้าหมายได้อย่างไร
สร้างบล็อกด้วย InnerBlocks

ลองพิจารณาบล็อกนี้และพิจารณาว่าเราจะสร้างบล็อกนี้ได้อย่างไร เครื่องมือทั่วไปที่เราเข้าถึงเมื่อสร้างบล็อกคือ Advanced Custom Fields (ACF) ACF Pro เพิ่มการรองรับบล็อกแบบกำหนดเอง ซึ่งช่วยให้นักพัฒนาเขียนบล็อกใน PHP สำหรับตัวแก้ไขและส่วนหน้า นอกจากนี้ยังช่วยให้เราใช้ฟิลด์ที่กำหนดเอง ซึ่งเป็นกระบวนทัศน์ที่นักพัฒนา WordPress หลายคนคุ้นเคย ACF รองรับ InnerBlocks ซึ่งหมายความว่าเราสามารถสร้างบล็อกแบบกำหนดเองได้ แต่ไม่จำเป็นต้องเขียนโค้ดแบบกำหนดเองสำหรับส่วนหัว ย่อหน้า หรือปุ่มนั้นด้วยซ้ำ
ด้วย ACF Blocks เราสามารถใช้ประโยชน์จากบล็อกหลักเพื่อสร้างประสบการณ์การแก้ไขที่ยอดเยี่ยมสำหรับข้อความทั้งหมดที่เราเห็นในบล็อกนี้ อีกทางเลือกหนึ่งที่เป็นไปได้คือการใช้รูปแบบบล็อก แต่ในฐานะนักพัฒนาและผู้ดูแลประสบการณ์ที่ยอดเยี่ยมของ WordPress การสร้างบล็อกแบบกำหนดเองจะบรรลุเป้าหมายที่ต้องการ
บล็อกรหัสการลงทะเบียน
นี่คือรหัสเพื่อลงทะเบียนบล็อก ACF ที่กำหนดเองของเรา อ่านเพิ่มเติมเกี่ยวกับการใช้ฟังก์ชัน acf_register_block_type ที่นี่
<?php /** * Template for registering an ACF powered custom block. * * More info: https://www.advancedcustomfields.com/resources/blocks/ */ /** * Register the block. */ add_action( 'acf/init', function() { /** * ACF block registration options here: https://www.advancedcustomfields.com/resources/acf_register_block_type/ */ acf_register_block_type( array( 'name' => 'call-to-action-demo', // JS will register as: acf/{block-name}. 'title' => __( 'Call to Action ACF Demo', 'locale' ), 'description' => __( 'A custom ACF Call to Action block.', 'locale' ), 'render_template' => 'partials/blocks/call-to-action-demo.php', // Change to block template. 'category' => 'design', // Category in the block inserter. 'keywords' => array( 'action', 'buttons', 'cta' ), // Searchable keywords. 'supports' => array( 'align' => false, // Disable support for align. 'anchor' => true, // Enable support for anchor. 'jsx' => true, // Enable support for JSX. 'mode' => false, // Disable ACF block edit/preview mode switching as we are only using InnerBlocks for editable content. ), ) ); } );
มาทำลายโค้ดกันเถอะ เรากำลังใช้ฟังก์ชัน acf_register_block_type เพื่อลงทะเบียนบล็อกของเรา และเรากำลังส่งอาร์กิวเมนต์อาร์เรย์ที่กำหนดบล็อกของเราและเปิดและปิดฟังก์ชันการทำงาน
- ขอให้สังเกตว่าเรากำลังปฏิบัติตามขั้นตอนที่แนะนำในการเพิ่มชื่อเฉพาะสำหรับบล็อกของเรา ตลอดจนชื่อและคำอธิบายที่มนุษย์สามารถอ่านได้ เราชี้ไปที่เทมเพลตการเรนเดอร์ ซึ่งเราจะตั้งค่าเทมเพลต PHP สำหรับบล็อกในภายหลัง เราได้เพิ่มหมวดหมู่ที่เราต้องการให้บล็อกของเราจัดกลุ่มในตัวแทรกบล็อก
- เรามีคำหลักที่ค้นหาได้เพื่อทำให้การค้นหาบล็อกง่ายขึ้นในตัวแทรก
- เราเพิ่มอาร์เรย์ 'สนับสนุน' เพื่อเปิดใช้งานฟังก์ชันต่างๆ เช่น การตั้งค่าจุดยึด HTML และเราได้ปิดการจัดตำแหน่งเนื่องจากบล็อกนี้จะอยู่ตรงกลางของหน้าเสมอ
- ที่รองรับอาร์เรย์เป็นที่ที่เราเปิดเวทมนตร์ InnerBlocks! การตั้งค่า 'jsx' เป็น true เป็นการบอก ACF ว่าเราจะสนับสนุนการเรนเดอร์เทมเพลต React jsx ภายในบล็อกของเรา
ตรวจสอบเนื้อหาที่เราต้องการในบล็อกของเรา:
- หัวเรื่อง
- ข้อความย่อหน้า
- ปุ่มเพื่อดำเนินการ!
ตอนนี้ โดยปกติเราจะกำหนดฟิลด์ให้กับบล็อกของเรา ดังที่แสดงไว้ที่นี่ แต่ในกรณีนี้ เราไม่จำเป็นต้องทำ—เราสามารถใช้ประโยชน์จากบล็อกหลักเพื่อให้บรรลุเป้าหมายทั้งหมดนี้ได้ หากบล็อกต้องการพื้นหลังรูปภาพ การเพิ่มช่องรูปภาพ ACF ลงในบล็อกอาจเป็นวิธีที่ยอดเยี่ยมในการบรรลุเป้าหมายนั้น สำหรับตอนนี้ เรามาดูตัวอย่าง InnerBlocks ของเราแล้วข้ามไปที่เทมเพลตกัน
เทมเพลตบล็อก
นี่คือเทมเพลตสำหรับบล็อกใหม่ ตรวจสอบให้แน่ใจว่าได้ชี้การลงทะเบียนบล็อกไปยังตำแหน่งเทมเพลตบล็อก แนวทางปฏิบัติทั่วไปคือการใส่สิ่งเหล่านี้ในโฟลเดอร์บางส่วนในธีม
<?php /** * ACF Call to Action example block template. * * More info: https://www.advancedcustomfields.com/resources/acf_register_block_type/ * * @param array $block The block settings and attributes. * @param string $content The block inner HTML (empty). * @param bool $is_preview True during AJAX preview. * @param (int|string) $post_id The post ID this block is saved to. * */ // Create id attribute allowing for custom "anchor" value. $block_ . $block['id']; if ( ! empty( $block['anchor'] ) ) { $block_id = $block['anchor']; } // Create class attribute allowing for custom "className" and "align" values. $class_name = 'acf-call-to-action-demo'; if ( ! empty( $block['className'] ) ) { $class_name .= ' ' . $block['className']; } if ( ! empty( $block['align'] ) ) { $class_name .= ' align' . $block['align']; } ?> <div class="<?php echo esc_html( $class_name ); ?>"> <div class="cta__inner"> <?php // Set up innerBlocks and provide a template. // Restrict InnerBlocks to allowed block list. $allowed_blocks = array( 'core/heading', 'core/paragraph', 'core/buttons' ); // Start InnerBlocks with a template. $template = array( array( 'core/heading', array( 'placeholder' => __( 'CTA Heading', 'locale' ), 'align' => 'center', 'level' => '2', ), ), array( 'core/paragraph', array( 'placeholder' => __( 'Add CTA text here', 'locale' ), 'align' => 'center', ), ), array( 'core/buttons', array( 'placeholder' => __( 'Add CTA buttons here', 'locale' ), 'align' => 'center', ), array( array( 'core/button', array( 'text' => __( 'Take action', 'locale' ), ), ), array( 'core/button', array( 'text' => __( 'Learn more', 'locale' ), ), ), ), ), ); // Echo out our JSX InnerBlocks compoennt for the editor. echo '<InnerBlocks allowedBlocks="' . esc_attr( wp_json_encode( $allowed_blocks ) ) . '" template="' . esc_attr( wp_json_encode( $template ) ) . '" templateLock="false" />'; ?> </div> </div>
มาทำลายโค้ดนี้กันเถอะ
- ในตอนเริ่มต้น เรามีต้นแบบแม่แบบบล็อกทั่วไปที่ ACF มีให้ในแนวทางบล็อก เช่น การสนับสนุนจุดยึดและชื่อคลาสที่กำหนดเอง
- คอมโพเนนต์ InnerBlocks สามารถรับคุณสมบัติได้ เราใช้สามแบบในเทมเพลตนี้
- บล็อกที่อนุญาต: เราเพิ่มอาร์เรย์ของบล็อกที่อนุญาตเพื่อจัดการ เฉพาะบล็อกเหล่านี้เท่านั้นที่จะสามารถเลือกได้ในพื้นที่ InnerBlocks ของบล็อกที่กำหนดเองของเรา
- เทมเพลต: เราสามารถส่งอาร์เรย์ของบล็อกและเราสามารถส่งแอตทริบิวต์ของบล็อกสำหรับบล็อกที่จะเริ่มต้นด้วยเมื่อโหลดเข้าสู่โปรแกรมแก้ไขครั้งแรก
- ขอให้สังเกตว่าเราสามารถส่งแอตทริบิวต์บล็อกเพื่อตั้งค่าผู้ใช้ของเราให้พร้อมสำหรับความสำเร็จ หัวข้อมีการตั้งค่าระดับ 2 แล้ว และย่อหน้าอยู่กึ่งกลาง
- หมายเหตุ: บล็อกหลักจะถูกอ้างถึงใน JavaScript เสมอว่า {plugin}/blockname ในกรณีของเรา เราใช้บล็อกหลัก แต่ถ้าคุณต้องการใช้บล็อก ACF แบบกำหนดเอง คุณต้องเขียน 'acf' ข้างหน้าชื่อบล็อก โปรดจำไว้ว่า เมื่อใช้ InnerBlocks เราจะส่งส่วนประกอบนี้ไปยัง WordPress Editor ซึ่งใช้ React นั่นเป็นเหตุผลที่เรากำลังคิดใน JS ที่นี่
- หมายเหตุอื่น: สังเกตว่าบล็อกแกน/ปุ่มใช้ InnerBlocks เอง! เรากำลังผ่านอาร์เรย์ของแกน/ปุ่มสองบล็อกภายใน!
- การล็อกเทมเพลต: templateLock ถูกตั้งค่าบนคอมโพเนนต์ InnerBlocks หากเราตั้งค่าเป็น 'ทั้งหมด' จะไม่มีการย้ายหรือลบบล็อกในเทมเพลตของเราที่มอบให้กับ InnerBlocks หากเราตั้งค่าเป็น 'insert' บล็อกภายในจะเลื่อนไปมาได้เท่านั้น ไม่สามารถลบบล็อกออกได้ และไม่สามารถเพิ่มบล็อกใหม่ได้ หากเราตั้งค่าเป็น 'เท็จ' อินสแตนซ์ InnerBlocks จะถูกปลดล็อกและจะปลดล็อกโดยไม่คำนึงถึงการล็อกเทมเพลตพาเรนต์ใดๆ (เพิ่มเติมเกี่ยวกับเรื่องนี้ด้านล่าง) อ่านเพิ่มเติมเกี่ยวกับ Block Templates ใน WordPress Block Editor Handbook เราจะพูดถึงการล็อคบล็อกมากขึ้น
เรามีบล็อกใหม่! หลังจากนั้น และแน่นอนว่าสไตล์บางอย่าง บล็อกตัวอย่างในเครื่องมือแก้ไขจะมีลักษณะดังนี้:


Nesting Deeper: ดูแลจัดการประสบการณ์ให้ดียิ่งขึ้นด้วย Nested InnerBlocks
เรามีบล็อกที่ยอดเยี่ยม และเราไม่ต้องตั้งค่า WYSIWYG หรือแม้แต่จัดการฟิลด์แบบกำหนดเองในเทมเพลตของเรา แต่จะเป็นอย่างไรหากเราต้องการดูแลจัดการและปรับแต่งประสบการณ์นี้ให้ดียิ่งขึ้นสำหรับลูกค้า สมมติว่าเราได้รับคำขอให้ตรวจสอบว่ามีส่วนหัวอยู่เสมอ ดังนั้นจึงมีบล็อกส่วนหัวเสมอ แต่เนื้อหาหลังจากนั้นมีความยืดหยุ่นและอาจรวมถึงรายการหรือบล็อกประเภทอื่น เป้าหมายของเราคือการบรรลุความยืดหยุ่นดังกล่าว ในขณะเดียวกันก็รักษาความสม่ำเสมอ
ลองพิจารณากฎบางอย่างเมื่อทำงานกับ InnerBlocks:
- บล็อกเดียวอาจมี InnerBlocks ได้เพียงหนึ่งอินสแตนซ์เท่านั้น
- หลายบล็อกภายใน InnerBlocks อาจใช้ส่วนประกอบ InnerBlocks ของตัวเอง
- InnerBlocks อาจถูกล็อคผ่านคุณสมบัติ templateLock แต่อินสแตนซ์ของ InnerBlocks ที่อยู่ลึกลงไปภายในโครงสร้างบล็อกที่ซ้อนกันอาจถูกปลดล็อคอีกครั้งโดยการตั้งค่า templateLock เป็นเท็จ
วิธีหนึ่งคือการสร้างบล็อกใหม่ที่ทำหน้าที่เป็นตัวห่อหุ้มสำหรับ InnerBlocks เราจะรวมบล็อกนั้นไว้ในเทมเพลตบล็อกหลักของเราและล็อกไว้ แต่จะปลดล็อกบล็อกตัวตัดคำของเราอย่างชัดเจนภายในโดยตั้งค่า ' templateLock ' เป็นเท็จ นอกจากนี้ เราอาจต้องการตรวจสอบให้แน่ใจว่าบล็อกตัวตัดพิเศษนี้มีให้ใช้งานภายในบล็อกหลักที่เราเลือกเท่านั้น โดยการตั้งค่าแม่สำหรับบล็อกของเรา เราสามารถอนุญาตให้บล็อกหลายประเภทภายในพื้นที่นั้นเสนอรายชื่อผู้แก้ไขและอื่นๆ ในขณะที่ยังอนุญาตเฉพาะส่วนหัว ปุ่ม และบล็อกตัวตัดของเราในบล็อกคำกระตุ้นการตัดสินใจหลัก
การล็อคบล็อกส่วนบุคคล
คุณสมบัติใหม่ใน WordPress 5.9 คือความสามารถในการล็อคบล็อกแต่ละบล็อกในเทมเพลต นี่เป็นอีกหนึ่งวิธีแก้ปัญหาที่เป็นไปได้สำหรับปัญหาที่ยืดหยุ่นแต่สอดคล้องกันของเรา
นี่คือลักษณะของเทมเพลตของเราเมื่อบล็อกบางบล็อกถูกล็อค:
<?php /** * ACF Call to Action example block template. * * More info: https://www.advancedcustomfields.com/resources/acf_register_block_type/ * * @param array $block The block settings and attributes. * @param string $content The block inner HTML (empty). * @param bool $is_preview True during AJAX preview. * @param (int|string) $post_id The post ID this block is saved to. * */ // Create id attribute allowing for custom "anchor" value. $block_ . $block['id']; if ( ! empty( $block['anchor'] ) ) { $block_id = $block['anchor']; } // Create class attribute allowing for custom "className" and "align" values. $class_name = 'acf-call-to-action-demo'; if ( ! empty( $block['className'] ) ) { $class_name .= ' ' . $block['className']; } if ( ! empty( $block['align'] ) ) { $class_name .= ' align' . $block['align']; } ?> <div class="<?php echo esc_html( $class_name ); ?>"> <div class="cta__inner"> <?php // Set up innerBlocks and provide a template. // Restrict InnerBlocks to allowed block list. $allowed_blocks = array( 'core/heading', 'core/paragraph', 'core/buttons' ); // Start InnerBlocks with a template. $template = array( array( 'core/heading', array( 'placeholder' => __( 'Heading', 'locale' ), 'align' => 'center', 'level' => '2', 'lock' => array( 'move' => true, // Block may nto be moved. 'remove' => true, // Block may not be removed. ), ), ), array( 'core/paragraph', array( 'placeholder' => __( 'Add CTA text here', 'locale' ), 'align' => 'center', ), ), array( 'core/buttons', array( 'placeholder' => __( 'Add CTA buttons here', 'locale' ), 'align' => 'center', 'lock' => array( 'move' => true, // Block may not be moved. 'remove' => true, // Block may not be removed. ), ), array( array( 'core/button', array( 'text' => __( 'Take action', 'locale' ), ), ), array( 'core/button', array( 'text' => __( 'Learn more', 'locale' ), ), ), ), ), ); // Echo out our JSX InnerBlocks compoennt for the editor. echo '<InnerBlocks allowedBlocks="' . esc_attr( wp_json_encode( $allowed_blocks ) ) . '" template="' . esc_attr( wp_json_encode( $template ) ) . '" />'; ?> </div> </div>
บล็อกส่วนหัวและปุ่มต่างๆ จะไม่สามารถย้ายหรือเอาออกได้อีกต่อไป อย่าลืมรีเฟรชเอดิเตอร์ นำออก แล้วเพิ่มบล็อกอีกครั้งเพื่อรับการเปลี่ยนแปลงเทมเพลต
โบนัส: สร้างบล็อกเดียวกันโดยกำเนิด
เมื่อคุณมีกระบวนการสร้างแล้ว การสร้างบล็อก WordPress แบบเนทีฟด้วย React นั้นง่ายอย่างน่าประหลาดใจและไม่แตกต่างจากการสร้างเทมเพลตบล็อกใน php การตั้งค่าสภาพแวดล้อมการพัฒนาบล็อกอยู่นอกเหนือขอบเขตของบทความนี้ แต่มีทรัพยากรจำนวนหนึ่งที่จะช่วยให้คุณเริ่มต้นได้ เช่น คู่มือ WordPress Block Editor Handbook เมื่อคุณรวมบล็อกแบบกำหนดเองได้แล้ว คุณจะสามารถสร้างบล็อกได้อย่างรวดเร็วโดยใช้ InnerBlocks
นี่คือตัวอย่างการเรียกร้องให้ดำเนินการบล็อก index.js ใน React คุณจะเห็นกลยุทธ์เดียวกันกับที่เรากล่าวถึงข้างต้นโดยใช้ ACF ที่นี่
import { __ } from '@wordpress/i18n'; import { registerBlockType } from '@wordpress/blocks'; import { InnerBlocks } from '@wordpress/block-editor'; import { useBlockProps } from '@wordpress/block-editor'; /** * Block Name. * Create an example Call to Action Block * Uses InnerBlocks for editable content within. */ export const blockName = 'call-to-action'; /** * Block Config. * Set basic params for controlling the editor. */ export const BLOCK_CONFIG = { // Set up the block template. CTA_TEMPLATE: [ [ 'core/heading', { placeholder: __('CTA Headline', 'locale'), align: 'center', level: 2, lock: { move: true, remove: true, }, }, ], [ 'core/paragraph', { placeholder: 'Optional CTA text', align: 'center', lock: { move: true, }, }, ], [ 'core/buttons', { lock: { move: true, remove: true, }, className: 'is-content-justification-center', align: 'center', // __experimentalLayout - https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/buttons/block.json layout: { type: 'flex', justifyContent: 'center', }, }, [ [ 'core/button', { text: 'Apply now', lock: { move: true, remove: true, }, }, ], ['core/button', { text: 'Learn more' }], ], ], ], // Set up the allowed blocks. ALLOWED_BLOCKS: ['core/paragraph', 'core/heading', 'core/buttons'], }; // Register the block via WP func. Change 'myplugin' to your plugin or theme. registerBlockType(`myplugin/${blockName}`, { title: __('Call to Action', 'locale'), // Change 'locale' to your locale for internationalization. description: __( 'Call to action block with headline and buttons', 'locale' ), keywords: [__('call'), __('action'), __('cta')], category: 'design', supports: { anchor: true, defaultStylePicker: false, html: false, align: false, }, attributes: { anchor: { type: 'string', default: '', }, }, transforms: {}, variations: [], edit: (props) => { const blockProps = useBlockProps({ className: `wp-block-myplugin-${blockName}`, }); return ( <div {...blockProps}> <div className="cta__inner"> <div className="cta__inner-blocks-wrapper"> <InnerBlocks template={BLOCK_CONFIG.CTA_TEMPLATE} allowedBlocks={BLOCK_CONFIG.ALLOWED_BLOCKS} renderAppender={false} /> </div> </div> </div> ); }, save: () => { return ( <div> <div className="cta__inner"> <InnerBlocks.Content /> </div> </div> ); }, });
ออกไปและสร้าง!
แหล่งข้อมูลเพิ่มเติม
- บทความของ Bill Erickson เกี่ยวกับ InnerBlocks
- บทความของ Bill Erickson ใน Block Editor
- คู่มือบล็อก ACF
- เอกสารประกอบ ACF Register Block Type
- คู่มือตัวแก้ไขบล็อก WordPress
- คู่มือ WordPress Block Editor: สร้างบทช่วยสอนการบล็อก