Многоуровневая навигация — одна из ключевых составляющих удобства для пользователей на сайте 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 и подключением скриптов. Развивайте данный подход, добавляя кеширование, анимации и поддержку мобильных устройств. Это даст вашим посетителям удобную и быструю навигацию без лишних загрузок.