การเพิ่มฟิลด์ให้กับรายการเมนู WordPress – ปลั๊กอินแบบกำหนดเอง

เผยแพร่แล้ว: 2021-05-19

ในบทความที่แล้ว เราได้ดูวิธีที่คุณสามารถเพิ่มฟิลด์ที่กำหนดเองของคุณในรายการเมนูโดยใช้เบ็ดการดำเนินการ wp_nav_menu_item_custom_fields ที่เปิดตัวใน WordPress 5.4 เราให้รายละเอียดสองเส้นทางเพื่อให้บรรลุสิ่งนี้ โดยการเพิ่มโค้ดที่กำหนดเองลงใน functions.php หรือโดยใช้ปลั๊กอิน WordPress

ในบทความนี้ เราจะสร้างฟิลด์เดิมขึ้นมาใหม่ แต่คราวนี้เราจะสร้างปลั๊กอินขึ้นมาเองตั้งแต่ต้น

มาเริ่มกันเลย.

การสร้างปลั๊กอิน

เราจะไม่พูดถึงรายละเอียดพื้นฐานของการสร้างปลั๊กอิน WordPress เนื่องจากบทความนี้ได้กล่าวถึงในบทความเชิงลึกของเรา "วิธีสร้างปลั๊กอิน WordPress ตัวแรกของคุณ" คำแนะนำทีละขั้นตอน' เราจะข้ามไปข้างหน้าเพื่อสร้างโฟลเดอร์ปลั๊กอินของเราภายใต้โฟลเดอร์ wp-content/plugin/ ต่อไป เราจะตั้งชื่อโฟลเดอร์ปลั๊กอินแบบกำหนดเองของเราว่า “menu-item-field-creator” และภายในนั้นเราจะสร้างไฟล์ชื่อ menu-item-field-creator.php

หลังจากนี้ เราจะเปิดไฟล์นี้ด้วยโปรแกรมแก้ไขข้อความที่เราชื่นชอบ และเพิ่มโค้ดด้านล่าง รหัสนี้มีผลในการแนะนำปลั๊กอินให้กับแกนหลักของ WordPress

 <?php /* Plugin Name: Menu Item Field Creator Description: My custom plugin to create menu item fields */

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

เมื่อทำตามขั้นตอนเหล่านี้เสร็จแล้ว ไปที่ส่วนปลั๊กอินของเราในพื้นที่ผู้ดูแลระบบ และตรวจสอบว่าแสดงปลั๊กอินอย่างถูกต้องหรือไม่

ต่อไป เราจะแทรกโค้ดฟังก์ชันแรกของเราที่จะสร้างคลาสหลักและฟังก์ชันบางอย่าง

The Simple Way

วิธีที่ง่ายที่สุดในการทำให้ปลั๊กอินนี้ทำงานคือการแทรกโค้ดที่เราเขียนในบทความก่อนหน้าของเราลงในไฟล์ PHP หลักของปลั๊กอิน เพื่อให้เนื้อหาสุดท้ายมีลักษณะดังนี้:

 <?php /* Plugin Name: Menu Item Field Creator Description: My custom plugin to create menu item fields */ /** * Add the field. */ function pr_menu_item_sub( $item_id, $item ) { $menu_item_sub = get_post_meta( $item_id, '_menu_item_sub', true ); ?> <div> <span class="subtitle"><?php _e( 'Subtitle', 'menu-item-sub' ); ?></span><br /> <input type="hidden" class="nav-menu-id" value="<?php echo $item_id; ?>" /> <div class="logged-input-holder"> <input type="text" name="menu_item_sub[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $menu_item_sub ); ?>" /> </div> </div> <?php } add_action( 'wp_nav_menu_item_custom_fields', 'pr_menu_item_sub', 10, 2 ); /** * Save input. */ function save_menu_item_sub( $menu_id, $menu_item_db_id ) { if ( isset( $_POST['menu_item_sub'][ $menu_item_db_id ] ) ) { $sanitized_data = sanitize_text_field( $_POST['menu_item_sub'][ $menu_item_db_id ] ); update_post_meta( $menu_item_db_id, '_menu_item_sub', $sanitized_data ); } else { delete_post_meta( $menu_item_db_id, '_menu_item_sub' ); } } add_action( 'wp_update_nav_menu_item', 'save_menu_item_sub', 10, 2 ); /** * Show the Menu Field Value. */ function show_menu_item_sub( $title, $item ) { if ( is_object( $item ) && isset( $item->ID ) ) { $menu_item_sub = get_post_meta( $item->ID, '_menu_item_sub', true ); if ( ! empty( $menu_item_sub ) ) { $title .= '<p class="menu-item-sub">' . $menu_item_sub . '</p>'; } } return $title; } add_filter( 'nav_menu_item_title', 'show_menu_item_sub', 10, 2 );

