Статьи

Создание плагина предстоящих событий в WordPress: создание виджета

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

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

В заключительной части этой серии мы будем:

  • посмотрите на API виджетов WordPress
  • зарегистрировать виджет, чтобы показать список предстоящих событий
  • запросить базу данных о предстоящих событиях с помощью класса WP_Query
  • создайте мета-запрос для сравнения дат, чтобы появлялись только события в будущем

Давайте углубимся в процесс создания виджета WordPress с нуля.

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

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

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

  1. __construct()
  2. form()
  3. update()
  4. widget()

Давайте кратко рассмотрим каждый из них:

Метод __construct() инициализирует виджет. Он устанавливает имя виджета, базовый идентификатор и другую информацию, такую ​​как описание, класс виджета и т. Д.

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

Этот метод гарантирует, что виджет обновляется всякий раз, когда к экземпляру виджета применяется новый параметр. Он принимает два аргумента: один для старого экземпляра и один для нового экземпляра виджета.

Этот метод выводит содержимое виджета на внешний интерфейс сайта. Здесь мы определяем, что должны видеть пользователи при посещении сайта. Этот метод принимает два аргумента:

  1. $widget_args : это массив, содержащий необходимую информацию о виджете
  2. $instance : экземпляр отображаемого виджета

Мы немного подробнее рассмотрим эти методы и их аргументы. А пока давайте зарегистрируем наш класс виджетов.

В корневой папке плагина создайте новый каталог с именем inc для include. В этом каталоге создайте файл с именем widget-upcoming-events.php . Мы напишем весь наш код виджета в этом файле, чтобы держать вещи в чистоте и управляемости.

Мы начнем с расширения родительского класса виджета следующим образом:

1
2
3
4
<?php
class Upcoming_Events extends WP_Widget {
 
}

Чтобы зарегистрировать виджет, мы будем использовать функцию register_widget() в сочетании с хуком widgets_init :

1
2
3
4
function uep_register_widget() {
    register_widget( ‘Upcoming_Events’ );
}
add_action( ‘widgets_init’, ‘uep_register_widget’ );

Функция register_widget() принимает имя расширенного класса в качестве аргумента.

Внутри класса Upcoming_Events мы определим наши четыре метода для тех, которые мы рассмотрели в предыдущем разделе:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class Upcoming_Events extends WP_Widget {
 
    public function __construct() {
 
    }
 
 
    public function form( $instance ) {
 
    }
 
 
    public function update( $new_instance, $old_instance ) {
 
    }
 
 
    public function widget( $args, $instance ) {
 
    }
     
}

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

1
include( ‘inc/widget-upcoming-events.php’ );

Если у вас есть опыт работы в ООП, то вы наверняка знаете, что такое конструкторы. Для начинающих конструкторы — это специальные функции в классе, которые автоматически вызываются при создании объекта этого класса.

Так как у нас есть класс для виджета, нам нужна функция, которая устанавливает определенные вещи, такие как идентификатор и имя виджета, всякий раз, когда создается этот виджет, и именно здесь в игру вступает метод __construct() .

Метод __construct() родительского класса принимает три аргумента:

  1. $base_id : уникальный идентификатор для виджета
  2. $title : заголовок виджета в админке. Должны быть помечены для перевода
  3. $widget_ops : массив, содержащий другие параметры виджета, такие как класс виджета, описание виджета и т. д.

Теперь, когда мы знаем, что делает __construct() и какие аргументы он принимает, давайте напишем для него код:

01
02
03
04
05
06
07
08
09
10
11
12
public function __construct() {
    $widget_ops = array(
        ‘class’ => ‘uep_upcoming_events’,
        ‘description’ => __( ‘A widget to display a list of upcoming events’, ‘uep’ )
    );
 
    parent::__construct(
        ‘uep_upcoming_events’, //base id
        __( ‘Upcoming Events’, ‘uep’ ), //title
        $widget_ops
    );
}

