Добавление полей в пункты меню 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 */

Как вы могли заметить, мы определили имя и описание плагина, поскольку мы хотим, чтобы они отображались в области плагина администратора. Ради этого примера мы не будем определять какое-либо другое поле заголовка.

Выполнив эти шаги, давайте перейдем в раздел «Плагины» в области администратора и проверим, правильно ли отображается плагин.

Далее мы вставим наш первый функциональный код, который установит наш основной класс и некоторые функции.

Простой способ

Самый простой способ заставить этот плагин работать — вставить код, который мы написали в нашей предыдущей статье, в основной 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 . Таким образом, 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 }

Теперь попробуйте создать метод, который сохраняет изменения вместе с тем, который отображает текущее/сохраненное значение, используя правильные хуки.

Вывод

Настройка меню WordPress может быть неприятной, пока вы не узнаете об инструментах, доступных для этого. Надеюсь, эта статья дала вам некоторое представление о том, чего можно достичь, и о том, как вы можете реализовать такие задачи.

Смотрите также

  • Добавление настраиваемых полей в пункты меню WordPress