Проблема с правилами перезаписи, когда правило включает слаг главной страницы
У меня есть страница Example (ID=443, слаг=example), которая настроена как главная страница моего сайта на WordPress через Консоль->Настройки->Чтение
. Я также настроил следующее правило перезаписи:
[(example)/(view-section)] => index.php?pagename=$matches[1]&foo=1&bar=2
На странице Example есть шорткод, который должен генерировать контент в зависимости от наличия и значений query vars foo
и bar
. Проблема в том, что эти query vars не устанавливаются корректно при посещении URL /example/view-section
(и других связанных, см. ниже).
Для отладки этой проблемы я использую тестовый плагин. Полный код приведен ниже:
<?php
function test_shortcode() {
global $wp_rewrite;
echo '<pre>' . 'foo: ' . get_query_var('foo') . '</pre>';
echo '<pre>' . 'bar: ' . get_query_var('bar') . '</pre>';
echo '<pre>' . print_r($wp_rewrite->rules, true) . '</pre>';
}
add_shortcode('foobar', 'test_shortcode');
function test_rules() {
$rules = get_option('rewrite_rules');
if (!isset($rules['(example)/(view-section)'])) {
global $wp_rewrite;
$wp_rewrite->flush_rules();
}
}
add_action('wp_loaded', 'test_rules');
function test_rewrite_rules($wprules) {
$rules = array('(example)/(view-section)' => 'index.php?pagename=$matches[1]&foo=1&bar=2');
return $rules + $wprules;
}
add_action('rewrite_rules_array', 'test_rewrite_rules');
function test_query_vars($query_vars) {
array_push($query_vars, 'foo');
array_push($query_vars, 'bar');
return $query_vars;
}
add_filter('query_vars', 'test_query_vars');
Я получил разные результаты в трех сценариях:
- При переходе на /example/view-section происходит редирект на /, а значения query vars пустые.
- При переходе на /index.php?pagename=example&foo=1&bar=2 все работает как нужно - отображается контент, сгенерированный шорткодом, с переданными значениями query vars.
- Если использовать
page_id
вместоpagename
илиpage
: /index.php?page_id=443&foo=1&bar=2, query varpage_id
удаляется и снова показывается главная страница по умолчанию.
Хотелось бы понять, почему WordPress ведет себя таким образом, и, если возможно, как сделать, чтобы первый сценарий работал как второй.
Важно отметить: если страница Example не настроена как главная, сценарии 1 и 3 работают так же, как сценарий 2.
Буду благодарен за помощь и готов предоставить дополнительные детали при необходимости.
ОБНОВЛЕНИЕ
В оригинальном вопросе были ссылки на работающий экземпляр WordPress с примером проблемы. Однако я не могу поддерживать этот экземпляр постоянно, поэтому удалил ссылки и постарался объяснить ситуацию только словами.

Проблема не связана с правилами перезаписи (хотя я бы предложил использовать add_rewrite_rule()
вместо более низкоуровневого подхода с прямым изменением массива перезаписи. То же самое касается flush_rewrite_rules()
. Кроме того, хотя в вашем случае правила перезаписываются только один раз — лучше делать это при активации плагина, а не внутри условия, которое проверяется при каждой загрузке страницы.
... так что "проблема" на самом деле связана с канонизацией. По сути, различные URL могут указывать на один и тот же контент (включая URL с дополнительными слешами). Идея заключается в следующем:
- С точки зрения SEO это плохо — если поисковые системы не поймут, что все эти URL представляют один и тот же ресурс, они могут начать конкурировать друг с другом.
- Плохо с точки зрения пользователя. Если они перейдут по адресу www.example.com?year=2012, лучше перенаправить их на www.example.com/2012 — так красивее и легче запомнить.
Таким образом, когда WordPress получает "неправильный" или "дублирующий" URL, например www.example.com?year=2012, он перенаправляет его на правильный (или "канонический") URL (в данном случае www.example.com/2012).
Одна из проверок, которые он выполняет, — это проверка, находимся ли мы на "главной странице", и если да, то используем ли мы канонический URL для нашей главной страницы: в вашем случае это http://108.166.64.229/. Если нет, вас перенаправят туда. Вы заметите, что http://108.166.64.229/example также перенаправляет туда.
Вы можете отключить это. Канонизация выполняется на хуке template_redirect
. Поэтому вы можете просто удалить её:
remove_filter('template_redirect', 'redirect_canonical');
Или вы можете "отменить" её (в конкретном случае вашей главной страницы), используя хук, который находится внутри callback-функции redirect_canonical
:
add_filter('redirect_canonical', 'wpse51530_redirect_canonical', 10, 2);
function wpse51530_redirect_canonical($redirect_url, $requested_url){
if( is_front_page() )
return $requested_url;
else
return $redirect_url;
}
Вы можете посмотреть, как WordPress выполняет канонизацию, здесь.
