Как изменить URL конкретных страниц / записей / рубрик / меток / таксономий через functions.php

Если вы читаете эту статью, то наверняка хотя бы раз слышали про WP_Rewrite. Этот класс позволяет работать с постоянными ссылками в WordPress, изменять их вид и структуру. WP_Rewrite задает правила перезаписи, которые будут действовать по всему блогу.

Сейчас же я покажу вам очень простой но действенный метод ручной замены URL конкретных страниц сайта на WordPress. Состоит он всего из трёх шагов: редиректа старых страниц на новые, изменения запроса к базе, перезаписи ссылок.

Шаг 1. Редиректы через хук template_redirect

Этот шаг нужен для того, чтобы страница не была доступна по двум URL одновременно, поэтому мы ставим 301й редирект со всех старых URL на новые (желающие могут реализовать это также через .htaccess).

В примерах я по умолчанию использую префикс для рубрик — category и для меток — tag, у вас они могут отличаться.

Весь код, который вы увидите в этой статье — в functions.php.

function true_301_redirect() {
	/* в массиве указываем все старые=>новые ссылки  */
	$rules = array(
		array('old'=>'/category/без_рубрики/','new'=>'/category/Без_рубрики/'), // рубрика
		array('old'=>'/контакты/','new'=>'/Контакты/'), // страница
		array('old'=>'/привет-мир/','new'=>'/хеллоу-мир/'), // запись
		array('old'=>'/tag/метка/','new'=>'/tag/Метка/') // метка
	);
	foreach( $rules as $rule ) :
		// если URL совпадает с одним из указанных в массиве, то редиректим
		if( urldecode($_SERVER['REQUEST_URI']) == $rule['old'] ) :
			wp_redirect( site_url( $rule['new'] ), 301 );
			exit();
		endif;
	endforeach;
}
 
add_action('template_redirect', 'true_301_redirect');

Вы могли заметить, что в большинстве ссылок я просто добавил заглавные буквы — это сделано для наглядности и такая замена тоже считается перезаписью ссылки.

Ссылки на описания функций, использованных в примерах, вы найдёте в конце статьи.

Шаг 2. Изменение параметров запроса через хук request

Окей, редиректы проставили и, если вы уже начали пробовать то, что получилось, то у вас наверняка повылазили ошибки 404. Сейчас нам нужно добиться того, чтобы новые URL WordPress воспринимал как старые.

function true_request( $query ){
 
	$url_zapros = urldecode($_SERVER['REQUEST_URI']);
 
	/* для рубрик */
	if( $url_zapros == '/category/Без_рубрики/' )
		$query['category_name'] = 'без_рубрики';
 
	/* для страниц */
	if( $url_zapros == '/Контакты/' ){
		$query['pagename'] = urlencode('контакты');
		unset($query['name']);
	}
 
	/* для записей */
	if( $url_zapros == '/хеллоу-мир/' )
		$query['name'] = 'привет-мир';
 
	/* для меток */
	if( $url_zapros == '/tag/Метка/' )
		$query['tag'] = 'метка';
 
	return $query;
}
 
add_filter( 'request', 'true_request', 9999, 1 );

Шаг 3. И конечно же сама перезапись ссылок

Хуки для записей и страниц будут отличаться от хуков для рубрик и меток.

Для записей / страниц

function true_posts_links( $url, $post ){
	if( !is_object( $post ) )
		$post = get_post( $post_id );
 
	$replace = $post->post_name;
 
	/* замены для записей и страниц,
		к сожалению тут только по ID замену можно сделать */
 
	if( $post->ID == 1 ) 
		$replace = 'хеллоу-мир';
	if( $post->ID == 12 ) 
		$replace = 'Контакты';
 
	$url = str_replace($post->post_name, $replace, $url );
	return $url;
}
 
add_filter( 'post_link', 'true_posts_links', 'edit_files', 2 );
add_filter( 'page_link', 'true_posts_links', 'edit_files', 2 );
add_filter( 'post_type_link', 'true_posts_links', 'edit_files', 2 );

Обязательно ли делать проверку именно по ID записи? Да, если в URL присутствует кириллица. Если вы не знаете, где найти ID, спрашивайте в комментах, всё расскажу и покажу.

Перезапись ссылок для рубрик / меток

function true_term_links( $url, $term, $taxonomy ){
	$replace = $term->slug;
 
	/* замены для рубрик/меток, опять-таки нужно указать ID и желаемый ярлык */
	if( $term->term_id == 5 ) 
		$replace = 'Без_рубрики';
	if( $term->term_id == 55 ) 
		$replace = 'Метка';
 
	$url = str_replace($term->slug, $replace, $url );
 
	return $url;
}
 
add_filter( 'term_link', 'true_term_links', 10, 3 );

Альтернатива всему этому в виде плагина Custom Permalinks

