Понимание add_rewrite_rule
Я пытаюсь настроить работу add_rewrite_rule
для извлечения параметра из URL и передачи его в запрос. Видел несколько постов об этом, но не могу заставить это работать.
Если URL начинается с определенной строки, я хотел бы удалить ее из URL и передать как параметр запроса.
Пример URL запроса:
http://domain.com/foo/my_page
Который должен преобразоваться в
http://domain.com/my_page?param=foo
Если 'foo' отсутствует, это должен быть обычный запрос. Эта логика должна применяться к любому URL страницы или URL произвольного типа записи на моем сайте (по сути foo/*). Предполагается, что это будет действовать как проход, если URL содержит 'foo', удалить его, а затем просто передать WordPress для выполнения его обычных действий.
У меня уже есть 'param' в разрешенных query_vars.
В целом, это должно работать для следующих случаев:
- /foo/my_page (Страница)
- /foo/my_folder/my_page (Подстраница)
- /foo/example_type (Архив произвольного типа записей)
- /foo/example_type/example_post (Отдельная запись произвольного типа)

Основное правило, которое подойдет для вашего примера:
function wpd_foo_rewrite_rule() {
add_rewrite_rule(
'^foo/([^/]*)/?',
'index.php?pagename=$matches[1]¶m=foo',
'top'
);
}
add_action( 'init', 'wpd_foo_rewrite_rule' );
Это правило берет все, что идет после foo/
, и устанавливает это как pagename
для запроса, а затем параметр param
получает статическое значение foo
. Если вам нужны разные шаблоны URL, потребуются дополнительные правила для каждого уникального шаблона. Обратитесь к документации WP_Query
для просмотра различных переменных запроса, которые можно установить в правилах перезаписи. Не забудьте сбросить правила перезаписи после добавления новых. Это можно сделать, посетив страницу настроек постоянных ссылок.
Теперь при переходе по вашему примеру URL:
http://domain.com/foo/my_page
будет загружаться правильная страница, но она не будет вести себя точно так же, как при переходе по:
http://domain.com/my_page?param=foo
потому что при использовании внутренних перезаписей параметр param
устанавливается внутри объекта запроса $wp_query
, а не суперглобального массива $_GET
. Если вам нужно работать с кодом, который ищет значение в $_GET
, потребуется дополнительный шаг для установки этого значения:
function wpd_foo_get_param() {
if( false !== get_query_var( 'param' ) ){
$_GET['param'] = get_query_var( 'param' );
}
}
add_action( 'parse_query', 'wpd_foo_get_param' );
Еще один метод, который стоит рассмотреть — это использование конечных точек (endpoints). В этом случае /foo/
будет добавляться в конец URL, а не в начало. Преимущество этого подхода в том, что функция API add_rewrite_endpoint
упрощает добавление всех необходимых правил, включая поддержку пагинации.

Спасибо за подробное объяснение. Кажется, почти работает - для страниц всё ок, но выдает 404 ошибку для архивов и одиночных записей пользовательских типов постов.

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

У меня есть пользовательский тип страниц под названием 'projects', у которого есть архив и отдельные страницы. Можете привести пример для этого случая, а остальные я смогу сделать сам.

Верно, это работает только для конкретного примера, который я указал выше, поэтому в конце я предлагаю использовать endpoint вместо этого. Если вам нужны различные уровни подстраниц, архивы с пагинацией, отдельные записи и т.д., вам придётся добавить множество правил. Этот плагин для анализа перезаписи поможет показать, как правила преобразуются в query vars, и может подсказать, как вам нужно строить дополнительные правила.

Извините, endpoint не подходит — мне нужно, чтобы переменная была в начале URL. Не хочу усложнять, но я не могу принять это решение, пока оно не соответствует требованиям, изложенным в исходном сообщении, включая архивы/страницы пользовательских записей и (хотя это не было явно указано) должно работать для подстраниц (foo/*).

Отредактируйте свой вопрос, добавив пример каждого шаблона URL, для которого нужно правило. Меня не слишком волнует, примут ли мой ответ, иногда я могу подтолкнуть людей к самостоятельному нахождению решения, дав им отправную точку.

Хорошо, я получил рабочие примеры для всех 3 типов запросов. Потребовалось множество экспериментов и проб, чтобы заставить их работать. Думаю, Мило хорошо подталкивает людей к самостоятельному поиску ответов на свои вопросы.
После бесчисленных изменений и обновлений постоянных ссылок я понял, что было гораздо проще сначала разобраться с URL вне add_rewrite_url, а уже после того, как они заработают, определять правила перезаписи. Например: index.php?param=foo&post_type=example_type
.
Ещё одна очевидная вещь, но я добавлю её здесь, чтобы помочь другим. Вы должны определять правила add_rewrite_rule для пользовательских типов записей ДО определения правил для страниц/подстраниц с подстановочными знаками. Я потратил на это немало времени и думаю, что именно это было основной причиной, по которой правила не работали.
Вот 3 правила, которые работают для всех моих нужд. Правило для Страниц/Подстраниц было объединено в одно.
// Архив пользовательских записей
add_rewrite_rule(
'^foo/example_type/?$',
'index.php?param=foo&post_type=example_type',
'top'
);
// Отдельная пользовательская запись
add_rewrite_rule(
'^foo/example_type/([^/]*)/?$',
'index.php?param=foo&example_type=$matches[1]',
'top'
);
// Страницы, верхнего уровня и подстраницы
// ЭТО ДОЛЖНО БЫТЬ РАЗМЕЩЕНО В КОДЕ ПОСЛЕ add_rewrite_rule для пользовательских типов записей
add_rewrite_rule(
'^foo/(.+)/?$',
'index.php?param=foo&pagename=$matches[1]',
'top'
);
Дополнительно я настроил цикл для добавления правил для нескольких пользовательских типов записей. Помните, вы должны определить правила add_rewrite_rule для пользовательских типов записей ДО определения правил для страниц/подстраниц с подстановочными знаками.
$custom_types = array('example_type', 'projects', 'people');
foreach($custom_types as $type) {
// Архив пользовательских записей
add_rewrite_rule(
'^foo/'.$type.'/?$',
'index.php?param=foo&post_type='.$type,
'top'
);
// Отдельная пользовательская запись
add_rewrite_rule(
'^foo/'.$type.'/([^/]*)/?$',
'index.php?param=foo&'.$type.'=$matches[1]',
'top'
);
}
Анализатор перезаписи, который порекомендовал Мило, был весьма полезен для лучшего понимания того, как WordPress выполняет запросы к страницам/записям.

Опоздал на шоу, но могу ли я обратиться к вам за еще одним примером? Признаюсь, я совсем не понимаю параметр $tag в add_rewrite_rule. Понятия не имею, что он означает. Также не понимаю пример с использованием pagename=$matches[1]'. ЧТО??? У меня есть URL вида domain.com/detail?id=2&it=3. Я хочу, чтобы страница выглядела как domain.com/detail/2-3/. Вы не против помочь?
