Нужна помощь с add_rewrite_rule

15 дек. 2010 г., 17:04:34
Просмотры: 69.2K
Голосов: 58

РЕШЕНИЕ


Я использовал Обновление 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/

  1. Как мне использовать add_rewrite_rule()?
  2. Мне нужно передать 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;
}

Я был бы действительно признателен, если бы кто-то смог помочь мне решить эту проблему.

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

Это выглядит очень похоже на первый вопрос, который вы задали здесь, и на который я дал ответ. Ситуация изменилась с тех пор, и мой ответ больше не актуален? Если вы не хотите, чтобы ID дизайнера был в вашем URL, вам нужно будет самостоятельно преобразовывать "slug" в ID, WordPress не может сделать это за вас. Дизайнеры всё ещё являются внешними объектами?

Jan Fabry Jan Fabry
16 дек. 2010 г. 00:47:11

@Jan Fabry Да, я обнаружил это после публикации (я забыл). Теперь я также лучше понимаю ваше предложение. Смотрите мой обновлённый код здесь. Мои дизайнеры всё ещё являются записями в пользовательской БД. Можно ли использовать POST вместо GET для передачи bid?

Steven Steven
16 дек. 2010 г. 01:04:44

Использование POST-запроса не сработает, если я скопирую ссылку и отправлю её кому-то ещё. Разве нельзя сделать slug уникальным и выполнять поиск данных на его основе?

Jan Fabry Jan Fabry
16 дек. 2010 г. 01:57:32

@Jan Fabry: Что ты имеешь в виду под slug? Получать данные о Дизайнере гораздо проще используяbidвместоdesigner`

Steven Steven
16 дек. 2010 г. 03:18:13
Все ответы на вопрос 1
15
91

Немного о правилах перезаписи 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() не сработала для него.

16 дек. 2010 г. 12:07:23
Комментарии

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

Steven Steven
16 дек. 2010 г. 12:18:27

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

Jan Fabry Jan Fabry
16 дек. 2010 г. 12:35:00

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

Steven Steven
16 дек. 2010 г. 12:43:09

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

Jan Fabry Jan Fabry
16 дек. 2010 г. 12:52:04

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

Steven Steven
16 дек. 2010 г. 13:01:11

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

Jan Fabry Jan Fabry
16 дек. 2010 г. 13:05:19

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

Steven Steven
16 дек. 2010 г. 13:23:54

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

Jan Fabry Jan Fabry
16 дек. 2010 г. 13:32:10

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

Steven Steven
16 дек. 2010 г. 15:18:33

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

Jan Fabry Jan Fabry
16 дек. 2010 г. 15:28:29

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

Steven Steven
16 дек. 2010 г. 20:01:46

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

Jan Fabry Jan Fabry
17 дек. 2010 г. 00:50:00

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

Steven Steven
17 дек. 2010 г. 02:09:40

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

v3nt v3nt
22 мая 2012 г. 16:40:32

Большое спасибо. По какой-то причине мне также пришлось использовать фильтр. Ваша дискуссия очень помогла!

Alexandre Bourlier Alexandre Bourlier
21 февр. 2015 г. 20:20:16
Показать остальные 10 комментариев