Если вы не хотите мудохаться через functions.php, то рекомендую плагин Custom Permalinks. Мне он показался очень удобным — прямо в админке можно указать свои произвольные урлы.

Например при создании рубрик:

Произвольный URL рубрики при помощи плагина Custom Permalinks
Подпишитесь, чтобы раз в неделю получать свежие статьи с блога по email.

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

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

  • Александр25 декабря 2015 в 13:12 #

    Привет -) Мне кажется, такие штуки не очень актуальны, хотя мы недавно с джумлы перевозили сайт - что-то похожее делали.

    Но есть актуальные проблемы, которые даже не гугляться.
    Например, пример загрузки лого через кастомайзер - http://kwight.ca/2012/12/02/adding-a-logo-uploader-to-your-wordpress-site-with-the-theme-customizer/.
    Но как эту фигню реализовать с поддержкой экранов ретина? Все реализации, которые встречались и я использую - просто поля для загрузки двух лого на странице настроек темы. Но хочется ведь красиво -)

    • Миша25 декабря 2015 в 16:12 #

      Привет, ну чтобы не было двух лого, нужно в формате svg загружать, или вы хотите чтобы загружалась большая картинка и WP её автоматически подрезал два ретины и для обычного?

      • Александр25 декабря 2015 в 16:12 #

        Второй вариант более дружелюбный -)

        • Миша25 декабря 2015 в 16:12 #

          В общем эти стили просто лепим к лого и всё — самый просто вариант.

          max-width: сколько_надо; height: auto;
          • Александр25 декабря 2015 в 16:12 #

            Ну это не решение для широкого использования, когда логотип может быть длинным и тонким, а может быть коротким и высоким.

  • Максим26 декабря 2015 в 19:12 #

    Привет.

    А как можно автоматически перезаписать ссылки, исходя из новых правил, прописанных через add_rewrite_rule? К примеру, я поставил новые правила, по ним записи/категории открываются, но по умолчанию в цикле всё равно выводятся первоначальные. Как сделать, чтобы они полностью перезаписались, причём не конкретные посты, а все пути к постам или категориям и пользовательским таксономиям. Из плагина "Custom Post Type Permalinks" выцепить не смог.

    Спасибо.

    • Миша27 декабря 2015 в 07:12 #

      Привет,

      если я правильно понял вопрос, то вам нужны фильтры post_link, post_type_link, term_link.

      • Максим27 декабря 2015 в 10:12 #

        В декабре взял вынужденный перерыв в работе над сайтом, поэтому многое уже из головы вылетело. Попробую в двух словах описать общую задачу.

        Есть пользовательский тип записей и есть пользовательские таксономии, к примеру, "город" и "тип". У меня стоит задача привести ссылки на посты к виду:

        http://домен/город/тип/slug_записи

        и страницы таксономии к виду:

        http://домен/город/slug_таксономии

        Отсюда идут вопросы.
        1) Можно ли с помощью

        query_vars

        автоматически генерировать параметр в ссылке, исходя из принадлежности к таксономии (разные города, типы)? Или нужны другие инструменты?
        2) Если будет первый пункт, то правила без проблем создадутся с помощью

        add_rewrite_rule

        . При вводе в адресной строке новых ссылок мы попадём на нужные страницы. Но ссылки на записи и таксономии при выводе их в цикле не поменялись на новые. Какой конструкцией можно это поправить? В Вашем примере описывается конкретные посты/категории, их нужно задавать. Наверное, нужно как-то проходить циклом что-ли по всем существующим или правильней было бы менять на лету, исходя из поступившего запроса?

        Таких понятных справок в интернете я не нашёл, хотя это многим нужная вещь.
        Спасибо.

        • Миша28 декабря 2015 в 08:12 #

          Могу ответить лишь то, что у меня сейчас серия постов идёт чисто по этой теме, просто следите за обновлениями.

          Если вы хотите доработать текущий пример то да, можете и циклом прокрутить, как вы сказали, можете и на лету менять, просто берите способ, который вам ближе.

  • Дмитрий4 декабря 2016 в 16:12 #

    Миша, подскажите пожалуйста, я использую такой редирект, но он не срабатывает:

    add_action( 'template_redirect', function() {
    	if ( preg_match( '#^/author/$user_ID/?$#i', $_SERVER['REQUEST_URI'] ) ) {
    		wp_redirect( 'http://mysite.ru/404', 301 );
    		exit;
    	}
    } );

    Я не могу понять как прописать правильно $user_ID в строке редиректа.
    У меня стоит плагин и после авторизации юзеры переходят в свой профиль по ссылке http://mysite.ru/author/id юзера/
    И юзер может в строке вбить другого юзера и зайти в его профиль.
    Вот хочу убрать эту возможность через редирект.

    • Миша4 декабря 2016 в 22:12 #

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

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

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

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

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

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

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