Понимание add_rewrite_rule

31 дек. 2016 г., 01:34:12
Просмотры: 52.3K
Голосов: 21

Я пытаюсь настроить работу 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 (Отдельная запись произвольного типа)
2
Комментарии

любой URL, включая записи, рубрики, метки и т.д., а не только тип записи page, или просто любую страницу? как насчёт родительских/дочерних страниц в иерархии?

Milo Milo
31 дек. 2016 г. 02:05:08

@Milo Я уточнил для вас. Я использую только страницы и пользовательские типы записей (архивы и отдельные страницы).

Louis W Louis W
31 дек. 2016 г. 02:07:00
Все ответы на вопрос 2
8
17

Основное правило, которое подойдет для вашего примера:

function wpd_foo_rewrite_rule() {
    add_rewrite_rule(
        '^foo/([^/]*)/?',
        'index.php?pagename=$matches[1]&param=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 упрощает добавление всех необходимых правил, включая поддержку пагинации.

2 янв. 2017 г. 05:15:52
Комментарии

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

Louis W Louis W
2 янв. 2017 г. 06:51:46

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

Milo Milo
2 янв. 2017 г. 09:00:13

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

Louis W Louis W
2 янв. 2017 г. 18:50:49

Кроме того, похоже, это не работает для подстраниц.

Louis W Louis W
2 янв. 2017 г. 20:59:03

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

Milo Milo
3 янв. 2017 г. 00:08:39

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

Louis W Louis W
3 янв. 2017 г. 00:25:18

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

Milo Milo
3 янв. 2017 г. 02:15:12

Примеры были добавлены.

Louis W Louis W
3 янв. 2017 г. 04:09:42
Показать остальные 3 комментариев
1

Хорошо, я получил рабочие примеры для всех 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 выполняет запросы к страницам/записям.

5 янв. 2017 г. 17:51:59
Комментарии

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

Debbie Kurth Debbie Kurth
10 нояб. 2019 г. 10:52:42