В методе __construct() нашего виджета мы сделали вызов метода __construct() родительского класса, обозначенного parent::__construct() и передали три аргумента для опций base id, title и widget. Также обратите внимание, что строки помечаются для перевода с помощью функции __() .

Метод form() — это место, где мы определяем тело нашего виджета, который будет отображаться в админке WordPress. Он принимает один аргумент $instance для экземпляра виджета.

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

Сначала мы определим значения по умолчанию для наших полей:

1
2
3
4
5
6
$widget_defaults = array(
    ‘title’ => ‘Upcoming Events’,
    ‘number_events’ => 5
);
 
$instance = wp_parse_args( (array) $instance, $widget_defaults );

Мы определили наши значения по умолчанию в массиве с ключами в качестве имен полей. Затем мы использовали служебную функцию wp_parse_args() которая объединяет массив аргументов (в нашем случае — $instance ) с массивом значений по умолчанию (в данном случае — $widget_defaults ). Также обратите внимание, что мы ввели тип $instance в виде массива.

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

1
2
3
4
<p>
    <label for=»<?php echo $this->get_field_id( ‘title’ ); ?>»><?php _e( ‘Title’, ‘uep’ );
    <input type=»text» id=»<?php echo $this->get_field_id( ‘title’ ); ?>» name=»<?php echo $this->get_field_name( ‘title’ ); ?>» class=»widefat» value=»<?php echo esc_attr( $instance[‘title’] ); ?>»>
</p>

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

Метод, используемый для генерации идентификатора поля, — это get_field_id() которому предшествует $this-> , что означает, что этот метод принадлежит к тому же классу. Этот метод уже определен в базовом классе WP_Widget и, поскольку мы расширили его собственным классом, он становится легко доступным. Метод принимает аргумент для поля, для которого мы генерируем идентификатор.

Мы пометили текст метки для перевода с помощью функции _e() .

Следующий метод, который мы использовали, это get_field_name() который работает так же, как get_field_id() за исключением того, что он генерирует значение для атрибута name поля.

Класс widefat мы дали полю ввода, является классом WordPress по умолчанию, который widefat поля ввода в администраторе WordPress.

Затем для атрибута value поля ввода мы просто повторили содержимое $instance['title'] , передав его через esc_attr() для кодирования любых нежелательных символов.

Чтобы в раскрывающемся списке выберите количество отображаемых событий, добавьте следующий код в метод form() :

1
2
3
4
5
6
7
8
<p>
    <label for=»<?php echo $this->get_field_id( ‘number_events’ ); ?>»><?php _e( ‘Number of events to show’, ‘uep’ );
    <select id=»<?php echo $this->get_field_id( ‘number_events’ ); ?>» name=»<?php echo $this->get_field_name( ‘number_events’ ); ?>» class=»widefat»>
        <?php for ( $i = 1; $i <= 10; $i++ ): ?>
            <option value=»<?php echo $i; ?>» <?php selected( $i, $instance[‘number_events’], true );
        <?php endfor;
    </select>
</p>

Код почти такой же, как и код поля заголовка, за исключением того, что мы запустили цикл для создания тегов параметров. Чтобы проверить, выбран ли какой-либо параметр в данный момент, мы использовали другую служебную функцию WordPress selected() которая сравнивает два заданных значения (в данном случае — $i и $instance['number_events'] ), а затем добавляет selected атрибут в тег текущего параметра. если значения равны.

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

Метод update() позволяет обновлять значения, которыми управляет виджет. Он принимает два аргумента $old_instance и $new_instance и возвращает обновленный экземпляр виджета.

Код довольно прост:

1
2
3
4
5
6
7
8
public function update( $new_instance, $old_instance ) {
    $instance = $old_instance;
 
    $instance[‘title’] = $new_instance[‘title’];
    $instance[‘number_events’] = $new_instance[‘number_events’];
 
    return $instance;
}

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