ณ จุดนี้ หากคุณเปิดใช้งานปลั๊กอิน คุณจะพบว่ามันใช้งานได้ดี อย่างไรก็ตาม มีวิธีที่จะได้ผลลัพธ์เดียวกันโดยใช้รูปแบบการเข้ารหัสที่ต่างกัน

การใช้การเขียนโปรแกรมเชิงวัตถุ

เพื่อให้บรรลุผลลัพธ์เดียวกันในแนวทางเชิงวัตถุมากขึ้น ดังที่เราอธิบายไว้ในบทความที่เกี่ยวข้อง โปรดทำตามคำแนะนำด้านล่าง

ในการเริ่มต้น ให้ล้างเนื้อหาของไฟล์ PHP หลักของปลั๊กอินของคุณ ยกเว้นจากความคิดเห็นส่วนหัวและแทรกบรรทัดเหล่านี้:

 class MyCP_Menu_Item_Field_Creator { } $mycp_menu_item_field_creator = new MyCP_Menu_Item_Field_Creator();

สิ่งที่เราได้ทำกับโค้ดนี้จนถึงตอนนี้คือการกำหนดคลาส wrapper MyCP_Menu_Item_Field_Creator ที่จะมีฟังก์ชันการทำงานทั้งหมด สุดท้าย เรายกตัวอย่างวัตถุ

สิ่งสำคัญคือต้องจำไว้ว่าชื่อคลาสหลักที่คุณกำหนดจะพร้อมใช้งานทั่วโลก ดังนั้นคุณต้องตรวจสอบให้แน่ใจว่าชื่อนั้นไม่ซ้ำกัน และไม่มีโอกาสที่ปลั๊กอินหรือธีมอื่นจะใช้ชื่อเดียวกัน นั่นคือเหตุผลที่แนะนำให้คุณใช้คำนำหน้าแบบกำหนดเอง เช่น MyCP_ ที่เราใช้ด้านบน

ภายในชั้นเรียนตอนนี้เราจะเพิ่มฟังก์ชันการทำงานบางอย่าง เนื้อหาสุดท้ายของไฟล์ PHP หลักของปลั๊กอินจะมีลักษณะดังนี้:

 <?php /* Plugin Name: Menu Item Field Creator Description: My custom plugin to create menu item fields */ class MyCP_Menu_Item_Field_Creator { public function __construct() { add_action( 'wp_nav_menu_item_custom_fields', array( $this, 'menu_item_sub' ), 10, 2 ); add_action( 'wp_update_nav_menu_item', array( $this, 'save_menu_item_sub' ), 10, 2 ); add_action( 'nav_menu_item_title', array( $this, 'show_menu_item_sub' ), 10, 2 ); } public function menu_item_sub( $item_id, $item ) { $menu_item_sub = get_post_meta( $item_id, '_menu_item_sub', true ); ?> <div> <span class="subtitle"><?php _e( 'Subtitle', 'menu-item-sub' ); ?></span><br /> <input type="hidden" class="nav-menu-id" value="<?php echo $item_id; ?>" /> <div class="logged-input-holder"> <input type="text" name="menu_item_sub[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $menu_item_sub ); ?>" /> </div> </div> <?php } public function save_menu_item_sub( $menu_id, $menu_item_db_id ) { if ( isset( $_POST['menu_item_sub'][ $menu_item_db_id ] ) ) { $sanitized_data = sanitize_text_field( $_POST['menu_item_sub'][ $menu_item_db_id ] ); update_post_meta( $menu_item_db_id, '_menu_item_sub', $sanitized_data ); } else { delete_post_meta( $menu_item_db_id, '_menu_item_sub' ); } } public function show_menu_item_sub( $title, $item ) { if ( is_object( $item ) && isset( $item->ID ) ) { $menu_item_sub = get_post_meta( $item->ID, '_menu_item_sub', true ); if ( ! empty( $menu_item_sub ) ) { $title .= '<p class="menu-item-sub">' . $menu_item_sub . '</p>'; } } return $title; } } $mycp_menu_item_field_creator = new MyCP_Menu_Item_Field_Creator();

