Проблема с правилами перезаписи, когда правило включает слаг главной страницы

8 мая 2012 г., 18:32:13
Просмотры: 1.97K
Голосов: 0

У меня есть страница 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');

Я получил разные результаты в трех сценариях:

  1. При переходе на /example/view-section происходит редирект на /, а значения query vars пустые.
  2. При переходе на /index.php?pagename=example&foo=1&bar=2 все работает как нужно - отображается контент, сгенерированный шорткодом, с переданными значениями query vars.
  3. Если использовать page_id вместо pagename или page: /index.php?page_id=443&foo=1&bar=2, query var page_id удаляется и снова показывается главная страница по умолчанию.

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

Важно отметить: если страница Example не настроена как главная, сценарии 1 и 3 работают так же, как сценарий 2.

Буду благодарен за помощь и готов предоставить дополнительные детали при необходимости.

ОБНОВЛЕНИЕ

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

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

Что произойдет, если вы снова сохраните настройки постоянных ссылок и затем попробуете?

Stephen Harris Stephen Harris
8 мая 2012 г. 18:58:30

@Stephen Harris, я получаю такие же результаты. Думаю, повторное сохранение постоянных ссылок имеет тот же эффект, что и вызов flush_rewrite_rules или $wp_rewrite->flush_rules, верно? Также на странице результатов видно, что правило правильно добавляется в массив $wp_rewrite->rules. Спасибо.

Willington Vega Willington Vega
8 мая 2012 г. 20:23:02
Все ответы на вопрос 1
1

Проблема не связана с правилами перезаписи (хотя я бы предложил использовать add_rewrite_rule() вместо более низкоуровневого подхода с прямым изменением массива перезаписи. То же самое касается flush_rewrite_rules(). Кроме того, хотя в вашем случае правила перезаписываются только один раз — лучше делать это при активации плагина, а не внутри условия, которое проверяется при каждой загрузке страницы.

... так что "проблема" на самом деле связана с канонизацией. По сути, различные URL могут указывать на один и тот же контент (включая URL с дополнительными слешами). Идея заключается в следующем:

  1. С точки зрения SEO это плохо — если поисковые системы не поймут, что все эти URL представляют один и тот же ресурс, они могут начать конкурировать друг с другом.
  2. Плохо с точки зрения пользователя. Если они перейдут по адресу 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 выполняет канонизацию, здесь.

8 мая 2012 г. 22:01:12
Комментарии

Спасибо @StephenHarris, это отличное объяснение проблемы, с которой я столкнулся, и ваши рекомендации сразу указали мне на решение.

Willington Vega Willington Vega
9 мая 2012 г. 16:32:18