Как создать многоуровневую навигацию в WordPress с поддержкой AJAX

Многоуровневая навигация — одна из ключевых составляющих удобства для пользователей на сайте WordPress. В этом материале мы разберем, как создать кастомное многоуровневое меню с поддержкой подгрузки подменю через AJAX, чтобы снизить нагрузку на страницу и улучшить пользовательский опыт. Пример подходит для тем, которые требуют гибкой и динамичной структуры меню.

Почему стоит использовать AJAX в многоуровневой навигации WordPress

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

  • Увеличению времени загрузки страницы;
  • Перегрузке HTML и ухудшению SEO;
  • Потере удобства навигации на мобильных устройствах.

Использование AJAX позволяет загружать подменю по требованию — при клике на пункт верхнего уровня. Это значительно улучшает производительность и UX.

Создание многоуровневого меню с AJAX: подготовка и регистрация меню

Для начала зарегистрируем меню в functions.php. Пусть это будет меню с названием «Основное меню».

function wpbuy_register_main_menu() {
    register_nav_menu('wpbuy_main_menu', __('Основное меню'));
}
add_action('after_setup_theme', 'wpbuy_register_main_menu');

Теперь добавим вывод меню в тему, используя кастомный Walker для поддержки AJAX.

Создание кастомного Walker для меню

Walker позволяет нам изменить HTML структуру меню. В нашем случае нам нужно добавить атрибуты для элементов, которые имеют подменю, чтобы при клике запускать AJAX подгрузку.

class WPBuy_Ajax_Walker_Nav_Menu extends Walker_Nav_Menu {
    function start_lvl( &$output, $depth = 0, $args = null ) {
        $indent = str_repeat("\t", $depth);
        $submenu_class = ($depth === 0) ? 'sub-menu ajax-submenu' : 'sub-menu';
        $output .= "\n$indent<ul class='" . $submenu_class . "'>\n";
    }

    function start_el(  &$output, $item, $depth=0, $args=null, $id=0 ) {
        $has_children = in_array('menu-item-has-children', $item->classes);
        $classes = empty($item->classes) ? array() : (array) $item->classes;
        if ($has_children) {
            $classes[] = 'ajax-loadable';
        }
        $class_names = join(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item, $args));
        $class_names = $class_names ? ' class="' . esc_attr($class_names) . '"' : '';

        $output .= "<li" . $class_names . ">";
        $attributes = '';
        $attributes .= ' href="' . esc_attr($item->url) . '"';
        if ($has_children) {
            $attributes .= ' data-item-id="' . $item->ID . '"';
            $attributes .= ' class="ajax-toggle" href="#"';
        }

        $item_output = $args->before;
        $item_output .= '<a' . $attributes . '>' . apply_filters('the_title', $item->title, $item->ID) . '</a>';
        $item_output .= $args->after;

        $output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);
    }
}

Этот Walker добавляет класс ajax-toggle и data-атрибуты для элементов с подменю.

Обработка AJAX-запроса для подгрузки подменю

Создадим обработчик AJAX в functions.php, который по ID пункта меню вернет HTML подменю.

function wpbuy_ajax_load_submenu() {
    if ( ! isset($_POST['item_id']) || ! is_numeric($_POST['item_id']) ) {
        wp_send_json_error('Неверный ID пункта меню');
    }
    $item_id = intval($_POST['item_id']);

    $menu_locations = get_nav_menu_locations();
    if ( empty($menu_locations['wpbuy_main_menu']) ) {
        wp_send_json_error('Меню не найдено');
    }
    $menu = wp_get_nav_menu_object($menu_locations['wpbuy_main_menu']);
    $menu_items = wp_get_nav_menu_items($menu->term_id);
    if ( ! $menu_items ) {
        wp_send_json_error('Пункты меню не найдены');
    }

    $submenu_items = array_filter($menu_items, function($item) use ($item_id) {
        return $item->menu_item_parent == $item_id;
    });

    if ( empty($submenu_items) ) {
        wp_send_json_error('Подменю не найдено');
    }

    $output = '<ul class="sub-menu ajax-submenu-loaded">';
    foreach ($submenu_items as $item) {
        $has_children = false;
        foreach ($menu_items as $potential_child) {
            if ($potential_child->menu_item_parent == $item->ID) {
                $has_children = true;
                break;
            }
        }
        $classes = 'menu-item';
        if ($has_children) {
            $classes .= ' menu-item-has-children ajax-loadable';
        }
        $output .= '<li class="' . esc_attr($classes) . '">';
        $output .= '<a href="' . esc_attr($item->url) . '"';
        if ($has_children) {
            $output .= ' data-item-id="' . esc_attr($item->ID) . '" class="ajax-toggle"';
        }
        $output .= '>' . esc_html($item->title) . '</a>';
        $output .= '</li>';
    }
    $output .= '</ul>';

    wp_send_json_success($output);
}
add_action('wp_ajax_wpbuy_load_submenu', 'wpbuy_ajax_load_submenu');
add_action('wp_ajax_nopriv_wpbuy_load_submenu', 'wpbuy_ajax_load_submenu');