เราลบคำนำหน้าออกจากชื่อของเมธอด เนื่องจากตอนนี้เรามีคำนำหน้าคลาสแทนแล้ว

ในฟังก์ชัน __construct เรากำหนด hooks ที่เราใช้พร้อมกับฟังก์ชันเรียกกลับที่จะดำเนินการ ต่อไป เราแนะนำฟังก์ชันเรียกกลับของ menu_item_sub ซึ่งจะแสดงช่องป้อนข้อมูลที่ผู้ดูแลระบบสามารถกรอกคำบรรยายของรายการได้

หลังจากนี้ เราบันทึกอินพุตด้วยเมธอด save_menu_item_sub และสุดท้ายด้วยการโทรกลับ show_menu_item_sub เราจะแสดงค่าในเมนูส่วนหน้า หากมี

การขยายวอล์คเกอร์

ในตัวอย่างข้างต้น เราได้รวมฟิลด์เมนูแบบกำหนดเองไว้ภายในชื่อรายการเมนู โดยไม่เปลี่ยนแปลงเอาต์พุต HTML ของข้อมูลแผนผังเมนู แต่ถ้าเราต้องการเพิ่มช่องคำบรรยายเป็นองค์ประกอบ HTML ที่แยกจากกัน เช่น องค์ประกอบ <div> นอกลิงก์องค์ประกอบชื่อ

นี่คือที่ที่เราต้องทำงานอีกครั้งกับคลาส Walker ดังที่เราเห็นในบทความ 'การทำความคุ้นเคยกับ WordPress Walker Class' โดยการขยาย Walker คุณสามารถปรับแต่งโครงสร้างของข้อมูลที่เหมือนต้นไม้ได้ ในกรณีนี้จะเป็นเมนู

แน่นอนว่าเราต้องแก้ไขโค้ดที่เกี่ยวข้องกับการแสดงส่วนหน้าของฟิลด์ที่กำหนดเองเท่านั้น มาแทนที่รหัสทั้งหมดด้วยรหัสนี้:

 <?php /* Plugin Name: Menu Item Field Creator Description: My custom plugin to create menu item fields */ class MyCP_Menu_Item_Field_Creator { public function __construct() { add_action( 'wp_nav_menu_item_custom_fields', array( $this, 'menu_item_sub' ), 10, 2 ); add_action( 'wp_update_nav_menu_item', array( $this, 'save_menu_item_sub' ), 10, 2 ); add_filter( 'wp_nav_menu_args', array( $this, 'menu_item_sub_custom_walker' ) ); } public function menu_item_sub( $item_id, $item ) { $menu_item_sub = get_post_meta( $item_id, '_menu_item_sub', true ); ?> <div> <span class="subtitle"><?php _e( 'Subtitle', 'menu-item-sub' ); ?></span><br /> <input type="hidden" class="nav-menu-id" value="<?php echo $item_id; ?>" /> <div class="logged-input-holder"> <input type="text" name="menu_item_sub[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $menu_item_sub ); ?>" /> </div> </div> <?php } public function save_menu_item_sub( $menu_id, $menu_item_db_id ) { if ( isset( $_POST['menu_item_sub'][ $menu_item_db_id ] ) ) { $sanitized_data = sanitize_text_field( $_POST['menu_item_sub'][ $menu_item_db_id ] ); update_post_meta( $menu_item_db_id, '_menu_item_sub', $sanitized_data ); } else { delete_post_meta( $menu_item_db_id, '_menu_item_sub' ); } } public function menu_item_sub_custom_walker( $args ) { if ( class_exists( 'My_Custom_Nav_Walker' ) ) { $args['walker'] = new My_Custom_Nav_Walker(); } else { echo 'DOES NOT EXIST'; } return $args; } } $mycp_menu_item_field_creator = new MyCP_Menu_Item_Field_Creator(); if ( ! class_exists( 'My_Custom_Nav_Walker' ) ) { class My_Custom_Nav_Walker extends Walker_Nav_Menu { public function start_el( &$output, $item, $depth=0, $args=[], $id=0 ) { $menu_item_sub = get_post_meta( $item->ID, '_menu_item_sub', true ); $output .= '<li class="' . implode( ' ', $item->classes ) . '">'; if ( $item->url && $item->url != '#' ) { $output .= '<a href="' . $item->url . '">'; } else { $output .= '<span>'; } $output .= $item->title; if ( $item->url && $item->url != '#' ) { $output .= '</a>'; } else { $output .= '</span>'; } if ( ! empty( $menu_item_sub ) ) { $output .= '<div class="menu-item-sub">' . $menu_item_sub . '</div>'; } } } }

