Программно добавить меню навигации и пункты меню

42

С помощью функций API я хочу определить новое меню навигации , выбрать его в текущей теме, а затем вставить несколько страниц в качестве элементов меню. Это должно быть сделано, например, при активации темы.

Посредством (умеренно болезненного) процесса обратного инжиниринга базы данных вставляются и обновляются после ручной настройки меню и элементов навигации, я собрал воедино следующие шаги, где «footer-nav» - идентификатор порции меню навигации I ». м создание:

if (!term_exists('footer-nav', 'nav_menu')) {

    $menu = wp_insert_term('Footer nav', 'nav_menu', array('slug' => 'footer-nav'));

    // Select this menu in the current theme
    update_option('theme_mods_'.get_current_theme(), array("nav_menu_locations" => array("primary" => $menu['term_id'])));

    // Insert new page
    $page = wp_insert_post(array('post_title' => 'Blog',
                                 'post_content' => '',
                                 'post_status' => 'publish',
                                 'post_type' => 'page'));

    // Insert new nav_menu_item
    $nav_item = wp_insert_post(array('post_title' => 'News',
                                     'post_content' => '',
                                     'post_status' => 'publish',
                                     'post_type' => 'nav_menu_item'));


    add_post_meta($nav_item, '_menu_item_type', 'post_type');
    add_post_meta($nav_item, '_menu_item_menu_item_parent', '0');
    add_post_meta($nav_item, '_menu_item_object_id', $page);
    add_post_meta($nav_item, '_menu_item_object', 'page');
    add_post_meta($nav_item, '_menu_item_target', '');
    add_post_meta($nav_item, '_menu_item_classes', 'a:1:{i:0;s:0:"";}');
    add_post_meta($nav_item, '_menu_item_xfn', '');
    add_post_meta($nav_item, '_menu_item_url', '');

    wp_set_object_terms($nav_item, 'footer-nav', 'nav_menu');
}

Это похоже на работу, но:

  • это надежный и элегантный способ сделать это?
  • я пропускаю что-то совершенно очевидное, что сделало бы все это в одной строке кода?
julien_c
источник

Ответы:

43

Я мог бы неправильно понять вас, но почему бы не использовать wp_create_nav_menu()?

Например, это то, что я делаю, чтобы создать пользовательское меню BuddyPress, когда я обнаруживаю, что BP активен:

    $menuname = $lblg_themename . ' BuddyPress Menu';
$bpmenulocation = 'lblgbpmenu';
// Does the menu exist already?
$menu_exists = wp_get_nav_menu_object( $menuname );

// If it doesn't exist, let's create it.
if( !$menu_exists){
    $menu_id = wp_create_nav_menu($menuname);

    // Set up default BuddyPress links and add them to the menu.
    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' =>  __('Home'),
        'menu-item-classes' => 'home',
        'menu-item-url' => home_url( '/' ), 
        'menu-item-status' => 'publish'));

    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' =>  __('Activity'),
        'menu-item-classes' => 'activity',
        'menu-item-url' => home_url( '/activity/' ), 
        'menu-item-status' => 'publish'));

    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' =>  __('Members'),
        'menu-item-classes' => 'members',
        'menu-item-url' => home_url( '/members/' ), 
        'menu-item-status' => 'publish'));

    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' =>  __('Groups'),
        'menu-item-classes' => 'groups',
        'menu-item-url' => home_url( '/groups/' ), 
        'menu-item-status' => 'publish'));

    wp_update_nav_menu_item($menu_id, 0, array(
        'menu-item-title' =>  __('Forums'),
        'menu-item-classes' => 'forums',
        'menu-item-url' => home_url( '/forums/' ), 
        'menu-item-status' => 'publish'));

    // Grab the theme locations and assign our newly-created menu
    // to the BuddyPress menu location.
    if( !has_nav_menu( $bpmenulocation ) ){
        $locations = get_theme_mod('nav_menu_locations');
        $locations[$bpmenulocation] = $menu_id;
        set_theme_mod( 'nav_menu_locations', $locations );
    }
ZaMoose
источник
Я не знал об этой функции. Да, я думаю, что приведенный выше код будет намного короче. Думаю, мне следует выйти за рамки Кодекса и погрузиться в реальный код, поскольку я обнаружил, что функции API часто, как в этом случае, слишком низкоуровневые. Благодарность!
julien_c
@julien_c, если это будет решено, отметьте это как таковое, чтобы позволить тем, кто придет после вас, воспользоваться вашим опытом здесь.
mor7ifer
Я просто хочу на самом деле проверить это в реальной жизни, поэтому я уверен, что он делает то, что я хочу. Я не забуду отметить это как решенное, как только я закончу!
julien_c
3
Если вы видите такие полезные функции, которых нет в кодексе, было бы неплохо добавить их (yay wiki) = p
Tom J Nowell
Извините, что мне потребовалось так много времени, чтобы проверить, что это работает в моем случае. Ответ принят! Кроме того, вы определяете пользовательские элементы меню ссылок , я добавил ответ ниже, чтобы определить ссылки на страницы (например, которые будут более устойчивы к изменениям URL).
julien_c
12