Подключение JavaScript для обработки кликов и AJAX-запросов

Чтобы меню работало динамично, нужно добавить скрипт, который будет перехватывать клики по пунктам с классом ajax-toggle, отправлять AJAX-запрос и вставлять подменю в DOM.

function wpbuy_enqueue_scripts() {
    wp_enqueue_script('wpbuy-ajax-menu', get_template_directory_uri() . '/js/wpbuy-ajax-menu.js', array('jquery'), '1.0', true);
    wp_localize_script('wpbuy-ajax-menu', 'wpbuy_ajax_object', array(
        'ajax_url' => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('wpbuy_ajax_nonce')
    ));
}
add_action('wp_enqueue_scripts', 'wpbuy_enqueue_scripts');

Создадим файл wpbuy-ajax-menu.js в папке js вашей темы:

jQuery(document).ready(function($) {
    $(document).on('click', 'a.ajax-toggle', function(e) {
        e.preventDefault();
        var link = $(this);
        var itemId = link.data('item-id');
        if (!itemId) return;

        // Проверяем, загружено ли уже подменю
        if (link.siblings('ul.ajax-submenu-loaded').length) {
            link.siblings('ul.ajax-submenu-loaded').slideToggle();
            return;
        }

        $.ajax({
            url: wpbuy_ajax_object.ajax_url,
            type: 'POST',
            data: {
                action: 'wpbuy_load_submenu',
                item_id: itemId,
                _ajax_nonce: wpbuy_ajax_object.nonce
            },
            beforeSend: function() {
                link.addClass('loading');
            },
            success: function(response) {
                if (response.success) {
                    link.after(response.data);
                    link.siblings('ul.ajax-submenu-loaded').hide().slideDown();
                } else {
                    alert('Ошибка загрузки подменю: ' + response.data);
                }
            },
            complete: function() {
                link.removeClass('loading');
            }
        });
    });
});

Улучшения и особенности реализации

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

2. Обработка ошибок: если подменю не найдено, показывать подсказку пользователю, а не просто alert.

3. Оптимизация CSS: стилизуйте подменю с учетом мобильных устройств, чтобы раскрытие было плавным и удобным.

4. Интеграция с плагинами: если используете, например, плагин Clearfy Pro, там есть функции для оптимизации меню и кеширования, что поможет дополнительно ускорить работу.

Итог

Создание многоуровневого меню с AJAX в WordPress — отличный способ улучшить UX и производительность сайта с большим количеством пунктов меню. Приведенный пример показывает базовую реализацию с кастомным Walker, обработкой AJAX и подключением скриптов. Развивайте данный подход, добавляя кеширование, анимации и поддержку мобильных устройств. Это даст вашим посетителям удобную и быструю навигацию без лишних загрузок.

Как добавить уникальные метаполя для продукта WooCommerce с примером кода
24.02.2026
Автоматическое удаление неактивных вариантов товаров в WooCommerce по расписанию
30.06.2026
Автоматическое удаление старых записей в WordPress через WP-Cron
08.03.2026
WooCommerce: как автоматически удалять неактивные варианты товаров
13.06.2026
WordPress: как избежать конфликтов между плагинами и быстро находить ошибки
23.12.2025