Статьи

Написание расширяемых плагинов с действиями и фильтрами

Одна из многих вещей, которые вы найдете, исследуя исходный код хорошего разработчика плагина, — это пользовательские хуки и фильтры, которые разработчик поместил по всему плагину. Наличие этих хуков действий и фильтров делает плагин «расширяемым», что означает, что другие плагины и темы могут манипулировать или добавлять в поведение плагина.

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

Мы рассмотрим несколько элементов расширяемых плагинов:

  • Объяснение того, что расширяемые плагины
  • Причины, по которым вы должны писать расширяемые плагины
  • Основные инструменты, которые вам нужны
  • Как вам нужно написать свои плагины, чтобы сделать их расширяемыми
  • Простые примеры хуков и фильтров, чтобы показать, как вы можете их использовать

Одно важное замечание: в этом руководстве будут использоваться чисто процедурные методы программирования . Все, о чем я здесь говорю, по-прежнему применимо при использовании объектно-ориентированного программирования (ООП), но вначале проще изучить эти методы в процедурных условиях.


Расширяемый плагин — это тот, который может быть изменен и расширен за пределы своего первоначального назначения другим плагином или темой. Когда плагин является расширяемым, другие плагины (или темы) могут изменить поведение или вывод плагина. Например, плагины электронной коммерции позволяют использовать дополнительные платежные шлюзы, которые позволяют обрабатывать покупки через дополнительные платежные системы. Эти платежные шлюзы представляют собой отдельные плагины, которые просто подключаются к основному плагину и расширяют его функциональные возможности.

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


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

Когда вы пишете расширяемые плагины, вы позволяете другим разработчикам расширять ваш плагин и делать его еще лучше, но без изменения исходного кода ядра. Вы также значительно облегчаете разработчикам и пользователям адаптацию плагина под свои нужды. Позвольте мне привести пример: в моем плагине Easy Digital Downloads есть система скидок. Коды скидок ограничены однократным использованием для каждого пользователя, поэтому, если пользователь попытается применить одинаковую скидку к двум разным покупкам, он получит ошибку. Один из моих реальных пользователей обнаружил, что она не хочет ограничивать скидки на одно использование для каждого пользователя, поэтому я дал ей простую функцию: она добавила новый пользовательский плагин, и ограничение было снято, не затрагивая код основного плагина. ,

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


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

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

Хук действия — это место в вашем плагине, в которое можно «зацепить» функции (как в вашем плагине, так и в других плагинах), чтобы их код выполнялся в этот момент. Когда запускается ловушка действий, все функции, которые подключены или «подключены» к нему, также будут работать.

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

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

Если вы не очень хорошо знакомы с действиями и фильтрами, я настоятельно рекомендую вам прочесть на них записи Кодекса .

Для действий есть четыре основные функции:

  • do_action() — это определяет подключаемое местоположение для действий
  • add_action() — это прикрепляет функцию к do_action() созданному с помощью do_action()
  • has_action() — проверяет, было ли зарегистрировано действие с помощью do_action()
  • remove_action() — удаляет действие, которое было установлено с помощью add_action()

Из этих четырех вы do_action() будете использовать do_action() и add_action() .

Для фильтров также есть четыре основные функции:

  • apply_filters() — это создает подключаемое местоположение для пользовательских фильтров, чтобы связать их
  • add_filter() — это прикрепляет пользовательский фильтр к apply_filters() созданной с помощью apply_filters()
  • has_filter() — проверяет, был ли зарегистрирован фильтр с apply_filters()
  • remove_filter() — это удаляет фильтр, ранее связанный с apply_filters()

Как и в случае действий, apply_filters() и add_filter() — это те два, которые вы будете использовать чаще всего.

Если вы запутались в этом вопросе, не беспокойтесь, мы рассмотрим, как на самом деле использовать их в следующем разделе.


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

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

Существует несколько основных сценариев, в которых вы будете использовать фильтры в своих плагинах:

  • Когда массивы настроены. Здесь будут добавлены фильтры, чтобы другие плагины могли изменять данные перед их использованием.
  • Когда объекты данных настроены. Как и в случае с массивами, вы будете использовать фильтр для объектов, чтобы другие разработчики могли изменять объект перед его использованием.
  • Когда строки данных настроены. С помощью фильтра, доступного для строки, другие разработчики могут изменить всю строку, изменить ее части или добавить к ней.

Из приведенных выше сценариев чаще всего используются фильтры, когда данные возвращаются или непосредственно перед их использованием. Например, если у вас есть плагин, который выполняет запрос сообщений, лучше всего передать массив аргументов запроса через фильтр, прежде чем они будут переданы в get_posts() или WP_Query чтобы другие могли манипулировать запросом перед его выполнением.

