สร้างประสบการณ์การแก้ไข WordPress ที่ยอดเยี่ยมและประหยัดเวลาด้วย Gutenberg InnerBlocks

เผยแพร่แล้ว: 2023-02-12

อย่าทำซ้ำตัวเอง

สำหรับนักพัฒนา ความเกียจคร้านอาจเป็นคุณงามความดี ส่วนประกอบที่ทำขึ้นอย่างดีและใช้ซ้ำได้ช่วยประหยัดเวลาและช่วยให้สามารถใช้ซ้ำได้อย่างมีประสิทธิภาพและสม่ำเสมอ สิ่งนี้ช่วยสร้างประสบการณ์การแก้ไขใน WordPress ได้ดี เนื่องจากความสม่ำเสมอทำให้เกิดความคุ้นเคยและความรู้สำหรับผู้ที่ใช้เว็บไซต์ในแต่ละวัน

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

ใส่ InnerBlocks

InnerBlocks เป็นฟีเจอร์ที่ยอดเยี่ยมในตัวแก้ไข WordPress นักพัฒนาสามารถใช้บล็อกหลัก เช่น ย่อหน้า หัวเรื่อง และปุ่มเพื่อสร้างประสบการณ์ที่สอดคล้องกันสำหรับลูกค้า แทนที่จะเขียนส่วนข้อความใหม่และประกาศฟิลด์ใหม่ ลูกค้าจะได้รับประสบการณ์ที่พวกเขาคุ้นเคย แก้ไขและรวมบล็อกเดียวกัน มาดูบล็อกที่เราอาจต้องสร้างสำหรับลูกค้า และดูว่า InnerBlocks ช่วยให้เราบรรลุเป้าหมายได้อย่างไร

สร้างบล็อกด้วย InnerBlocks

ตัวอย่างการบล็อกคำกระตุ้นการตัดสินใจที่มีลิงก์พาดหัว ย่อหน้า และปุ่ม
รูป: ตัวอย่าง Call to Action Block ซึ่งรวมถึงพาดหัว ย่อหน้า และลิงก์ปุ่มบางปุ่ม

ลองพิจารณาบล็อกนี้และพิจารณาว่าเราจะสร้างบล็อกนี้ได้อย่างไร เครื่องมือทั่วไปที่เราเข้าถึงเมื่อสร้างบล็อกคือ 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 เราจะพูดถึงการล็อคบล็อกมากขึ้น

เรามีบล็อกใหม่! หลังจากนั้น และแน่นอนว่าสไตล์บางอย่าง บล็อกตัวอย่างในเครื่องมือแก้ไขจะมีลักษณะดังนี้:

บล็อกคำกระตุ้นการตัดสินใจที่เลือกบล็อกหัวข้อไว้
รูปภาพ: Call to Action Block ในเอดิเตอร์ เลือกบล็อกหัวเรื่องแล้ว

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: สร้างบทช่วยสอนการบล็อก