В качестве дополнения к ответу ZaMoose, вот как вы можете создать пункт меню «Тип страницы » (не « Пользовательский »):

wp_update_nav_menu_item($menu_id, 0, array('menu-item-title' => 'About',
                                           'menu-item-object' => 'page',
                                           'menu-item-object-id' => get_page_by_path('about')->ID,
                                           'menu-item-type' => 'post_type',
                                           'menu-item-status' => 'publish'));

Предполагая, что вы знаете только слаг страницы, например.

julien_c
источник
9

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

Во-первых, приведенный выше код создает элементы навигации типа «URL», что хорошо для некоторых людей, но я хочу ссылаться на страницы, а не на URL, потому что это важная функция навигации WordPress, и клиенты неизбежно перемещают объекты, поэтому я никогда не использую URL тип элемента навигации.

Кроме того, размещенный код обрабатывает только плоский массив детей. Я создал функцию для рекурсивного объявления новых элементов навигации, сохранения их возвращенных метаданных (в основном идентификатора после создания в цикле) и параметра для принятия дочерних элементов.

Просто отредактируйте, $nav_items_to_addа остальное обрабатывается рекурсивно. В каждом массиве есть 3 обязательных ключа. Во-первых, ключ массива - это слаг, так же 'shop' => array( ... )как и то, что вы хотите для страницы с слагом shop. ['title']это способ, которым элемент навигации будет помечен на передней части. pathэто путь к странице в иерархии страниц WordPress, так что он идентичен слагу, если страница является родительским shopэлементом верхнего уровня, и если бы он был потомком, homeто это было бы 'path' => 'home/shop'.

Последний необязательный ключ массива - это место, ['parent']где вы можете объявить другой ключ в массиве как родительский для текущего. Важно отметить, что элементы добавляются рекурсивно, поэтому родительский элемент должен существовать до того, как вы попытаетесь создать дочерний элемент. Это означает, что объявление должно произойти для родительского элемента nav, прежде чем он станет дочерним.

    $locations = get_nav_menu_locations();

    if (isset($locations['primary_navigation'])) {
        $menu_id = $locations['primary_navigation'];

        $new_menu_obj = array();

        $nav_items_to_add = array(
                'shop' => array(
                    'title' => 'Shop',
                    'path' => 'shop',
                    ),
                'shop_l2' => array(
                    'title' => 'Shop',
                    'path' => 'shop',
                    'parent' => 'shop',
                    ),
                'cart' => array(
                    'title' => 'Cart',
                    'path' => 'shop/cart',
                    'parent' => 'shop',
                    ),
                'checkout' => array(
                    'title' => 'Checkout',
                    'path' => 'shop/checkout',
                    'parent' => 'shop',
                    ),
                'my-account' => array(
                    'title' => 'My Account',
                    'path' => 'shop/my-account',
                    'parent' => 'shop',
                    ),
                'lost-password' => array(
                    'title' => 'Lost Password',
                    'path' => 'shop/my-account/lost-password',
                    'parent' => 'my-account',
                    ),
                'edit-address' => array(
                    'title' => 'Edit My Address',
                    'path' => 'shop/my-account/edit-address',
                    'parent' => 'my-account',
                    ),
            );

    foreach ( $nav_items_to_add as $slug => $nav_item ) {
        $new_menu_obj[$slug] = array();
        if ( array_key_exists( 'parent', $nav_item ) )
            $new_menu_obj[$slug]['parent'] = $nav_item['parent'];
        $new_menu_obj[$slug]['id'] = wp_update_nav_menu_item($menu_id, 0,  array(
                'menu-item-title' => $nav_item['title'],
                'menu-item-object' => 'page',
                'menu-item-parent-id' => $new_menu_obj[ $nav_item['parent'] ]['id'],
                'menu-item-object-id' => get_page_by_path( $nav_item['path'] )->ID,
                'menu-item-type' => 'post_type',
                'menu-item-status' => 'publish')
        );
    }

    }
Брайан
источник
2

Добавить пункт меню программно. Вы можете подключиться к wp_nav_menu_itemsфильтру. поместите ниже код в вашей теме functions.php, чтобы добавить пункт меню входа / выхода в главном меню. «Основной» - это имя / идентификатор зарегистрированного меню.

/**
 * Add login logout menu item in the main menu.
 * ===========================================
 */

add_filter( 'wp_nav_menu_items', 'lunchbox_add_loginout_link', 10, 2 );
function lunchbox_add_loginout_link( $items, $args ) {
    /**
     * If menu primary menu is set & user is logged in.
     */
    if ( is_user_logged_in() && $args->theme_location == 'primary' ) {
        $items .= '<li><a href="'. wp_logout_url() .'">Log Out</a></li>';
    }
    /**
     * Else display login menu item.
     */
    elseif ( !is_user_logged_in() && $args->theme_location == 'primary' ) {
        $items .= '<li><a href="'. site_url('wp-login.php') .'">Log In</a></li>';
    }
    return $items;
}
Аамер Шахзад
источник