Как сделать пункт меню верхнего уровня без ссылки, но с связанными подменю?
Я создаю горизонтальное меню, и некоторые пункты этого меню будут иметь выпадающие списки (подменю), а некоторые нет. Те пункты, которые имеют подменю, на самом деле не являются страницами. Они предназначены только для организации выпадающих списков.
Например, допустим, горизонтальное меню выглядит следующим образом:
Главная | О нас | Продукты | Направления | Контакты
И пункт меню "продукты" должен иметь 3 связанные страницы в вертикальном выпадающем списке под ним, поэтому сам "продукты" фактически не представляет страницу, как это можно реализовать в WordPress?
(Я использую WordPress как CMS, со статической главной страницей и внутренними страницами. Я создаю собственные шаблоны, стилизую меню в CSS, затем регистрирую меню в functions.php и вызываю их в шаблонах.) В WordPress вы добавляете записи в меню через список страниц или через произвольные ссылки. Но я не хочу, чтобы "продукты" были со ссылкой. Если я не добавлю ссылку в произвольную ссылку, система не позволит мне добавить её в меню.
Можно ли это сделать через административную панель меню или нужно использовать другой подход?
Спасибо за любую помощь!

Самый простой способ сделать это без плагинов — использовать функцию "Меню" в WordPress. Вот инструкция для WordPress 4.8:
- В админке WordPress перейдите в раздел "Внешний вид → Меню"
- Во вкладке "Редактировать меню" выберите "Произвольные ссылки"
- В поле "URL" введите "#" (без кавычек)
- В поле "Текст ссылки" введите желаемый текст для верхнего уровня выпадающего меню
- Нажмите кнопку "Добавить в меню"
- Перетащите пункт меню в нужное положение внутри вашего меню
- Для только что добавленного пункта меню нажмите на стрелку вниз справа от пункта (слева от него будет написано "произвольная ссылка")
- Удалите символ "#" из URL. Это преобразует ссылку в обычный текст во всех браузерах.
- Нажмите кнопку "Сохранить меню"

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

Ты прочитал весь комментарий? После добавления ссылки нажми на стрелку выпадающего списка рядом с именем ссылки и удали "#" из текстового поля URL. Это во всех браузерах сделает ссылку некликабельной.

Да, спасибо, я прочитал весь комментарий. Я вернулся и попробовал снова, и понял свою проблему. Когда я оставляю #, слово появляется в навигационной панели, но как "мертвая ссылка". Когда я удалил #, слово не отображалось в навигационной панели, пока я не навел на него курсор, и тогда оно появлялось в состоянии наведения. Так что я предполагаю, что мне нужно применить CSS к этому слову, чтобы оно отображалось без привязки к ссылке. Не уверен, почему появляется состояние наведения...

Это всё ещё актуально в версии 4.9.5, однако я не уверен, так как это больше похоже на хак, использующий баг. Если это не так... это избавит многих от головной боли... Это чем-то похоже на то, что WordPress считает "1 2 3 4 5 6" надёжным паролем... до сих пор.

К вашему сведению, если вы выполните Шаг 8 (по какой-то веской причине), то курсор не будет превращаться в указатель при наведении на пользовательскую ссылку. В этом случае вы можете стилизовать его с помощью pointer:cursor.

У меня есть несколько идей:
- Установить пользовательскую ссылку на
#
, которая ничего не возвращает - Добавить пользовательский класс к элементам, а затем использовать jQuery для удаления ссылок.
- Использовать PHP-эквивалент метода jQuery
- Использовать плагин Disable Parent Menu Link (или разобрать его и написать свой собственный)

Спасибо за советы и ссылки! Как предложил Гэвин, использование # для пользовательской ссылки "работает"; другие варианты могут работать лучше, но они не такие простые. Ну, плагин, вероятно, простой, но я не люблю использовать плагины, если могу добиться того же более прямым способом. Мне придётся выбрать лучший подход. Ещё раз спасибо!

Если вы планируете использовать это на тактильных устройствах, будьте осторожны с использованием пустого href=""
, потому что большинство пользователей тактильных устройств не смогут увидеть выпадающее меню без использования JS

Ссылки ломаются. Возможно, вам стоит включить некоторые из этих идей в свой ответ

