Как добавить таксономию в структуру URL произвольного типа записи?

Прежде всего я хочу поздравить всех своих читателей с Новым Годом! Не ожидал, что дата публикации поста выпадет на 1-е января :)

А теперь вернёмся к WordPress и глянем на простой пример интернет-магазина.

Допустим у магазина есть отдельный тип записей под товары — tovar и таксономия для их организации tovar_kat. По умолчанию URL товара будет следующего вида /tovar/ЯРЛЫК ТОВАРА/.

Мы же хотим привести его к такому виду: /ЯРЛЫК КАТЕГОРИИ ТОВАРА/ЯРЛЫК ТОВАРА/. Если смотреть по конкретному примеру, то будет произведена замена /tovar/burton-cartel/ на /snowboard-bindings/burton-cartel/.

Код из этой статьи позволит вам всё это реализовать. Вставляйте его в файл functions.php вашей темы, но перед этим взгляните на настройки постоянных ссылок в админке, желательно, чтобы они были вот такими:

рекомендуемые настройки постоянных ссылок в WordPress

Перезаписываем ссылки и основной запрос

add_filter('post_link', 'true_post_type_permalink', 20, 3);
add_filter('post_type_link', 'true_post_type_permalink', 20, 3);
 
function true_post_type_permalink( $permalink, $post_id, $leavename ) {
 
	$post_type_name = 'tovar'; // название типа записи, вы можете найти его в админке или в функции register_post_type()
	$post_type_slug = 'tovar'; // часть URL товаров, не всегда совпадает с названием типа записи!
	$tax_name = 'tovar_kat'; // ну это понятно, название таксономии - категории товаров
 
	$post = get_post( $post_id ); // получаем объект поста по его ID
 
	if ( strpos( $permalink, $post_type_slug ) === FALSE || $post->post_type != $post_type_name ) // не делаем никаких изменений, если тип записи не соответствует или если URL не содержит ярлык tovar
		return $permalink;
 
        $termini = wp_get_object_terms( $post->ID, $tax_name ); // получаем все категории, к которым принадлежит данный товар
 
 
        if ( !is_wp_error( $termini ) && !empty( $termini ) && is_object( $termini[0] ) ) // и делаем перезапись ссылки, только, если товар находится хотя бы в одной категории, иначе возвращаем ссылку по умолчанию
        	$permalink = str_replace( $post_type_slug, $termini[0]->slug, $permalink );
 
	return $permalink;
}
 
 
add_filter('request', 'true_post_type_request', 1, 1 );
 
function true_post_type_request( $query ){
	global $wpdb; // нам немного придётся поработать с БД
 
	$post_type_name = 'tovar'; // указываем тут название типа записей товара
	$tax_name = 'tovar_kat'; // а также название таксономии - категории товаров
 
	$yarlik = $query['attachment']; // после того, как мы изменили ссылки товаров в предыдущей функции, WordPress начал принимать их за страницы вложений
 
	// а теперь давайте получим ID товара, ярлык которого соответствует запросу на странице
	$post_id = $wpdb->get_var(
		"
		SELECT ID
		FROM $wpdb->posts
		WHERE post_name = '$yarlik'
		AND post_type = '$post_type_name'
		"
	);
 
	$termini = wp_get_object_terms( $post_id, $tax_name ); // товар должен находиться в категории (одной или нескольких)
 
 
	if( isset( $yarlik ) && $post_id && !is_wp_error( $termini ) && !empty( $termini ) ) : // изменяем запрос, если всё ок
 
		unset( $query['attachment'] );
		$query[$post_type_name] = $yarlik;
		$query['post_type'] = $post_type_name;
		$query['name'] = $yarlik;
 
	endif;
 
	return $query; // возвращаем результат
}

Ставим 301 редирект со старых ссылок на новые

Про важность редиректа думаю рассказывать не нужно. Особенно если ваш сайт функционирует уже давно и набрал большое количество товаров. Тогда без редиректа будет большое количество ошибок 404.

add_action('template_redirect', 'true_post_type_redirect');
 
