Нужна помощь с add_rewrite_rule
РЕШЕНИЕ
Я использовал Обновление 3 и добился работы. То, что я неправильно понял, это то, что я думал, что правило перезаписи изменит designers/?designer=some-designer&bid=9
на /designers/some-designer
. Но на самом деле всё наоборот.
Я провел некоторые исследования, но не совсем понимаю, как использовать add_rewrite_rule().
Этот пост довольно близок к тому, что мне нужно, но действительно ли мне нужно так много кода?
Мой текущий URL такой:
http://www.norwegianfashion.no/designers/?designer=Batlak-og-Selvig&bid=9
Я хочу получить такой:
http://www.norwegianfashion.no/designers/Batlak-og-Selvig/
- Как мне использовать
add_rewrite_rule()
? - Мне нужно передать ID дизайнера (bid). Как я могу это сделать при использовании правил перезаписи так, чтобы он не отображался в URL?
Обновление 1
Я нашел это, что немного более понятно. Но это не работает:
function add_rewrite_rules( $wp_rewrite )
{
$new_rules = array(
'('.$template_page_name.')/designers/(.*?)/?([0-9]{1,})/?$' => 'designers.php?designer='.
$wp_rewrite->preg_index(1).'&bid='.
$wp_rewrite->preg_index(2)
);
// Всегда добавляйте свои правила в начало, чтобы убедиться, что ваши правила имеют приоритет
$wp_rewrite->rules = $new_rules + $wp_rewrite->rules;
}
add_action('generate_rewrite_rules', 'add_rewrite_rules');
function query_vars($public_query_vars) {
$public_query_vars[] = "designer";
$public_query_vars[] = "bid";
return $public_query_vars;
}
add_filter('query_vars', 'query_vars')
Обновление 2
Вот другое решение, которое я попробовал, предложенное Jan Fabry в другой теме. Я поместил это в functions.php, но это не имеет никакого эффекта.
add_action('generate_rewrite_rules', 'add_rewrite_rules');
add_filter('query_vars', 'query_vars');
/* Пользовательские правила перезаписи для дизайнеров
------------------------------------------------------------------------------*/
function add_rewrite_rules( $wp_rewrite )
{
add_rewrite_rule('^designers/([^/]*)/([^/]*)$ /designers/?designer=$1&bid=$2 [L]', 'top');
flush_rewrite_rules(false);
}
function query_vars($public_query_vars) {
$public_query_vars[] = "designer";
$public_query_vars[] = "bid";
return $public_query_vars;
}
Обновление 3
Я также нашел несколько примеров здесь. Но это тоже не работает :(
add_filter('rewrite_rules_array','wp_insertMyRewriteRules');
add_filter('query_vars','wp_insertMyRewriteQueryVars');
add_filter('init','flushRules');
// Не забудьте выполнить flush_rules() при добавлении правил
function flushRules(){
global $wp_rewrite;
$wp_rewrite->flush_rules();
}
// Добавление нового правила
function wp_insertMyRewriteRules($rules)
{
$newrules = array();
$newrules['(designers)/(\d*)$'] = 'index.php?pagename=designers&designer=$matches[1]';
return $newrules + $rules;
}
// Добавление переменной bid, чтобы WP распознавал её
function wp_insertMyRewriteQueryVars($vars)
{
array_push($vars, 'designer');
return $vars;
}
Обновление 4 Я также попробовал это решение, но всё ещё безуспешно.
add_filter('search_rewrite_rules', 'designers_createRewriteRules');
function designers_createRewriteRules($rewrite) {
global $wp_rewrite;
// добавление токенов перезаписи
$designer_token = '%designers%';
$wp_rewrite->add_rewrite_tag($designer_token, '(.+)', 'designers=');
$bid_token = '%bid%';
$wp_rewrite->add_rewrite_tag($bid_token, '(.+)', 'bid=');
$keywords_structure = $wp_rewrite->root . "designers/$designer_token/$bid_token";
$keywords_rewrite = $wp_rewrite->generate_rewrite_rules($keywords_structure);
return ( $rewrite + $keywords_rewrite );
}
Обновление 5
Похоже, что мои правила перезаписи не добавляются.
Выполнение следующего после добавления новых правил: print_r($wp_rewrite)
, не включает мои новые правила перезаписи.
Обновление 6
Я протестировал решение Jana. Но URL не меняется :(
/* Скрипт инициализации для шаблона NF
------------------------------------------------------------------------------*/
add_action('after_setup_theme','norwegianfashion_setup');
if ( ! function_exists( 'norwegianfashion_setup' ) ):
function norwegianfashion_setup() {
/* Здесь я делаю много всего */
// SEO-дружественный URL для дизайнеров
add_action( 'init', 'wpa5413_init' );
add_filter( 'query_vars', 'wpa5413_query_vars' );
}
endif;
/* Пользовательские правила перезаписи для дизайнеров
------------------------------------------------------------------------------*/
function wpa5413_init()
{
// Не забудьте сбросить правила вручную один раз после добавления этого кода!
add_rewrite_rule(
'designers/([^/]+)/?',
'index.php?pagename=designers&designer=$matches[1]',
'top' );
}
function wpa5413_query_vars( $query_vars )
{
$query_vars[] = 'designer';
return $query_vars;
}
Я был бы действительно признателен, если бы кто-то смог помочь мне решить эту проблему.

Немного о правилах перезаписи URL
Система перезаписи URL в WordPress кажется сложной, но на самом деле понять, как она работает, не так уж трудно. Она используется для обработки "красивых" URL (/designers/
), как если бы они были обычными (/index.php?pagename=designers
). Основная идея состоит в том, что у вас есть список правил перезаписи — регулярных выражений, которые могут сопоставлять входящие URL и преобразовывать их в другие URL, в основном в виде index.php
с некоторыми переменными запроса. Эти переменные устанавливаются в соответствии с частями регулярного выражения, которые соответствуют URL. Правила оцениваются сверху вниз, поэтому если два правила могут совпасть, "выигрывает" первое.
Эти правила перезаписи хранятся в базе данных при вызове flush_rewrite_rules()
, но поскольку генерация и запись этих правил — это дорогая операция, вы не должны делать это при каждом init
. Вместо этого делайте это только когда изменяете правила: вероятно, при активации плагина (используя register_activation_hook()
) или вручную, посетив страницу настроек Постоянных ссылок (потому что автоматически сделать это при активации темы сложно). Если вы не сбросите правила, вызов add_rewrite_rule()
не даст эффекта. Нет проблем вызывать add_rewrite_rule()
при каждом init
, даже после сброса правил.
Есть много способов добавить свои правила перезаписи, и если вам нужно добавить только одно правило, вы можете сделать это с помощью add_rewrite_rule()
. Поскольку правила для записей, страниц, таксономий и т.д. приводят к множеству правил, они создаются с помощью высокоуровневых функций, таких как add_rewrite_tag()
, add_permastruct()
, и т.д. Но они не нужны для простого случая, который мы рассматриваем здесь.
Также есть некоторые фильтры, поэтому вы можете добавить свои правила, используя хуки generate_rewrite_rules
или generate_rewrite_rules_array
. Они дают очень детальный контроль над всеми правилами, но опять же, add_rewrite_rule()
достаточно, если вы просто хотите добавить одно правило.
Я создал небольшой плагин, который позволяет анализировать текущие правила перезаписи, и (конечно) рекомендую использовать его при попытке что-либо изменить.
Получение дополнительной информации из URL
Давайте продолжим на вашем примере. У вас есть бренд дизайнеров Batlak og Selvig
с числовым ID (bid
) 9
. Вы не хотите видеть этот ID в URL, а только имя. Мы называем URL-дружественную версию имени (без пробелов и специальных символов) слагом: Batlak-og-Selvig
.
В общем случае URL должен содержать всю информацию для идентификации контента, который вы хотите показать на странице. Вы можете использовать куки или POST-запросы для хранения ID дизайнера, но это перестанет работать, если кто-то поделится ссылкой, отправив её по почте, через Facebook, Twitter или просто продиктует по телефону. Если вы не хотите использовать числовой ID в URL, убедитесь, что слаг уникален: сначала выполните поиск ID на основе слага, а затем продолжайте, как делали раньше.
Итак, что мы поняли: мы хотим добавить правило перезаписи для шаблона "/designers/
, за которым следует что угодно до следующего /
", и сохранить это "что угодно" в переменной запроса designer_slug
. В вашем случае, я полагаю, вы также хотите использовать страницу со слагом designers
в качестве основного контента, поэтому мы также сообщим об этом WordPress.
add_action( 'init', 'wpa5413_init' );
function wpa5413_init()
{
// Не забудьте вручную сбросить правила после добавления этого кода!
add_rewrite_rule(
// Регулярное выражение для сопоставления входящего URL
'designers/([^/]+)/?',
// Результирующий внутренний URL: `index.php`, потому что мы используем WordPress
// `pagename`, потому что мы используем эту страницу WordPress
// `designer_slug`, потому что мы присваиваем первую захваченную часть регулярного выражения этой переменной
'index.php?pagename=designers&designer_slug=$matches[1]',
// Это довольно специфичный URL, поэтому добавляем его в начало списка
// Иначе "универсальные" правила внизу (для страниц и вложений) "победят"
'top' );
}
Осталось только сообщить WordPress, чтобы он также сохранял designer_slug
в переменных запроса, чтобы вы могли получить к нему доступ позже. WordPress использует белый список разрешённых переменных запроса, чтобы предотвратить изменение каждого параметра запроса через URL. Всё, что не в этом списке, игнорируется. Просто подключитесь к хуку query_vars
и добавьте свою переменную:
add_filter( 'query_vars', 'wpa5413_query_vars' );
function wpa5413_query_vars( $query_vars )
{
$query_vars[] = 'designer_slug';
return $query_vars;
}
Как видите, этот ответ в основном совпадает с моим предыдущим ответом, но без сброса правил в коде (так что вы можете использовать его в functions.php
вашей темы вместо плагина), и с большей уверенностью и объяснениями, потому что я много узнал о правилах перезаписи с момента (и из-за) ответа на ваш первый вопрос.
Обсуждение в чате
Мы уточнили окончательные вопросы по этой теме в чате. В итоге Стивен использовал хук generate_rewrite_rules
, потому что функция add_rewrite_rule()
не сработала для него.

Спасибо за развернутый фидбек! Я продолжаю видеть index.php?pagename=designers
. Моя страница / шаблон Designers
использует файл designers.php. Разве мы не должны использовать именно его?

@Steven: pagename
— это slug страницы WordPress, которую вы хотите отобразить (запись в базе данных). Эта страница затем может указывать, что хочет использовать файл шаблона designers.php
в админке WP. Таким образом, вы указываете slug страницы, а не название шаблона, поскольку один и тот же шаблон может использоваться для нескольких страниц: в данном случае WordPress не понимает, что именно вы хотите сделать.

Смотрите мой Update 6, это код, который я сейчас тестирую. Но URL по-прежнему остается с /?designer=Batlak-og-Selvig&bid=9
:( Есть ли способ проверить, были ли добавлены правила rewrite?

@Steven: Мне кажется, вы слишком усложняете настройку хуков. Удалите функцию add_rewrite_rules()
и вызывайте add_filter()/add_action()
напрямую. Если это в файле темы, уберите flush_rewrite_rules()
и просто посетите страницу настроек постоянных ссылок, чтобы сбросить правила (или добавьте их в wpse5413_init()
и удалите позже). Мой плагин отображает текущие правила перезаписи. Помните, что это меняет только обработку входящих URL, а не то, как ваш код формирует URL в HTML.

@Jan Fabry: Хорошо, я обновил код, удалив функцию add_rewrite_rules()
. Также попытался разместить add_filter
и add_Action
в самом верху файла функций. Единственный способ вручную сбросить постоянные ссылки - это нажать кнопку сохранения? Но URL в браузере все равно остается прежним :(

@Steven: Думаю, вам даже не нужно нажимать кнопку сохранения - просто открытие страницы постоянных ссылок также сбрасывает их. И снова: это только добавит WordPress возможность обрабатывать URL вида /designers/designer-slug/
, но вам нужно самостоятельно изменить места, где вы формируете эти URL в вашем HTML. Проверьте, перейдя по /designers/Batlak-og-Selvig/
вручную - если это работает, найдите все места генерации таких URL и измените их для использования новой структуры.

А, кажется, я начинаю понимать. Я думал, что правила перезаписи изменяют то, как URL отображается в адресной строке браузера. Но на самом деле это означает, что я должен выводить URL в виде www.mysite.com/batlat-og-selvig/9
, а затем он "преобразуется" в /?designer=Batlak-og-Selvig&bid=9

@Steven: Да, именно так: правила перезаписи обрабатывают входящие ссылки и (только в некоторых случаях) не влияют на генерируемые ссылки в вашем коде.

@Jan Fabry: Хорошо, теперь я создал уникальный ярлык для каждого дизайнера. Ссылка на страницу дизайнера теперь выглядит так http://norwegianfashion.com/designers/batlak-og-selvig
(я использую .com на localhost). Но мое правило перезаписи не срабатывает. Я просто получаю ошибку 404 - Страница не найдена.

@Steven: И твое правило перезаписи в списке, наверху? Если ты можешь зайти в чат, мы попробуем разобраться там.

@Jan Fabry: Должен ли я использовать $_GET['designer'] для получения слага / имени дизайнера?

@Steven: Думаю, "официальный" метод это $wp_query->get( 'designer' )

@Jan Fabry: Спасибо, Ян. Теперь вы можете увидеть это в действии :) http://www.norwegianfashion.no/designers/batlak-og-selvig/

Ян - что должно быть в pagename, если мы хотим загрузить запись пользовательского типа поста (directors) под названием test-director в single-directors.php. В настоящее время возникают проблемы с реализацией этого; 'directors/(.+?)/showreels/([^/])/video/([^/])/?', 'index.php?whatgoeshere!!!=???&showreel=$matches[2]&video=$matches[3]'
