Управление созданием правил перезаписи URL в плагинах WordPress

Владимир | | PHP, Web разработка, WordPress.

wp rewrite rules

В WordPress входит группа функций, которые позволяют определять собственную структуру URL. К ним относятся add_rewrite_rule(), add_rewrite_tag(), flush_rules() и т.п. Использование этих функций достаточно подробно описано в документации, но у движка есть особенности, которые могут привести к неожиданным проблемам.

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

Для того, чтобы добавить правило нужно:

1) Вызвать функцию add_rewrite_rule и передать ей регулярное выражение для разбора параметров.

function add_my_rules() {
    add_rewrite_rule( 'my_param/(\d+)?$', 'index.php?my_param=$matches[1]', 'top' );
}

2) Добавить новую переменную в объект WP_Query. Для этого используется фильтр query_vars.

add_filter( 'query_vars', 'add_query_vars' );
function add_query_vars( $vars ) {
    $vars[] = 'my_param';
    return $vars;
}

В первом параметре функция add_query_vars получит массив со всеми переменными WP_Query и мы сможем добавить в этот массив имя нашего параметра (my_param).

После этого можно получить значение параметра с помощью get_query_var(). Например,

$my_param_value = get_query_var('my_param');
...

Т.е. мы сможем использовать полученное значение, например, при выборке постов (в обработчике события pre_get_posts) или прямо в шаблонах темы. Тут возможности ограничены только вашей фантазией и задачами.

Остаётся только один вопрос: «Когда вызывать add_my_rules?»

Если правила добавляются в плагине, то логично для этих целей использовать события активации и деактивации. Т.е. сделать что-то вроде:

register_activation_hook( __FILE__, 'my_plugin_setup' );
function my_plugin_setup() {
    add_my_rules();
    flush_rewrite_rules();
}

register_deactivation_hook( __FILE__, 'deactivate' );
function deactivate() {
    flush_rewrite_rules();
}

В результате всё будет работать, т.к. при активации плагина правила добавляются, а при деактивации — происходит перезапись правил, без вызова функции add_rewrite_rules, т.е. без новых правил.

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

Обратите внимание. Для повышения производительности WP кэширует правила. Поэтому для того, чтобы перезаписать правила обязательно нужно вызвать flush_rewrite_rules (сбрасывает кэш). При этом, flush_rewrite_rules может вызываться самим движком (например, при сохранении ЧПУ) и может вызываться другими плагинами.

Решение.

Очевидно, что register_activation_hook для установки правил не подходит, т.к. вызывается только один раз при активации плагина. Нам нужно использовать событие, которое возникает при каждом пересоздании правил.

Изменим наш код следующим образом.

Убираем вызов add_my_rules из register_activation_hook и добавляем обработчик события generate_rewrite_rules

add_action( 'generate_rewrite_rules', 'add_my_rules' );

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

Исправить проблему можно следующим образом.

Добавляем переменную

$is_deactivating = false;

устанавливаем её равной true при вызове deactivate

function deactivate() {
    $this->is_deactivating = true;
    flush_rewrite_rules();
}

и добавляем проверку при установке правила

function add_my_rules() {
    if ($this->is_deactivating === false) {
        add_rewrite_rule( 'my_param/(\d+)?$', 'index.php?my_param=$matches[1]', 'top' );
    }
}

Теперь при деактивации плагина будет проверяться значение переменной $is_deactivating и если оно равно true, то наши правила добавляться не будут.

Как видите, решение довольно простое, но при условии, что вы понимаете, как работает движок. Помнить обо всех нюансах очень сложно, но есть общее правило – если вы используете встроенные возможности WP, в первую очередь ищите соответствующие события.

Успехов!