Это самый важный метод из всех, так как он отображает намеченный контент на внешней стороне сайта. Он принимает два аргумента $args и $instance . Массив $args содержит следующие элементы:

  1. $name : имя боковой панели, в которой отображается виджет
  2. $id : идентификатор уважаемой боковой панели
  3. $description : описание боковой панели
  4. $class : класс боковой панели
  5. $before_widget : HTML- $before_widget , который предшествует виджету. Может быть открывающим тегом содержащего элемента
  6. $after_widget : HTML- $after_widget , следующий за виджетом. Обычно закрывающий тег содержащего элемента
  7. $before_title : HTML- $before_title который будет помещен перед заголовком виджета
  8. $after_title : HTML, которому предшествует заголовок виджета
  9. $widget_id : идентификатор этого конкретного экземпляра виджета. Это НЕ базовый идентификатор виджета
  10. $widget_name : имя виджета, переданное при регистрации виджета

Если вы когда-либо регистрировали боковую панель для темы WordPress, то первые восемь элементов массива $args должны казаться вам знакомыми. Последние два элемента зависят от виджета.

Давайте widget_title массив $args и применим фильтр widget_title к заголовку виджета:

1
2
3
4
public function widget( $args, $instance ) {
    extract( $args );
    $title = apply_filters( ‘widget_title’, $instance[‘title’] );
}

Теперь пришло время подготовить запрос для получения списка событий. Для этого мы будем использовать класс WP_Query вместе с мета-запросом:

01
02
03
04
05
06
07
08
09
10
11
$query_args = array(
    ‘post_type’ => ‘event’,
    ‘posts_per_page’ => $instance[‘number_events’],
    ‘post_status’ => ‘publish’,
    ‘ignore_sticky_posts’ => true,
    ‘meta_key’ => ‘event-start-date’,
    ‘orderby’ => ‘meta_value_num’,
    ‘order’ => ‘ASC’
);
 
$upcoming_events = new WP_Query( $query_args );

Поскольку мы хотим отсортировать наши события в порядке возрастания по датам их начала, мы установили для meta_key значение meta event-start-date наших событий. Наряду с этим мы сказали WordPress, что сравниваем здесь числа (а не строки), устанавливая meta_value_num в meta_value_num . Если вы установите meta_value только в meta_value , WordPress выполнит сравнение, как будто сравнивает строки, а это не то, что нам нужно.

Приведенный выше запрос извлечет указанное количество событий в порядке возрастания относительно их дат начала. Но мы также хотим отсеять события, которые уже прошли, т.е. их мета-значение event-end-date меньше, чем текущая отметка времени. Для этого мы передадим мета-запрос, который проверит даты их окончания:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
$meta_quer_args = array(
    ‘relation’ => ‘AND’,
    array(
        ‘key’ => ‘event-end-date’,
        ‘value’ => time(),
        ‘compare’ => ‘>=’
    )
);
 
$query_args = array(
    ‘post_type’ => ‘event’,
    ‘posts_per_page’ => $instance[‘number_events’],
    ‘post_status’ => ‘publish’,
    ‘ignore_sticky_posts’ => true,
    ‘meta_key’ => ‘event-start-date’,
    ‘orderby’ => ‘meta_value_num’,
    ‘order’ => ‘ASC’,
    ‘meta_query’ => $meta_quer_args
);
 
$upcoming_events = new WP_Query( $query_args );

В приведенном выше коде мы сравнили мета-значение event-end-date чтобы оно было больше или равно текущей отметке времени. Теперь будут извлечены только события с их мета-значениями event-end-date превышающими текущую метку времени, то есть события, предстоящие в будущем.

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

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
echo $before_widget;
if ( $title ) {
    echo $before_title .
}
?>
 