Когда дело доходит до действий, есть также несколько основных случаев, где вы будете их размещать:

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

Давайте рассмотрим несколько примеров.

Шорткоды, которые выводят HTML, чрезвычайно распространены (на самом деле они, вероятно, являются наиболее распространенными из всех шорткодов), и один из способов сделать шорткоды нашего плагина более дружественными для других разработчиков — это предоставить им возможность изменять содержимое шорткод, но без необходимости отмены регистрации и повторной регистрации.

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

Разработчик может захотеть добавить дополнительную разметку до и после HTML по умолчанию: с установленным фильтром они могут это сделать.

Ваш шорткод может выглядеть примерно так:

1
2
3
4
5
6
7
8
9
function wptp_sample_shortcode( atts, $content = null ) {
 
    $html = ‘<div class=»wptp_shortcode»>’;
        $html .= ‘<p>Contents of the sample shortcode</p>’;
    $html .= ‘</div>’;
 
    return $html;
 
}

Мы можем улучшить это, добавив фильтр к возврату, например так:

1
2
3
4
5
6
7
8
9
function wptp_sample_shortcode( atts, $content = null ) {
 
    $html = ‘<div class=»wptp_shortcode»>’;
        $html .= ‘<p>Contents of the sample shortcode</p>’;
    $html .= ‘</div>’;
 
    return apply_filters( ‘wptp_shortcode_html’, $html );
 
}

HTML-код в нашем шорткоде теперь можно изменить следующим образом:

1
2
3
4
function wptp_modify_html( $html ) {
    return ‘<div class=»extra_div»>’ .
}
add_filter( ‘wptp_shortcode_html’, ‘wptp_modify_html’ );

Это приведет к тому, что исходный HTML-код, созданный в шорткоде, будет обернут другим тегом div .

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
function wptp_show_books() {
 
    $query_args = array(
        ‘post_type’ => ‘books’,
        ‘posts_per_page’ => 5
    );
 
    $books = new WP_Query( $query_args );
    if( $books->have_posts() ) :
        while( $books->have_posts() ) : $books->the_post()
            // show info about each book here
        endwhile;
    endif;
    wp_reset_postdata();
 
}

Но что если пользователь захочет изменить типы возвращаемых книг, возможно, выбрав только книги из определенной категории? Вы можете сделать это намного проще для них, сделав это:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
function wptp_show_books() {
 
    $query_args = array(
        ‘post_type’ => ‘books’,
        ‘posts_per_page’ => 5,
        ‘author’ => 3
    );
 
    $books = new WP_Query( apply_filters( ‘wptp_books_query’, $query_args ) ) ;
    if( $books->have_posts() ) :
        while( $books->have_posts() ) : $books->the_post()
            // show info about each book here
        endwhile;
    endif;
    wp_reset_postdata();
 
}

Единственное изменение, которое я сделал, было добавление фильтра вокруг $query_args , что означает, что другие разработчики (или пользователи) могут изменять аргументы запроса, прежде чем они действительно будут переданы в WP_Query . Например, мы можем установить запрос, чтобы показывать только книги автора 3 следующим образом:

1
2
3
4
5
function wptp_alter_books_query( $args ) {
    $args[‘author’] = 3;
    return $args;
}
add_filter( ‘wptp_books_query’, ‘wptp_alter_books_query’ );

Продолжим пример 2 и сделаем его еще лучше. Мы уже добавили фильтр, который позволяет пользователям изменять запрос, теперь давайте добавим несколько хуков, которые позволят нам изменить созданный HTML-код.

