WordPressメニュー項目へのフィールドの追加–カスタムプラグイン

公開: 2021-05-19

前回の記事では、WordPress 5.4で導入されたwp_nav_menu_item_custom_fieldsアクションフックを使用して、独自のカスタムフィールドをメニュー項目に追加する方法について説明しました。 これを達成するための2つのルートを詳しく説明しました。 functions.php .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出力を変更せずに、メニュー項目のタイトル内にカスタムメニューフィールドを含めました。 しかし、字幕フィールドを、タイトル要素のリンクの外側にある<div>要素などの個別のHTML要素として追加したい場合はどうでしょうか。

ここで、Walkerクラスをもう一度使用する必要があります。 記事「WordPressWalkerクラスに慣れる」で見たように、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メニュー項目へのカスタムフィールドの追加