คุณอาจสังเกตเห็นว่าเราลบเมธอด show_menu_item_sub และทำงานกับโครงสร้างรายการเมนูส่วนหน้าแตกต่างกัน เราได้แนะนำคลาส Walker แบบกำหนดเอง My_Custom_Nav_Walker นอกคลาสหลักของเรา และด้วยเมธอด menu_item_sub_custom_walker เราเปลี่ยนค่าเริ่มต้นสำหรับอาร์กิวเมนต์ 'walker' เป็น My_Custom_Nav_Walker ด้วยวิธีนี้ เอาต์พุต HTML ของเมนูที่เราให้ไว้ใน Walker แบบกำหนดเองของเราจะนำไปใช้กับส่วนหน้าของเรา

มาตรวจสอบผลลัพธ์กัน

ดังที่เราเห็น คำอธิบายของเราในครั้งนี้ถูกวางไว้นอก href ของลิงก์รายการเมนูตามที่เราตั้งใจไว้

ก้าวต่อไป

ก่อนที่เราจะสรุปเรื่องนี้ ควรสังเกตว่าเราใช้ตัวอย่าง "คำบรรยาย" อย่างจงใจเพราะทำและเข้าใจได้ง่าย

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

เราจะให้ข้อมูลผลลัพธ์แก่คุณเพื่อเป็นคำแนะนำเบื้องต้น แทนที่วิธีการส่งออกปัจจุบัน (แสดงด้านล่าง)

 function menu_item_sub( $item_id, $item ) { $menu_item_sub = get_post_meta( $item_id, '_menu_item_sub', true ); ?> <div> <span class="subtitle"><?php _e( 'Subtitle', 'menu-item-sub' ); ?></span><br /> <input type="hidden" class="nav-menu-id" value="<?php echo $item_id; ?>" /> <div class="logged-input-holder"> <input type="text" name="menu_item_sub[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $menu_item_sub ); ?>" /> </div> </div> <?php }

ด้วยสิ่งนี้:

 function PREFIX_Menu_Item_Roles() { global $wp_roles; $display_roles = apply_filters( 'nav_menu_roles', $wp_roles->role_names ); if ( ! $display_roles ) return; ?> <p class="field-nav_menu_logged_in_out nav_menu_logged_in_out nav_menu_logged_in_out-thin"> <fieldset> <legend><?php _e( 'Display Mode', 'nav-menu-roles' ); ?></legend> <label for="edit-menu-item-role_logged_in"> <input type="radio" class="edit-menu-item-logged_in_out" value="in" name="menu-item-role_logged_in" /> <?php _e( 'Logged In Users', 'nav-menu-roles' ); ?><br/> </label> <label for="edit-menu-item-role_logged_out"> <input type="radio" class="edit-menu-item-logged_in_out" value="out" name="menu-item-role_logged_out" /> <?php _e( 'Logged Out Users', 'nav-menu-roles' ); ?><br/> </label> <label for="edit-menu-item-role_everyone"> <input type="radio" class="edit-menu-item-logged_in_out" value="" name="menu-item-role_everyone" /> <?php _e( 'Everyone', 'nav-menu-roles' ); ?><br/> </label> </fieldset> </p> <?php }

ตอนนี้ให้พยายามสร้างวิธีการที่บันทึกการเปลี่ยนแปลงพร้อมกับวิธีการแสดงค่าปัจจุบัน/ที่บันทึกไว้โดยใช้ hooks ที่ถูกต้อง

บทสรุป

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

ดูสิ่งนี้ด้วย

  • การเพิ่มฟิลด์ที่กำหนดเองให้กับรายการเมนู WordPress