Самый простой метод, который я придумал, — это создать пункт меню "Произвольная ссылка" со значением URL-адреса #
. Это отправляет пользователя к пустому хэшу на той же странице, то есть фактически никуда не ведет.
Однако у использования пустых хэшей для заглушек ссылок есть побочные эффекты. Ссылка все равно будет отображаться и вести себя как ссылка, что может сбить пользователя с толку, когда он кликает на то, что выглядит как ссылка, но ничего не происходит. Другой эффект заключается в том, что клик по ссылке с пустым хэшем перезапишет любой существующий хэш, отправляя пользователя в начало страницы. Это может быть не так критично для меню, которое и так находится вверху страницы, но довольно раздражает, когда страница неожиданно прыгает, особенно если это меню в подвале сайта.
Решение — комбинировать метод с пустым хэшем с фрагментом кода, который обнаруживает такие ссылки в меню и полностью удаляет атрибут href
из этих ссылок. Элемент a
без атрибута href
— это правильный метод в HTML 5 для создания заглушки ссылки.
/**
* Удаляет атрибут href из пустых ссылок `<a href="#">` в навигационных меню
* @param string $menu текущий HTML меню
* @return string измененный HTML меню
*/
add_filter( 'wp_nav_menu_items', function ( $menu ) {
return str_replace( '<a href="#"', '<a', $menu );
} );

Это сработало для меня:
Я активировал CSS Классы в разделе Меню > Настройки экрана > CSS Классы. Затем я назначил элементу меню, который хотел деактивировать, класс ".nolink" и добавил этот код в панель пользовательского CSS:
.nolink {
pointer-events: none; /* Отключает события мыши */
cursor: default; /* Устанавливает курсор по умолчанию */
}

Использование #
в качестве цели ссылки с последующим применением пользовательского CSS-класса для стилизации, на мой взгляд, является наименее костыльным решением. Однако установка pointer-events: none
не кажется мне логичной, так как это сломает подменю. Не могли бы вы пояснить, зачем вы установили этот атрибут?

Хотя это старая тема, но быстрый и простой способ создания ссылки в WordPress — указать URL ссылки как:
#_
Обратите внимание на подчеркивание после хэштега. Таким образом, если ваше меню фиксировано и прокручивается вместе со страницей, при клике на ссылку не будет прыжка в начало страницы, и для этого не потребуются плагины или скрипты.

Используя PHP подход, я добавил этот код в functions.php:
function remove_link_contact_menu($item_output, $item) {
if ($item->post_name == 'contact')
return '<span>' . $item->title . '</span>';
return $item_output;
}
add_filter('walker_nav_menu_start_el', 'remove_link_contact_menu', 20, 2);
add_filter('megamenu_walker_nav_menu_start_el', 'remove_link_contact_menu', 20, 2);
Этот код заменяет ссылку на элемент span для пункта меню с post_name == "contact", что мне и было нужно. Вы можете легко изменить это условие для проверки заголовка меню или ID, или добавить код для проверки наличия дочерних пунктов меню и т.д.

- Установите пользовательскую ссылку на #, которая ничего не возвращает (элемент списка)
Добавьте этот фильтр:
add_filter( 'wp_nav_menu_items', 'wpse_remove_empty_links' ); function wpse_remove_empty_links( $menu ) { return preg_replace("/<a href=\"#\">(.+?)<\/a>/is", "<span>$1</span>", $menu); }
Отредактируйте CSS для элемента
<span>
, чтобы получить такой же стиль как у<a>
, не забудьте добавитьcursor: context-menu;
.

Это отключит клик (и уберет стилизацию элемента). Таким образом, вам не нужно использовать кастомные # ссылки в вашем меню.
add_action( 'wp_footer', function(){
?>
<script>
(function( $ ) {
var itemm = $('#main-menu .menu-item-has-children > a');
itemm.click(function(){
document.activeElement && document.activeElement.blur();
return false;
});
})(jQuery);
</script>
<?php
}, 1, 0 );

Как уже предлагали другие участники, вы можете создать пользовательский пункт меню в виде ссылки с символом # в качестве URL. Затем удалите # после добавления пункта в меню. И наконец, можно использовать простое регулярное выражение для удаления тега <a> из таких ссылок.
preg_replace('/<a>([^<]+)<\/a>/i', '<span class="no-link">$1</span>', $navHTML);

