Почему бы не прописать редиректы с этих 56 ссылок на новые нормальные адреса?
Но с другой стороны, если хочется без редиректов, я не вижу минусов от странных URL, кроме как эстетичности. Но это переходящая мода. Вон Google/Youtube этим не заморачиваются.
Только что проверил, Wordpress позволяет вставлять и точки и пробелы в ЧПУ и в slug поста/страницы.
[ATTACH]170106[/ATTACH]
Вам нужно зарегистрировать отдельное меню (или отдельные размещения меню) для каждой категории.
Как идентификатор (slug) можете использовать slug/ID категории (в качестве префикса) _ menu, а как название меню "Меню для НАЗВАНИЕ КАТЕГОРИИ".
Далее, вы сможете редактировать каждое из меню из панели управления Wordpress - внешний вид - меню.
Регистрация меню
register_nav_menus()
https://codex.wordpress.org/Function_Reference/register_nav_menus
Отображение меню
wp_nav_menu(['theme_location' => $category.'_menu']), где $category (префикс текущей категории), можно получить с помощью get_the_category()[0]->slug
https://codex.wordpress.org/Function_Reference/wp_nav_menu
https://developer.wordpress.org/reference/functions/get_the_category/
За этот метод выше я ручаюсь, потому, что реализовывал на клиентском мультиязычном сайте (для каждого языка отдельное меню).
Но в вашем случае, можно сделать даже немного проще, без регистрации отдельных локаций.
В таком случае, вызов будет что-то типа
wp_nav_menu(['theme_location' => 'sidebar', 'menu'=> $category.'_menu'])
То-есть, вам нужно создать ОДНО размещение меню через register_nav_menu() со slug, например, sidebar и далее уже для него создать меню для каждой категории со slug slug/ID категории _ menu.
Далее мы получаем slug/ID первой категории поста get_the_category()[0]->slug и получаем для него меню
Проведя следующие работы, вы сможете добавлять ссылки на посты/страницы/категории прямо из панели управления для каждой категории, как вы и хотели.
Название ссылки в меню можно будет отредактировать.
Меню на каждой категории можно будет дополнительно стилизовать, потому, что WP добавляет ID="название меню" к блоку меню, например, .category_name_one_menu {color: red}
Также, советую установить плагин кеширования меню в переходящие данные, потому, что его генерирование на удивление может замедлять работу сайта (каждая ссылка в меню берется из базы данных, как плюс - всегда актуальные ссылки, как минус - растущее с количеством ссылок количество запросов в базу).
https://generatewp.com/how-to-use-transients-to-speed-up-wordpress-menus/
В таком случае,
1. Не будет доступен визуальный редактор меню, и как вытекающее, нужно будет постоянно следить за актуальностью ссылок в коде.
2. Меню не будет кешироватся с помощью функционала переходящих данных Wordpress.
Я думаю, вы не понимаете, как работает заголовок Last-modified.
О том, как обрабатывает данную директиву Яндекс, написано в следующей публикации.
/ru/news/21486
Там также присутствует метод проверки корректной настройки Last-modified/If-modified-since с помощью инструментов Яндекса.
Немного терминологии...
Last-modified и Etag это заголовки валидаторы актуальности кеша.
Это не влияет на формирование даты в сниппете! Я думаю, что это основное заблуждение через которое веб-мастера стараются реализовать этот заголовок для динамический страниц.
Когда браузер или робот получает заголовок Last-modified от сервера, в следующий раз, клиент (браузер или робот) отправит специальный заголовок серверу - If-modified-since.
На этом поведение браузера/робота заканчивается.
Больше браузер никак не использует этот заголовок.
Клиент также может игнорировать валидаторы кеша, если кеширование страницы запрещено директивой cache-control.
После того, как сервер получил от клиента заголовок If-modified-since, он должен сравнить дату с датой в Last-modified, и если
1. Дата у клиента равна Last-modified (то-бишь, версия в кеше актуальная), он возвращает 304 Not Modified статус-код.
Тем самым, браузер или робот, может пропустить повторное скачивание страницы/файла (из-за того, что она уже присутствует в кеше/была проиндексирована ранее).
То-есть, со стороны поискового робота, это помогает сэкономить ресурсы сервера/бота/клиента и crawling budget (как вытекающее).
2. Дата у клиента старше даты Last-modified (то-бишь, версия в кеше уже неактуальная).
Сервер возвращает 200 статус-код.
Тем самым, указывает роботу/браузеру, что страницу нужно загрузить заново/переиндексировать.
Если вы не обрабатываете заголовок If-modified-since от клиента, тогда поведение браузера/робота всегда одинаковое и попадает в этот пункт.
Этот пункт характеризует работу браузера/робота без использование Last-modified директивы вообще. То-есть, она не задействована и не делает ничего.
Я думаю, что вы просто злитесь через то, что не можете предоставить такие же качественные ответы, как я.
Хороший пример того, что получит человек, если обратится к вам в ЛС с бюджетом от 50$ (судя по вашей подписи).
Может лучше потратить время на более качественные ответы по теме, а не желчь?
Если находясь на /en/example перейти на /example (ru - по-умолчанию), редирект пойдет на /en/example обратно.
Потому, что плагин записывает последний язык в cookie qtrans_front_language.
И чтобы его перезаписать, нужно сначала открыть /ru/example (который присвоит новые cookie и выполнит 302 редирект на /example).
Но даже если функционал cookie выпилить, плагин все-равно будет пытаться определить предпочитаемый язык через referer.
И если с /en/example перейти по ссылке на /example (ru - по-умолчанию), плагин перебросит все-равно на /en/example (на основе referer - предыдущая страница была на английском).
Это не ошибка плагина, а его дизайн.
Разработчик не планирует исправлять это в последующих обновлениях.
https://qtranslatexteam.wordpress.com/browser-redirection-based-on-language/
Виджет не просто выводит ссылки на /ru, /en.
Он выводит ссылки на языковые версии текущей страницы (/en/example, находясь на /example).
Однако, проблему решили в ЛС.
Возможно кому-то будет полезно решение проблемы.
qTranslate X практически не использует систему хуков, поэтому, решение затрагивает правку исходного кода ядра плагина.
Это означает, что работы нужно вносить после каждого обновления плагина.
qtranslate_core.php
1. Отключаем функционал cookie для фронт-энда.
Это означает, что если пользователь однажды выбрал у вас на сайте англ. версию и перешел с поиска на русскую версию по-умолчанию, он больше не будет переброшен на англоязычную версию.
Функция qtranxf_loadConfig
секция switch($url_mode){
case QTX_URL_PATH:
$q_config['disable_client_cookies'] = false;
установить в true
2. Отключаем восстановление языка по Referer.
Это означает, что если пользователь перешел с /en/example на /example-2, он больше не будет переброшен на /en/example-2, а ему будет показана версию по-умолчанию.
Функция qtranxf_detect_language()
секция if(!qtranxf_external_host($ref_info['host']) ) {
изменить условие if на if(false and !qtranxf_external_host($ref_info['host']) ) {
3. ВСЕГДА сокращаем путь в ссылке для языка по-умолчанию (затрагивает в том числе ссылки в виджете).
Функция qtranxf_convertURL().
В самом верху вставляем $showDefaultLanguage = false;
https://webmasters.googleblog.com/2017/12/rendering-ajax-crawling-pages.html
Оригинал.
Я думаю, что новость упускает этот момент.
По сути #! и # технически оба якорные ссылки.
В новости четко сказано, что бот будет напрямую рендерить содержимое якорных ссылок (# или только #! упущено).
Почему я думаю, что речь идет о якорных ссылках в общем.
Потому что Google работает над развитием Progressive Web Apps.
И тут стоит вопрос, как индексировать всплывающие меню, ленивую подгрузку результатов и списков. В PWA, динамичность на каждом шагу. И очень редко эта динамичность сопровождается изменением URL.
Если я правильно понял из следующей новости, то во втором квартале 2018 года, Google будет распознавать якорные ссылки, как отдельные страницы.
В статье речь о #!, но я уверен, речь идет об якорных ссылках вообщем.
/ru/news/1029230
Теперь эта ситуация изменилась, и Google будет сканировать и обрабатывать сайты на AJAX, как есть. Это значит, что поисковик будет рендерить #! URL напрямую, и вебмастерам больше не нужно будет предоставлять отображаемую версию страницы.
Разница в производительности скорее всего вызвана разницей в кодеках.
Очень странно, что в Chrome AVC по-умолчанию (на Windows в любом случае).
Обычно, наоборот.
А операционная система какая?
Stats for nerds (контекстное меню по видео фрейму) посмотрите.
Youtube отдает разные форматы в зависимости от устройства/браузера.
Chrome всегда получает видео в VP8 формате.
Safari в H.264.
Если в stats for nerds в Firefox - H.264 и там быстрее, тогда вы можете форсировать кодек с VP8 на H.264 в Chrome с помощью расширения
https://chrome.google.com/webstore/detail/h264ify/aleakchihdccplidncghkekgioiakgal
Google распознает якорные ссылки, как отдельные страницы.
Однако, по ссылкам #comment- указан rel="canonical" на страницу без якоря.
Соответственно, вес никуда не уплывает.
Я думаю, разработчики Wordpress хорошо знакомы с алгоритмами работы Google.
Хорошо взвесили плюсы и риски, при реализации данного функционала.---------- Добавлено 07.01.2018 в 20:40 ----------
Простого решения, типа добавить строчку в functions.php нету, потому, что плагин qTranslate почти не использует систему хуков.
Соответственно, нельзя отловить и модифицировать участок кода, можно его только переписать.
Если вы знакомы с программированием, тогда вам нужно унаследовать класс qTranslateXWidget и модифицировать методы, где вызывается qtranxf_convertURL (то-есть, создать новый виджет на основе класса виджета плагина).
Либо переписать исходный код виджета (или функции), но в таком случае, правки нужно будет вносить повторно после каждого обновления плагина.
Что и где изменили?
qtrans_convertURL не используется в виджете.
В виджете используется qtranxf_convertURL напрямую.
Вот исходный код функции qtranslate_core.php, которая генерирует ссылки.
Функцию править не нужно, как я догадываюсь.
Нужно отредактировать ее вызов в классе виджета (унаследовав его).
Оригинальные файлы плагина лучше не перезаписывать, иначе все изменения могут быть потеряны после обновления плагина.
function qtranxf_convertURL($url='', $lang='', $forceadmin = false, $showDefaultLanguage = false) { global $q_config; if(empty($lang)) $lang = $q_config['language']; if(empty($url)){ if( $q_config['url_info']['doing_front_end'] && defined('QTS_VERSION') && $q_config['url_mode'] != QTX_URL_QUERY){ //quick workaround, but need a permanent solution $url = qts_get_url($lang); //qtranxf_dbg_log('qtranxf_convertURL: qts_get_url: url=', $url); if(!empty($url)){ if($showDefaultLanguage && $q_config['hide_default_language'] && $lang==$q_config['default_language']) $url=qtranxf_convertURL($url,$lang,$forceadmin,true); return $url; } } //$url = esc_url($q_config['url_info']['url']); } if( !$q_config['url_info']['doing_front_end'] && !$forceadmin ) return $url; if(!qtranxf_isEnabled($lang)) return ''; if(!$showDefaultLanguage) $showDefaultLanguage = !$q_config['hide_default_language']; $showLanguage = $showDefaultLanguage || $lang != $q_config['default_language']; //qtranxf_dbg_log('qtranxf_convertURL('.$url.','.$lang.'): showLanguage=',$showLanguage); $complete = qtranxf_get_url_for_language($url, $lang, $showLanguage); //qtranxf_dbg_log('qtranxf_convertURL: complete: ',$complete); return $complete;}
Это по сути, мастер-функция на qtranxf_get_url_for_language
function qtranxf_get_url_for_language($url, $lang, $showLanguage=true) { global $q_config; static $url_cache=array(); //qtranxf_dbg_log('qtranxf_get_url_for_language: $url_cache:',$url_cache); if(!isset($url_cache[$url])) $url_cache[$url] = array(); $urlinfo = &$url_cache[$url]; //$urlinfo = apply_filters('qtranslate_url_for_language_pre', $urlinfo, $url, $lang, $showLanguage); if($showLanguage){ if(isset($urlinfo[$lang])){ //qtranxf_dbg_log('qtranxf_get_url_for_language: cached: lang='.$lang.': ',$urlinfo); return $urlinfo[$lang]; } }else{ if(isset($urlinfo['bare'])){ //qtranxf_dbg_log('qtranxf_get_url_for_language: cached: bare: ',$urlinfo); return $urlinfo['bare']; } } if(isset($urlinfo['language_neutral'])){ //qtranxf_dbg_log('qtranxf_get_url_for_language: cached: language_neutral: ',$urlinfo); return $urlinfo['language_neutral']; } $homeinfo = qtranxf_get_home_info(); if(!isset($urlinfo['url_parsed'])){ if(empty($url)){ $urlinfo = qtranxf_copy_url_info($q_config['url_info']); if( isset($urlinfo['wp-path']) && qtranxf_language_neutral_path($urlinfo['wp-path']) ){ //qtranxf_dbg_log('qtranxf_get_url_for_language: language_neutral: wp-path: url='.$url.':',$urlinfo); $complete = qtranxf_buildURL($urlinfo,$homeinfo); if(!isset($url_cache[$complete])) $url_cache[$complete] = $urlinfo; $urlinfo['language_neutral'] = $complete; return $complete; } } else{ $urlinfo = qtranxf_get_url_info($url); // check if it's an external link if(!isset($urlinfo['wp-path'])){ $urlinfo['language_neutral'] = $url; //qtranxf_dbg_log('qtranxf_get_url_for_language: language_neutral: external path: ',$urlinfo); return $url; } if(empty($urlinfo['host'])){ if(empty($urlinfo['wp-path'])){ if(empty($urlinfo['query']) ){ $urlinfo['language_neutral'] = $url; //qtranxf_dbg_log('qtranxf_get_url_for_language: language_neutral: relative path: ',$urlinfo); return $url; } }else{ switch($urlinfo['wp-path'][0]){ case '/': break; case '#': { $urlinfo['language_neutral'] = $url; //qtranxf_dbg_log('qtranxf_get_url_for_language: language_neutral: relative hash: ',$urlinfo); return $url; } default: $urlinfo['wp-path'] = trailingslashit($q_config['url_info']['wp-path']).$urlinfo['wp-path']; break; } } }elseif(qtranxf_external_host_ex($urlinfo['host'],$homeinfo)){ $urlinfo['language_neutral'] = $url; //qtranxf_dbg_log('qtranxf_get_url_for_language: language_neutral: external host: ',$urlinfo); return $url; } if(qtranxf_language_neutral_path($urlinfo['wp-path'])){ $urlinfo['language_neutral'] = $url; //qtranxf_dbg_log('qtranxf_get_url_for_language: language_neutral: wp-path: ',$urlinfo); return $url; } qtranxf_url_del_language($urlinfo); } $urlinfo['url_parsed'] = $url; } $urlinfo_lang = qtranxf_url_set_language($urlinfo,$lang,$showLanguage); $complete = qtranxf_buildURL($urlinfo_lang,$homeinfo); //$complete = apply_filters('qtranslate_url_for_language',$complete,$lang,$urlinfo_lang,$homeinfo); if($showLanguage){ $urlinfo[$lang] = $complete; }else{ $urlinfo['bare'] = $complete; } if(!isset($url_cache[$complete])) $url_cache[$complete] = $urlinfo; //qtranxf_dbg_log('done: qtranxf_get_url_for_language('.$lang.($showLanguage?', true':', false').'): $urlinfo=',$urlinfo,false); return $complete;}