В директории с плагинами WordPress расположено несколько сотен различных плагинов и виджетов. Несмотря на это, бывают ситуации, когда даже такого огромного набора средств недостаточно. В таком случае вам понадобится создать собственный виджет или плагин, решающий определенную проблему, что является весомым аргументом в пользу дальнейшей дистрибьюции темы, особенно если созданные виджеты завязаны на реализации каких-либо уникальных возможностей или функций.
Традиционно, существует два различных способа добавления созданных виджетов к теме. Первый способ основан на внесении новой функции в файл functions.php. Этот способ мы уже использовали ранее для добавления необходимой нам функциональности. Как мы успели заметить, данный способ приводит к быстрому разрастанию файла functions.php, что значительно усложняет его дальнейшее редактирование, однако использование комментариев и разбиения на участки позволяет решить возникшую проблему. Второй способ добавления виджетов к теме заключается в создании плагина под каждый новый виджет. Этот способ также не лишен своих недостатков: созданный плагин будет существовать отдельно от темы, что, естественно, добавит несколько новых шагов к процессу установки темы. Мы же хотим, чтобы тема была настолько проста в использовании насколько это возможно, следовательно, мы постараемся избежать лишней работы. К счастью, в фреймворке Thematic предусмотрено довольно инновационное встроенное решение для виджетов, которое значительно упрощает процесс их создания и управления — функция, которая ищет папку с названием widgets в дочерней теме и добавляет любые виджеты без каких-либо дополнительных действий со стороны разработчика. Эта возможность также означает, что созданные виджеты будут автоматически распространяться вместе с дочерней темой, что очень удобно, поскольку это позволяет исключить шаги по установке/активации дополнительных плагинов. Еще один приятный бонус использования папки widgets — вы можете организовать каждый виджет в виде отдельного PHP файла.
В конце предыдущей главы мы написали функцию, которая добавляла информацию об авторе в конец каждой записи. Почему бы не сделать данную функциональность более гибкой, представив ее в виде отдельного виджета, который будет отображаться только на страницах с отдельными записями?
Введение в API виджетов
Для того чтобы создать новый виджет в WordPress, нам необходимо расширить стандартный класс виджетов (WP_Widget). Если вы не знакомы с объектно-ориентированным программированием, не стоит переживать: в процессе разработки виджетов WordPress мы лишь поверхностно затронем ООП. Каждый класс виджетов обладает четырьмя стандартными функциями: конструктором, а также функциями widget, update и form.
Для начала взглянем на пустую оболочку для нового виджета:
class My_Widget extends WP_Widget { function My_Widget() { // this is a constructor, where each new instance of your widget gets built }function form($instance) { // this generates the widget options form which you see // in the widgets section in the admin }function update($new_instance, $old_instance) { // this handles the submission of the options form to // update the widget options }function widget($args, $instance) { // the most important function: this one handles actually outputting // the widget's content to the theme } }
В каждую из приведенных в примере функций разработчик должен поместить соответствующий код. Также как и области виджетов, созданные виджеты должны быть зарегистрированы для того чтобы их можно было использовать. Регистрация виджетов производится при помощи следующей строки:
register_widget ('My_Widget');
Не углубляясь в детали, отметим, что функции form и update отвечают за возможность введения и отображения заголовка виджета. Таким образом, если вы не нуждаетесь в дополнительных настройках для данных функций, вы можете просто скопировать код для них из предыдущего виджета.
Создание виджета
Приступим к созданию нашего первого произвольного виджета. Создадим папку widgets в нашей дочерней теме и добавим к ней новый PHP файл. Назовем его author-data.php. Объявим класс Author_Data_Widget вместе с четырьмя необходимыми функциями и вызовем register_widget:
<?phpclass Author_Data_Widget extends WP_Widget { function Author_Data_Widget() {} function form($instance) {}function update($new_instance, $old_instance) {} function widget($args, $instance) { } } register_widget('Author_Data_Widget'); ?>
Наша первая задача состоит в том, чтобы создать конструктор. В канонической форме записи конструктор имеет следующий вид:
function My_Widget() { $this-<WP_Widget($id, $name, $widget_ops, $control_ops); }
Инструкция ($this->WP_Widget) описывает процесс создания нового экземпляра виджета. Параметр $id используется для внутреннего обращения к созданному виджету, $name — имя, которое отображается в панели виджетов, $widget_ops — массив, включающий в себя описание виджета, которое будет показано в панели администратора, $control_ops — необязательный параметр, не требуемый для большинства виджетов (мы не будем пока что его рассматривать). Запишем данную функцию к нашему виджету:
function Author_Data_Widget() { $widget_ops = array( 'description' =< 'A widget that displays author info on single posts.' ); $this-<WP_Widget('author_data', 'Author Data', $widget_ops); }
Даже с одной этой функцией мы сможем увидеть наш виджет во внутреннем интерфейсе.
Однако, если мы переместим наш виджет в одну из областей виджетов, то увидим, что у него нет никаких настроек.
Сделаем так, чтобы пользователи могли определять заголовок виджета. Для этого нам придется внести некоторые изменения в функции form и update. Начнем с метода form.
К счастью, WordPress способен обрабатывать создание элемента form; все, что мы должны сделать, это определить элементы label и input для каждой из настроек. Эти элементы для корректной работы должны иметь атрибуты id и name; WordPress помогает нам и в этом случае, поскольку виджет имеет функции get_field_id и get_field_name. Ниже приведен пример, как может выглядеть наша простая форма:
function form($instance) { $title = esc_attr($instance['title']); ?> <p> <label for="<?php echo $this->get_field_id('title'); ?>">Title: <input id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo attribute_escape($title); ?>" /> </label> </p> <?php }
Функция получает переменную $instance, которая представляет текущий виджет с определенным набором настроек. Первое, что мы делаем, это извлекаем переменную $title из $instance. Затем мы создаем поле формы, используя $this->get_field_id и $this->get_field_name для установки атрибутов поля id и name.
После того как форма будет представлена, WordPress перейдет к функции update, которая позволяет сохранить изменения, внесенные пользователем в поля формы. Давайте взглянем на данную функцию:
function update($new_instance, $old_instance) { $instance = $old_instance; $instance['title'] = strip_tags($new_instance['title']);return $instance; }
Функция update работает несколько иначе: она получает два параметра, первый из которых содержит новый виджет, включающий настройки, представленные в форме, а второй — содержит старый виджет с предыдущими настройками. Таким образом, мы должны захватить заголовок из $new_instance и использовать его для установки заголовка в нашем экземпляре. Чтобы избежать беспорядка, мы сохранили $old_instance в новую переменную, названную $instance, которая и будет хранить наш новый заголовок. Затем мы возвращаем $instance и WordPress производит обновление виджета с теми настройками, которые мы установили.
Если ваша форма имеет более чем одно поле, вам придется повторить заданный процесс ля каждой настройки, которая требует установки. Вы можете включать в функцию update столько логики, сколько вам понадобится. Если вы, к примеру, хотите отбросить некоторые настройки (на основании проверки условия), все, что вам понадобится сделать, это возвратить false, вследствие чего виджет не будет обновлен.
Теперь, когда мы создали собственную форму настроек, вернемся к панели администратора и проведем небольшое тестирование формы: перетащим виджет Author Data в одну из областей виджетов. Вы должны увидеть новое поле, позволяющее устанавливать заголовок виджета:
Таким образом, мы имеем три функции: конструктор, form и update, каждая из которых выполняет обработку нашей формы виджета.
Посмотрим на функцию, которая позволяет вывести на экран наш виджет:
function widget($args, $instance) { extract($args, EXTR_SKIP);if (is_single()) {echo $before_widget; $title = apply_filters('widget_title', $instance['title']); if ( !empty( $title ) ) { echo $before_title . $title . $after_title; }; echo '<div>'; echo get_avatar(get_the_author_meta('user_email'), 150); echo '<h4>' . the_author_meta('display_name') . '</h4>'; // Is there an author description? if (get_the_author_meta('description')) { echo '<div><p>' . get_the_author_meta('description') . '</p></div>'; } echo '</div>'; echo $after_widget; } }
Функция получает два параметра: $args — массив аргументов, используемых всеми виджетами в теме. Эти аргументы уже знакомы вам: before_title, after_title, before_widget, и after_widget. Второй параметр — это $instance, который содержит набор настроек вашего виджета. В нашем случае это только заголовок.
Теперь, когда мы записали все необходимые функции, виджет должен правильно выводить на экран информацию об авторе на страницах с отдельными записями. Ниже приведен полный листинг файла author-data.php:
<?phpclass Author_Data_Widget extends WP_Widget { function Author_Data_Widget() { $widget_ops = array( 'description' => 'A widget that displays author info on single posts.' ); $this->WP_Widget('author_data', 'Author Data', $widget_ops); } function form($instance) { $title = esc_attr($instance['title']); ?> <p> <label for="<?php echo $this->get_field_id('title'); ?>">Title: <input id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo attribute_escape($title); ?>" /> </label> </p> <?php } function update($new_instance, $old_instance) { $instance = $old_instance; $instance['title'] = strip_tags($new_instance['title']); return $instance; } function widget($args, $instance) { extract($args, EXTR_SKIP); if (is_single()) { echo $before_widget; $title = apply_filters('widget_title', $instance['title']); if (!empty($title)) { echo $before_title . $title . $after_title; }; echo '<div>'; echo get_avatar(get_the_author_meta('user_email'), 150); echo '<h4>' . the_author_meta('display_name') . '</h4>'; // Is there an author description? if (get_the_author_meta('description')) { echo '<div><p>' . get_the_author_meta('description') . '</p></div>'; } echo '</div>'; echo $after_widget; } } } register_widget('Author_Data_Widget'); ?>