Я понимаю, что немного запоздал с этим, но вот два метода, которые я использую:
1) Сделать родительский пункт меню дубликатом первого подпункта и изменить его название. Например, если первый пункт в разделе "Продукты" — это "Продукт 1", используйте "Продукт 1" в качестве родительского пункта меню, а затем измените его название на "Продукты". Таким образом, и "Продукты", и "Продукт 1" будут вести на страницу Продукт 1.
2) Добавить редирект, чтобы страница "Продукты" перенаправляла на "Продукт 1". Преимущество этого варианта в том, что он позволяет создать пустую страницу "Продукты" для иерархического списка в разделе "Страницы", но если кто-то попытается перейти на пустую страницу "Продукты", его автоматически перенаправит.

Я решил это следующим образом: в файле header.php (вашей темы) я нашел:
'link_before' => '',
'link_after' => '',
и заменил на:
'link_before' => '<script>var scriptTag=document.getElementsByTagName("script");scriptTag=scriptTag[scriptTag.length-1];if(scriptTag.parentNode.href)if(scriptTag.parentNode.href.slice(-1)=="#")document.write("<span onclick=\"return false\">")</script>',
'link_after' => '<script>var scriptTag=document.getElementsByTagName("script");scriptTag=scriptTag[scriptTag.length-1];if(scriptTag.parentNode.href)if(scriptTag.parentNode.href.slice(-1)=="#")document.write("</span>")</script>',
Простыми словами, этот скрипт проверяет, заканчивается ли родительская ссылка на "#", и в этом случае добавляет элемент span вокруг содержимого тега A, что отключает клик.
Надеюсь, это поможет :-)

Привет, я знаю, что это старый ответ, но на будущее: я бы не рекомендовал просто изменять файл заголовка вашей темы, потому что при следующем обновлении все ваши изменения будут перезаписаны. Лучшее решение в этом случае — создать дочернюю тему с вашим пользовательским кодом.

Начиная с 1/2019, правильное решение для создания валидного HTML5 выглядит следующим образом.
- Добавьте "Пользовательскую ссылку" (Custom Link) с URL, установленным в #, и любым названием. Оба поля обязательны для заполнения.
- Отредактируйте только что добавленную ссылку, оставив поле URL пустым.
- Сохраните изменения.
В результате получится навигационный элемент верхнего уровня в виде <a>Меню</a>
, что является правильным способом представления неактивной (некликабельной) ссылки.

Создайте пользовательскую ссылку в меню, как указано ранее. Просмотрите исходный код и найдите атрибут href подменю, например: #mm-1. Вставьте это значение в URL пользовательской ссылки и сохраните меню. Это обеспечит корректную работу мобильной версии при нажатии на текст меню.

Моя версия выглядит так:
сначала в меню админ-панели в нужной ссылке в поле href
ставим #
или оставляем пустым, а затем в function.php
темы добавляем:
function replace_empty_menu_links( $item_output, $item, $depth, $args ) {
if ( $item->url == '#' || $item->url == '' ) {
$item_output = sprintf( '%1$s<' . 'div' . '%2$s>%3$s%4$s%5$s</' . 'div' . '>%6$s',
$args->before,
$attributes,
$args->link_before,
apply_filters( 'the_title', $item->title, $item->ID ),
$args->link_after,
$args->after
);
}
return $item_output;
}
add_filter( 'walker_nav_menu_start_el', 'replace_empty_menu_links', 10, 4 );
Вы можете заменить 'div'
на любой элемент, который вам подходит.
Это работает для версии 5.3.2 (проверено в этой версии, но должно работать и в других).
В такой форме сохраняется работа всех аргументов 'before'
, 'after'
, 'link_before'
, 'link_after'
и т.д. из wp_nav_menu()
.
Также это работает и для подменю.

Более простое решение можно найти в другом вопросе:
Ищите ответ пользователя Askelon. Работает идеально, без необходимости использовать preg_replaces или jQuery.

Вы можете отключить события на теге <a>
для всех пунктов меню первого уровня с помощью чистого CSS. Класс .main-menu
может иметь другое название в зависимости от именования вашего меню.
/* отключаем кликабельность родительских пунктов меню */
ul.main-menu > li > a {
pointer-events: none;
}
