Где лучше всего использовать add_filter

12 янв. 2013 г., 07:23:45
Просмотры: 30.3K
Голосов: 15

Стоит ли использовать функцию add_filter в хуке действия init моего плагина или просто в основном скрипте плагина?

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

Есть ли общие рекомендации по приоритетности хуков action и filter, чтобы мы могли придерживаться более последовательного стиля кода?

0
Все ответы на вопрос 1
1
18

add_filter() и add_action() доступны до загрузки любых плагинов. Поэтому вы можете использовать их в первой строке вашего плагина или темы.

Для лучшей читаемости я рекомендую группировать регистрацию действий и фильтров в самом начале вашего главного файла:

  • в плагине — файл с заголовком плагина
  • в теме — functions.php

Есть исключения из этого правила:

  • Цепочки колбэков. В этом примере я регистрирую действие для shutdown только после того, как был вызван первый фильтр wp_nav_menu_objects. Поэтому второй колбэк не может быть зарегистрирован одновременно с первым.
  • ООП стиль. Иногда вам нужно настроить члены класса перед регистрацией колбэков. Используя очень похожий пример

    add_action(
        'plugins_loaded',
        array ( T5_Plugin_Class_Demo::get_instance(), 'plugin_setup' )
    );
    class T5_Plugin_Class_Demo
    {
        public function plugin_setup()
        {
            $this->plugin_url    = plugins_url( '/', __FILE__ );
            $this->plugin_path   = plugin_dir_path( __FILE__ );
            $this->load_language( 'plugin_unique_name' );
    
            // дополнительные действия: регистрация действий и фильтров
        }
    }
    

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

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

add_action( 'activate_header',      't5_activate_screen' );
// wp_loaded слишком поздно, WP кастомайзер не обнаружит функции.
add_action( 'after_setup_theme',    't5_setup_custom_background' );
add_action( 'after_setup_theme',    't5_setup_custom_header' );
add_filter( 'body_class',           't5_enhance_body_class' );
add_action( 'comment_form_before',  't5_enqueue_comment_reply' );
add_action( 'content_before',       't5_frontpage_widget' );
add_action( 'footer_before',        't5_loop_navigation' );
add_action( 'get_the_excerpt',      't5_excerpt_clean_up', 1 );
add_action( 'header_before',        't5_skiplink', 0, 0 );
add_filter( 'the_title',            't5_fill_empty_title', 20, 1 );
add_action( 'wp_enqueue_scripts',   't5_enqueue_style' );
add_action( 'wp_enqueue_scripts',   't5_enqueue_script' );
add_action( 'wp_loaded',            't5_setup' );
add_action( 'wp_loaded',            't5_page_enhancements' );
add_action( 'wp_loaded',            't5_post_format_support' );
add_action( 'wp_loaded',            't5_load_theme_language' );
add_action( 'wp_loaded',            't5_setup_sidebars' );
add_filter( 'wp_nav_menu_items',    't5_customize_top_menu', 10, 2 );
add_filter( 'wp_nav_menu_args',     't5_nav_menu_args', 10, 1 );
add_filter( 'wp_title',             't5_wp_title_filter', 20, 2 );

add_shortcode( 'gallery',    't5_shortcode_gallery' );
add_shortcode( 'wp_caption', 't5_shortcode_img_caption' );
add_shortcode( 'caption',    't5_shortcode_img_caption' );

// Используйте это действие для отмены регистрации действий и фильтров темы.
do_action( 't5_theme_hooks_registered' );

Последняя строка важна: дочерняя тема или плагин теперь могут подключиться к действию t5_theme_hooks_registered и отменить регистрацию любых предыдущих хуков. Это избавит от проблем с приоритетами, и я могу свободно менять приоритеты своих колбэков в любое время.

Но не полагайтесь только на порядок исходного кода. Документируйте используемые хуки в блоке документации. Я использую пользовательский тег wp-hook для этого. Вот пример с цепочками хуков из той же темы:

/**
 * Регистрация обработчика для автоматически создаваемого цитаты.
 *
 * @wp-hook get_the_excerpt
 * @param   string $excerpt
 * @return  string
 */
function t5_excerpt_clean_up( $excerpt )
{
    if ( ! empty ( $excerpt ) )
        return $excerpt;

    add_filter( 'the_content', 't5_excerpt_content' );

    return $excerpt;
}
/**
 * Удаление частей из автоматически создаваемой цитаты.
 *
 * @wp-hook the_content
 * @param   string $content
 * @return  string
 */
function t5_excerpt_content( $content )
{
    remove_filter( current_filter(), __FUNCTION__ );

    return preg_replace( '~<(pre|table).*</\1>~ms', '', $content );
}

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

12 янв. 2013 г. 08:08:49
Комментарии

+1. Что касается "стиля ООП", я предпочитаю передавать управление классу/объекту, который затем регистрирует действия/фильтры в своем конструкторе (или позже, если это уместно). Это обеспечивает лучшую (ООП!) инкапсуляцию и откладывает регистрацию хуков до момента использования/создания экземпляра класса.

webaware webaware
12 янв. 2013 г. 08:25:18