Как добавить таксономию в структуру 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;
 
}
Миша Рудрастых Разработчик WordPress WooCommerce

Миша Рудрастых

Впервые познакомился с WordPress в 2009 году, и после двух лет мучений с Joomla и самописными движками это был просто бальзам на душу. С 2014 года меня можно встретить на WordCamp — официальной конфе по WP в Москве, иногда там выступаю. Также в настоящее время веду курсы по WordPress в Epic Skills в Питере.

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