<ul class=»uep_event_entries»>
    <?php while( $upcoming_events->have_posts() ): $upcoming_events->the_post();
        $event_start_date = get_post_meta( get_the_ID(), ‘event-start-date’, true );
        $event_end_date = get_post_meta( get_the_ID(), ‘event-end-date’, true );
        $event_venue = get_post_meta( get_the_ID(), ‘event-venue’, true );
    ?>
        <li class=»uep_event_entry»>
            <h4><a href=»<?php the_permalink(); ?>» class=»uep_event_title»><?php the_title();
            <?php the_excerpt();
            <time class=»uep_event_date»><?php echo date( ‘F d, Y’, $event_start_date );
        </li>
    <?php endwhile;
</ul>
 
<a href=»<?php echo get_post_type_archive_link( ‘event’ ); ?>»>View All Events</a>
 
<?php
wp_reset_query();
 
echo $after_widget;

Приведенный выше код должен быть $before_widget : сначала мы повторили содержимое $before_widget как открывающий тег содержащего элемента. Затем мы проверили, есть ли у виджета заголовок, если это так, мы распечатали его, обернув его между $before_title и $after_title .

После этого мы просмотрели события, которые мы извлекли — распечатав их названия, выдержки и другую информацию, такую ​​как даты и места проведения. В конце мы добавили ссылку на их страницу архива, используя функцию get_post_type_archive_link() которая возвращает постоянную ссылку на страницу архива с указанным типом записи. Затем мы завернули наш виджет, повторив закрывающий тег $after_widget .

Давайте напишем несколько основных стилей для нашего виджета в файле css/style.css :

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
.uep_event_entry{
    margin-bottom: 21px;
}
 
.uep_event_entry h4{
    margin-bottom: 3px;
}
 
.uep_event_entry h4 a{
    text-decoration: none;
    color: inherit;
}
 
.uep_event_entry .event_venue{
    font-size: 0.9em;
    color: #777777;
    font-weight: normal;
    font-style: italic;
}
 
.uep_event_entry p{
    margin-bottom: 3px !important;
}
 
.uep_event_entry .uep_event_date{
    font-size: 0.9em;
    color: #777777;
}

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

  1. $callback : обратный вызов виджета для проверки
  2. $widget_id : идентификатор виджета. Необходим для проверки
  3. $id_base : базовый идентификатор виджета, переданный в методе __construct()
  4. $skip_inactive : пропустить ли неактивные виджеты

Добавьте следующий код ниже функции uep_admin_script_style() в главном файле плагина upcoming-events.php :

01
02
03
04
05
06
07
08
09
10
11
12
function uep_widget_style() {
    if ( is_active_widget( », », ‘uep_upcoming_events’, true ) ) {
        wp_enqueue_style(
            ‘upcoming-events’,
            STYLES .
            false,
            ‘1.0’,
            ‘all’
        );
    }
}
add_action( ‘wp_enqueue_scripts’, ‘uep_widget_style’ );

Поэтому мы сначала проверили, активен ли виджет в данный момент. Если это так, мы поставили таблицу стилей в очередь с помощью функции wp_enqueue_style() .

Это все о методе widget() . Мы успешно создали виджет, который показывает список предстоящих событий вместе с другой связанной информацией.

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

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

Добавьте следующий код в файл upcoming-events.php :

1
2
3
4
5
function uep_activation_callback() {
    uep_custom_post_type();
    flush_rewrite_rules();
}
register_activation_hook( __FILE__, ‘uep_activation_callback’ );

Таким образом, мы зарегистрировали хук активации для нашего плагина, используя функцию register_activation_hook() которая принимает два аргумента:

  1. $file : путь к основному файлу плагина
  2. $function : $function обратного вызова, запускаемая при активации плагина.

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

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

Это был еще один длинный учебник, в котором мы написали много кода и рассмотрели различные функции WordPress. Мы создали виджет WordPress с нуля, расширив родительский класс WP_Widget и WP_Widget функции-члены, которые этот класс предоставляет для определения функциональности нашего виджета. Мы также написали запрос, используя возможности класса WP_Query для получения списка событий, отфильтрованных по их мета значениям.

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

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