Многоуровневая навигация — важный элемент удобства пользования сайтом на WordPress. В этой статье рассмотрим, как самостоятельно создать кастомное многоуровневое меню с помощью PHP и встроенных функций WordPress, без использования плагинов. Это позволит гибко управлять выводом меню, адаптировать его под любые задачи и снизить нагрузку, исключив лишние расширения.
Зачем создавать многоуровневое меню в WordPress через код
Стандартный функционал WordPress позволяет создавать меню в административной панели, но вывод и стилизация зависят от темы и могут быть ограничены. Если нужно тонко настроить структуру, добавить динамические элементы или изменить HTML-разметку, то лучше написать собственный код вывода меню.
Кодовое решение даст следующие преимущества:
- Контроль над HTML-разметкой и CSS-классами
- Динамическое добавление пунктов меню, например, категорий или пользовательских ссылок
- Оптимизация под конкретные задачи и дизайн сайта
- Минимизация зависимостей от сторонних плагинов
Создаем функцию вывода многоуровневого меню
Для начала создадим функцию wpcontent_render_menu, которая будет выводить меню рекурсивно, обрабатывая все уровни вложенности. Используем стандартную функцию WordPress wp_get_nav_menu_items для получения всех пунктов меню.
function wpcontent_render_menu($menu_name, $parent_id = 0) {
$locations = get_nav_menu_locations();
if (!isset($locations[$menu_name])) {
echo '<!-- Меню не найдено -->';
return;
}
$menu = wp_get_nav_menu_object($locations[$menu_name]);
$menu_items = wp_get_nav_menu_items($menu->term_id);
if (!$menu_items) {
echo '<!-- Нет пунктов меню -->';
return;
}
// Фильтруем пункты по родительскому ID
$items = array_filter($menu_items, function($item) use ($parent_id) {
return intval($item->menu_item_parent) === $parent_id;
});
if (!empty($items)) {
echo '<ul class="wpcontent-menu">';
foreach ($items as $item) {
$has_children = count(array_filter($menu_items, function($child) use ($item) {
return intval($child->menu_item_parent) === intval($item->ID);
})) > 0;
echo '<li class="wpcontent-menu-item'.($has_children ? ' has-children' : '').'">';
echo '<a href="'.esc_url($item->url).'">'.esc_html($item->title).'</a>';
if ($has_children) {
wpcontent_render_menu($menu_name, intval($item->ID));
}
echo '</li>';
}
echo '</ul>';
}
}
Вызов функции для вывода меню будет выглядеть так:
wpcontent_render_menu('primary'); // где 'primary' – локация меню в вашей теме
Добавляем поддержку кастомных CSS-классов и активного пункта
Для улучшения UX и стилизации полезно выделять текущую страницу и добавлять классы, заданные в админке меню. Внесем изменения в функцию:
function wpcontent_render_menu($menu_name, $parent_id = 0) {
$locations = get_nav_menu_locations();
if (!isset($locations[$menu_name])) {
echo '<!-- Меню не найдено -->';
return;
}
$menu = wp_get_nav_menu_object($locations[$menu_name]);
$menu_items = wp_get_nav_menu_items($menu->term_id);
if (!$menu_items) {
echo '<!-- Нет пунктов меню -->';
return;
}
$items = array_filter($menu_items, function($item) use ($parent_id) {
return intval($item->menu_item_parent) === $parent_id;
});
if (!empty($items)) {
echo '<ul class="wpcontent-menu">';
foreach ($items as $item) {
$classes = (array) $item->classes;
$has_children = count(array_filter($menu_items, function($child) use ($item) {
return intval($child->menu_item_parent) === intval($item->ID);
})) > 0;
if ($has_children) {
$classes[] = 'has-children';
}
if (in_array('current-menu-item', $classes) || in_array('current-menu-ancestor', $classes)) {
$classes[] = 'wpcontent-current';
}
$class_names = implode(' ', array_map('esc_attr', $classes));
echo '<li class="'. $class_names .'">';
echo '<a href="'.esc_url($item->url).'">'.esc_html($item->title).'</a>';
if ($has_children) {
wpcontent_render_menu($menu_name, intval($item->ID));
}
echo '</li>';
}
echo '</ul>';
}
}
Теперь вы сможете контролировать стили меню через CSS, используя классы has-children для пунктов с подменю и wpcontent-current для активного пункта.
Пример стилей для многоуровневого меню
Вот базовый пример CSS для горизонтального многоуровневого меню с выпадающими подменю:
.wpcontent-menu {
list-style: none;
margin: 0;
padding: 0;
display: flex;
}
.wpcontent-menu-item {
position: relative;
margin-right: 20px;
}
.wpcontent-menu-item a {
text-decoration: none;
padding: 10px 15px;
display: block;
color: #333;
}
.wpcontent-menu-item.has-children > ul {
display: none;
position: absolute;
top: 100%;
left: 0;
background: #fff;
box-shadow: 0 2px 5px rgba(0,0,0,0.15);
list-style: none;
padding: 0;
margin: 0;
min-width: 150px;
z-index: 999;
}
.wpcontent-menu-item.has-children:hover > ul {
display: block;
}
.wpcontent-menu-item.has-children > ul > li {
margin: 0;
}
.wpcontent-menu-item.has-children > ul > li > a {
padding: 8px 12px;
color: #555;
}
.wpcontent-current > a {
font-weight: bold;
color: #0073aa;
}
Динамическое меню с категориями и произвольными ссылками
Иногда требуется добавить в меню динамические пункты, например, последние категории блога или ссылки на популярные записи. Для этого можно расширить функцию, добавив параметры для динамических элементов.
function wpcontent_render_dynamic_menu($menu_name, $parent_id = 0, $add_categories = false) {
$locations = get_nav_menu_locations();
if (!isset($locations[$menu_name])) {
echo '<!-- Меню не найдено -->';
return;
}
$menu = wp_get_nav_menu_object($locations[$menu_name]);
$menu_items = wp_get_nav_menu_items($menu->term_id);
if (!$menu_items) {
echo '<!-- Нет пунктов меню -->';
return;
}
$items = array_filter($menu_items, function($item) use ($parent_id) {
return intval($item->menu_item_parent) === $parent_id;
});
echo '<ul class="wpcontent-menu">';
foreach ($items as $item) {
$classes = (array) $item->classes;
$has_children = count(array_filter($menu_items, function($child) use ($item) {
return intval($child->menu_item_parent) === intval($item->ID);
})) > 0;
if ($has_children) {
$classes[] = 'has-children';
}
if (in_array('current-menu-item', $classes) || in_array('current-menu-ancestor', $classes)) {
$classes[] = 'wpcontent-current';
}
$class_names = implode(' ', array_map('esc_attr', $classes));
echo '<li class="'. $class_names .'">';
echo '<a href="'.esc_url($item->url).'">'.esc_html($item->title).'</a>';
if ($has_children) {
wpcontent_render_dynamic_menu($menu_name, intval($item->ID), false);
}
echo '</li>';
}
// Добавим категории, если нужно
if ($add_categories && $parent_id === 0) {
$categories = get_categories(array('hide_empty' => true));
foreach ($categories as $cat) {
echo '<li class="category-item">';
echo '<a href="'.esc_url(get_category_link($cat->term_id)).'">'.esc_html($cat->name).'</a>';
echo '</li>';
}
}
echo '</ul>';
}
Такой подход позволит сочетать статические пункты из меню и динамические категории, например, в футере или боковой панели.
Использование плагина Clearfy Pro для оптимизации меню
Если вы хотите избавиться от лишних пунктов меню, ускорить загрузку и улучшить SEO, рекомендую обратить внимание на плагин Clearfy Pro. Этот плагин позволяет автоматически оптимизировать меню, удалять лишние параметры из ссылок и улучшать структуру для поисковых систем.
Clearfy Pro можно легко интегрировать с вашим кастомным меню, чтобы повысить качество навигации и производительность сайта.
Итоги и рекомендации по кастомизации меню
Создание многоуровневого меню в WordPress через код — отличное решение для разработчиков, желающих получить полный контроль над навигацией. Используя предложенную функцию wpcontent_render_menu, вы сможете:
- Выводить меню с любой глубиной вложенности
- Добавлять кастомные CSS-классы для гибкой стилизации
- Включать динамические элементы, например, категории
- Поддерживать адаптивность и улучшать UX
Рекомендую также изучить возможности стандартных функций WordPress, таких как wp_nav_menu с кастомными walker-классами, если нужно более сложное управление. Но для большинства задач предложенный подход даст хороший баланс простоты и расширяемости.