Сначала мы немного изменим наш оригинальный HTML:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function wptp_show_books() {
 
    $query_args = array(
        ‘post_type’ => ‘books’,
        ‘posts_per_page’ => 5,
        ‘author’ => 3
    );
 
    $books = new WP_Query( apply_filters( ‘wptp_books_query’, $query_args ) ;
    if( $books->have_posts() ) :
 
        echo ‘<div class=»wptp_books»>’;
 
            while( $books->have_posts() ) : $books->the_post()
 
                echo ‘<div class=»wptp_book»>’;
 
                    echo ‘<h3 class=»wptp_book_title»>’ .
 
                echo ‘</div>’;
 
            endwhile;
 
        echo ‘</div>’;
 
    endif;
    wp_reset_postdata();
 
}

Теперь мы хотели бы предоставить разработчикам возможность добавлять дополнительную разметку в различных точках, таких как:

  • Перед выводом любого HTML
  • После окончания HTML
  • Перед названием каждой книги
  • После названия каждой книги

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function wptp_show_books() {
 
    $query_args = array(
        ‘post_type’ => ‘books’,
        ‘posts_per_page’ => 5,
        ‘author’ => 3
    );
 
    $books = new WP_Query( apply_filters( ‘wptp_books_query’, $query_args ) );
    if( $books->have_posts() ) :
 
        do_action( ‘wptp_books_before’ );
        echo ‘<div class=»wptp_books»>’;
 
            while( $books->have_posts() ) : $books->the_post()
 
                echo ‘<div class=»wptp_book»>’;
 
                    do_action( ‘wptp_before_book_title’, get_the_ID() );
 
                    echo ‘<h3 class=»wptp_book_title»>’ .
 
                    do_action( ‘wptp_after_book_title’, get_the_ID() );
 
                echo ‘</div>’;
 
            endwhile;
 
        echo ‘</div>’;
        do_action( ‘wptp_books_after’ );
 
    endif;
    wp_reset_postdata();
 
}

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

1
2
3
4
function wptp_show_book_image( $book_id ) {
    echo get_the_post_thumbnail( $book_id, ‘thumbnail’ );
}
add_action( ‘wptp_before_book_title’, ‘wptp_show_book_image’ );

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

Soliloquy — это мощный плагин для WordPress, позволяющий быстро и эффективно создавать и поддерживать адаптивные, эффективные, безопасные и оптимизированные для SEO слайдеры изображений.

Почти все в этом плагине является расширяемым. Вот только один пример:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$labels = apply_filters( ‘tgmsp_post_type_labels’, array(
    ‘name’ => __( ‘Soliloquy’, ‘soliloquy’ ),
    ‘singular_name’ => __( ‘Soliloquy’, ‘soliloquy’ ),
    ‘add_new’ => __( ‘Add New’, ‘soliloquy’ ),
    ‘add_new_item’ => __( ‘Add New Soliloquy Slider’, ‘soliloquy’ ),
    ‘edit_item’ => __( ‘Edit Soliloquy Slider’, ‘soliloquy’ ),
    ‘new_item’ => __( ‘New Soliloquy Slider’, ‘soliloquy’ ),
    ‘view_item’ => __( ‘View Soliloquy Slider’, ‘soliloquy’ ),
    ‘search_items’ => __( ‘Search Soliloquy Sliders’, ‘soliloquy’ ),
    ‘not_found’ => __( ‘No Soliloquy Sliders found’, ‘soliloquy’ ),
    ‘not_found_in_trash’ => __( ‘No Soliloquy Sliders found in trash’, ‘soliloquy’ ),
    ‘parent_item_colon’ => »,
    ‘menu_name’ => __( ‘Soliloquy’, ‘soliloquy’ )
) );
 
$args = apply_filters( ‘tgmsp_post_type_args’, array(
    ‘labels’ => $labels,
    ‘public’ => true,
    ‘exclude_from_search’ => true,
    ‘show_ui’ => true,
    ‘show_in_admin_bar’ => false,
    ‘rewrite’ => false,
    ‘query_var’ => false,
    ‘menu_position’ => 100,
    ‘menu_icon’ => plugins_url( ‘css/images/menu-icon.png’, dirname( __FILE__ ) ),
    ‘supports’ => array( ‘title’ )
) );

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

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

01
02
03
04
05
06
07
08
09
10
11
function bbp_get_forum_content( $forum_id = 0 ) {
    $forum_id = bbp_get_forum_id( $forum_id );
 
    // Check if password is required
    if ( post_password_required( $forum_id ) )
        return get_the_password_form();
 
    $content = get_post_field( ‘post_content’, $forum_id );
 
    return apply_filters( ‘bbp_get_forum_content’, $content, $forum_id );
}

Перед bbp_get_forum_content содержимого форума он проходит через фильтр bbp_get_forum_content который позволяет разработчику изменять содержимое до его отображения.

Easy Digital Downloads , или EDD, является одним из моих плагинов, который был создан для того, чтобы упростить продажу цифровых продуктов через WordPress. Как и в случае с большинством плагинов для электронной коммерции, в EDD есть процесс оплаты, через который покупатель может ввести свои личные данные и информацию об оплате. После того, как вся эта информация собрана, она отправляется в платежный шлюз (систему для обработки платежа), но перед тем, как она попадает в шлюз, применяется фильтр, который позволяет манипулировать данными, прежде чем они будут использованы платежом. система:

1
2
3
4
5
$purchase_data = apply_filters(
    ‘edd_purchase_data_before_gateway’,
    $purchase_data,
    $valid_data
);

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


Расширяемые плагины приносят пользу всем: первоначальному разработчику, другим разработчикам и самим пользователям.

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

Инструменты, представленные здесь, — это все, что вам нужно для начала. Есть вопросы? Спрашивай!