向 WordPress 菜單項添加字段 – 自定義插件

已發表: 2021-05-19

在上一篇文章中,我們研究瞭如何使用 WordPress 5.4 中引入的wp_nav_menu_item_custom_fields操作掛鉤將自己的自定義字段添加到菜單項。 我們詳細介紹了實現這一目標的兩條途徑; 通過將一些自定義代碼添加到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 */

您可能會注意到,我們定義了插件名稱和描述,因為我們希望它們顯示在管理插件區域中。 為了這個例子,我們不會定義任何其他的頭字段。

完成這些步驟後,讓我們前往管理區域中的插件部分並檢查插件是否正確顯示。

接下來,我們將插入我們的第一個函數代碼,它將建立我們的主類和一些函數。

簡單的方法

讓這個插件工作的最簡單方法是將我們在上一篇文章中編寫的代碼插入到插件的主 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();

到目前為止,我們對這段代碼所做的是定義將包含整個功能的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函數中,我們定義了我們使用的鉤子以及它們將執行的回調函數。 接下來我們介紹了menu_item_sub回調函數,它將顯示管理員用戶可以填寫項目副標題的輸入字段。

在此之後,我們使用save_menu_item_sub方法保存輸入,最後,使用show_menu_item_sub回調,我們在前端菜單中顯示值(如果可用)。

擴展步行者

在上面的示例中,我們在菜單項標題中包含了自定義菜單字段,而沒有更改菜單樹數據的 HTML 輸出。 但是,如果我們想將副標題字段添加為單獨的 HTML 元素,例如標題元素鏈接之外的<div>元素,該怎麼辦?

這是我們必須再次與 Walker 類一起工作的地方。 正如我們在文章“熟悉 WordPress Walker 類”中所見,通過擴展 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 。 這樣,我們在自定義 Walker 中提供的菜單 HTML 輸出將應用於我們的前端。

讓我們檢查一下結果。

正如我們所看到的,我們這次的描述按照我們的意圖放在了菜單項鍊接的 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 }

現在嘗試創建一種方法來保存更改以及使用正確掛鉤顯示當前/保存值的方法。

結論

在您了解可用於執行此操作的工具之前,自定義 WordPress 菜單可能會令人沮喪。 希望本文能讓您深入了解可能實現的目標以及實現此類任務的方法。

也可以看看

  • 向 WordPress 菜單項添加自定義字段