function true_post_type_redirect() {
 
	$post_type_name = 'tovar'; // как и в первом шаге, указываем тут название типа записи
	$post_type_slug = 'tovar'; // тут ярлык, то есть то, что в URL
	$tax_name = 'tovar_kat'; // и название таксономии
 
	if( strpos( $_SERVER['REQUEST_URI'], $post_type_slug ) === FALSE) // выходим из функции ничего не делая, если URL не содержит ярлыка типа записи "tovar"
		return;
 
	if( is_singular( $post_type_name ) ) : // функцию выполняем только на страницах записей данного типа
		global $post, $wp_rewrite;
 
		$termini = wp_get_object_terms( $post->ID, $tax_name ); // опять проверяем товар на наличие категорий
 
		if ( !is_wp_error( $termini ) && !empty( $termini ) && is_object( $termini[0] ) ) :
 
			wp_redirect( site_url() . '/' . $wp_rewrite->front . '/' . $termini[0]->slug . '/' . $post->post_name, 301 );
			// wp_redirect( get_permalink( $post->ID ), 301 ); // можно использовать эту строчку, но строго обязательно должен быть установлен первый хук из этой статьи
 
			exit();
        	endif;
	endif;
 
}
Подпишитесь, чтобы раз в неделю получать свежие статьи с блога по email.

Смотрите также

Комментарии 2

  • Илья Волков4 апреля 2016 в 21:04 #

    У меня 2 нубских вопроса, но я так и не смог на них найти четкого и адекватного ответа.

    1. С точки зрения грамотной оптимизации - если есть возможность не пользоваться плагином для решения какой-либо задачи, лучше его не использовать. Плагины по сути делают сайт тяжелее или это миф? Я замечал, что если на сайте много плагинов он начинает уйму библиотек подгружать, они могут конфликтовать. А это не очень хорошо. Но как быть если например задач много, например, 20 доп функций - это скажем 20 плагинов - можно закопаться. Как тогда быть?

    2. Вопрос #2. Тоже для меня очень тяжкий вопрос и на него также никто мне не ответил.
    Есть вот такой url - это по сути вложенный друг в друга странички
    http://remz.org/otdelka/osteklenie/osteklenie-balkona/teploe-osteklenie-balkonov/

    логика в том, что есть "отделка" дальше ветка ведет на "остекление" и так по накатанной.

    Это правильно с точки зрения заполнения сайта или лучше url 1-2 уровней и например раскидывать это все по рубрикам.
    Интересует именно валидация с точки зрения продвижения в SEO и логики, которые предусмотрели разработчики WordPress!

    • Миша5 апреля 2016 в 07:04 #

      Не таких уж и нубских, немного не по теме, ну да ладно.

      1. Этот вопрос очень часто задаётся, вот только на него нет однозначного ответа. Насчет библиотек ты правильно заметил — такое возможно, но обычно в кривых плагинах. Что касается быстродействия — всё зависит от плагинов и от реализуемых их задач. Понятное дело, что некоторые задачи могут значительно замедлять работу сайта. Понятное дело, что существуют плагины с медленным кодом.

        Я для себя этот вопрос решил следующим образом — минимум плагинов ( например WP-Super-Cache, BackWPup и ещё парочка ), всё остальное в коде.

      2. Если я правильно понял вопрос, то лучше, это если каждый уровень URL будет доступен, допустим удалил teploe-osteklenie-balkonov/ и открылась другая страница (лучше, но не критично).

        А как это будешь реализовывать — через рубрики и посты или через страницы — уже зависит от тебя.

        Однако, если это будут лендинги, то однозначно через страницы.

        Если вопрос подрузмевал то, что содержится в URL, то тут два простых правила: во-первых, чем короче, тем лучше, во-вторых, в URL должны быть ключевые слова.

Оставить комментарий / вопрос

phpjsHTMLCSSSQLПросто код
  Для того, чтобы оставить комментарий, пожалуйста, зарегистрируйтесь или авторизуйтесь на сайте.
Получайте новости блога по email или следите за мной в социальных сетях.
  • Миша: Да, точно)

  • Владимир: и на третьей строке не хватает скобки ) закрывающей if :)

  • Миша: Добрый вечер! Рекомендую получить ID пользователя через функцию get_current_user_id().

  • Дмитрий: Миша, подскажите пожалуйста, я использую такой редирект, но он не срабатывает: add_action( 'template_redirect', funct...

  • Миша: Ну как не определена - это аргумент функции. Или я просто вас не до конца понимаю.