Динамическое добавление пунктов меню с помощью wp_nav_menu_objects
В моей основной навигации я хочу, чтобы каждая страница верхнего уровня имела список своих подстраниц. Для этого я создал код, который динамически добавляет пункты меню в основную навигацию. Однако это работает только для подстраниц первого уровня. Вы можете видеть, что я закомментировал код, который обрабатывает второй уровень, потому что он выводил эти ссылки на основном уровне. Почему это не работает на втором уровне? Может быть, мы не можем назначить пункт меню динамически созданному родительскому элементу меню?
Код выглядит так:
add_filter( 'wp_nav_menu_objects', 'epc_wp_nav_menu_items', 10, 2 );
function epc_wp_nav_menu_items($items, $args) {
if ($args->theme_location == 'primary') {
$menu_order = 10000;
$menu_order2 = 20000;
global $wpdb;
global $post;
$post_id = 0;
if($post){
$post_id = $post->ID;
}
foreach($items as $item){
$pageChildren = $wpdb->get_results("SELECT post_title, ID FROM wp_posts WHERE post_parent = ".$item->object_id." AND post_status = 'publish' AND post_type='page' ORDER BY menu_order", 'OBJECT' );
foreach($pageChildren as $child){
$menu_order++;
$new_item = epc_add_menu_item($post_id, $menu_order, $item, $child);
$items[] = (object)$new_item;
/*
$pageChildrenSecondLevel = $wpdb->get_results("SELECT post_title, ID FROM wp_posts WHERE post_parent = ".$child->ID." AND post_status = 'publish' AND post_type='page' ORDER BY menu_order", 'OBJECT' );
foreach($pageChildrenSecondLevel as $child2){
$menu_order2++;
$new_item2 = epc_add_menu_item($post_id, $menu_order2, $new_item, $child2);
$items[] = (object)$new_item2;
}
*/
}
}
}
return $items;
}
function epc_add_menu_item($post_id, $menu_order, $item, $child){
$new_item = new stdClass;
$new_item->ID = $menu_order;
$new_item->menu_item_parent = $item->ID;
$new_item->url = get_permalink( $child->ID );
$new_item->title = $child->post_title;
$new_item->menu_order = $menu_order;
$new_item->object_id = $child->ID;
$new_item->post_parent = $item->object_id;
$classes = 'menu-item';
$classes .= ' menu-item-parent-' . $item->ID;
$classes .= ' menu-item-type-post_type';
$classes .= ' menu-item-object-page';
if($post_id == $child->ID){
$classes .= ' current-menu-item';
$classes .= ' page-item';
$classes .= ' page-item-' . $child->ID ;
$classes .= ' current_page_item';
}
$new_item->classes = $classes;
return $new_item;
}

Также необходимо указать поле db_id
для родительского пункта меню:
function epc_add_menu_item( $post_id, $menu_order, $item, $child ) {
...
$new_item->db_id = $menu_order;
...
}
Примечание: пункт меню, который имеет дочерние элементы, также должен иметь класс menu-item-has-children
.

Используйте этот пользовательский класс для отображения подменю:
class Wp_Sublevel_Walker extends Walker_Nav_Menu {
function start_lvl(&$output, $depth = 0, $args = array()) {
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul class='submenu'>\n";
}
function end_lvl(&$output, $depth = 0, $args = array()) {
$indent = str_repeat("\t", $depth);
$output .= "$indent</ul>\n";
}
}

Если ваши пользовательские пункты меню основаны на записях, рубриках или других объектах WordPress, вы можете использовать функцию wp_setup_nav_menu_item(WP_object) для получения объекта пункта меню.
$item=wp_setup_nav_menu_item(get_post());
Этот объект будет содержать большую часть корректно установленной информации, но не все данные будут присутствовать. Нам все еще нужно задать некоторые свойства для пункта. Необходимо указать родительский пункт меню, если вы хотите сделать его верхнего уровня - установите значение 0.
$item->menu_item_parent = $parentitem->ID;
Чтобы пункт мог иметь дочерние элементы, нужно назначить db_id, но ЭТО ДОЛЖЕН БЫТЬ ID объекта WordPress, с другими значениями это не работает (по крайней мере, у меня не получилось). Поэтому нам нужно установить это:
$item->db_id = get_the_ID();
Если текущий пункт будет иметь дочерние элементы, добавьте menu-has-children
в переменную classes. Обратите внимание, я также добавляю другие (css)классы, необходимые для моей темы.
$item->classes = array("menu-item", "menu-item-type-post_type", "menu-item-object-page", "menu-item-has-children");
Вы можете создать свой собственный элемент, создав пункт, как описано выше, а затем изменив $item->title
и $item->url
, сохраняя при этом ID. Просто убедитесь, что ID уникален на уровне меню (я не проверял, должен ли он быть уникальным во всем меню).
(Для тех, кто, как и я, нашел эту тему при попытке создать пользовательское меню: Порядок пунктов меню должен быть таким, чтобы родительский элемент непосредственно предшествовал своим дочерним элементам.)
