Пишем плагин-виджет для WordPress с использованием нового Widgets API

Одно из основных нововведений WordPress 2.8 это новый API для создания виджетов, делающий создание виджетов очень простым. Я расскажу, как сделать плагин добавляющий виджет на примере плагина-виджета “будущие посты”.

Для начала немного о том, как работает новый API.

Теория

Начиная с WordPress 2.8 виджет, это не просто набор функций. Виджет, это класс наследующий класс WordPress под названием WP_Widget, в php как и в любом ООП языке программирования, класс наследник получает методы класса родителя. Проще говоря в своем виджете мы можем пользоваться уже готовыми функциями написанными разработчиками Вордпресс в классе WP_Widget.

Практика

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


<?php
/*
Plugin Name: Future Posts
*/
?>
<?

class FuturePosts extends WP_Widget {
function FuturePosts() {
parent::WP_Widget(false, $name = 'Future Posts');
}

function widget($args, $instance) {
extract( $args );
?>
<?php echo $before_title
. $instance['title']
. $after_title;
query_posts('order=ASC&post_status=future');
while (have_posts()) : the_post(); ?>
<li><?php the_title();?></li>
<?php endwhile; ?>

<?php
}

function update($new_instance, $old_instance) {
return $new_instance;
}

function form($instance) {
$title = esc_attr($instance['title']);
?>

<p>
<label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?>
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" />
</label>
</p>

<?php
}

}
add_action('widgets_init', create_function('', 'return register_widget("FuturePosts");'));

?>

По большому счету всё поведение виджета описано в трех функциях, widget – непосредственно вывод виджета в блог, update – обновление виджета, form – форма изменения настроек виджета в панели администрирования. Найдя эти функции в вашем виджете, WordPress сам сделает остальное, выведет текст виджета в блог, запишет данные в БД, сделает форму управления виджетом. По большому счету виджету для работы достаточно функции


function widget() {

echo "Я виджет";

}

всё остальное уже сделано за нас разработчиками.

Для каждого виджета wordpress автоматически создает поле в таблице БД и записывает туда все данные о виджете, включая все переменные, отправленные через форму. Эти данные доступны в функциях плагина через массив $instance.

Рассмотрим код плагина подробно.


<?php
/*
Plugin Name: Future Posts
*/
?>

Эта часть необходима для того, что бы WordPress понял, что файл является плагином, в Plugin Name нужно написать название нашего плагина.


class FuturePosts extends WP_Widget {

Эта строка открыавет класс нашего виджета и наследует его от WP_Widget, все функции нашего виджета будут находится в этом классе.


function FuturePosts() {
parent::WP_Widget(false, $name = 'Future Posts');
}

Функция конструктор необходимая для создания виджета, как вы наверное уже догадались, $name = ‘Future Posts’ это название нашего виджета. Название этой функции должно совпадать с названием класса.

Функция widget – непосредственно функция вывода виджета в блог. Функция выводит

заголовок, который берется из БД через массив $instance, если заголовок не определен, это не вызовет ошибок.


echo $before_title
. $instance['title']
. $after_title;

а затем список постов, запрошенных при помощи стандартной функции wordpress query_posts


query_posts('order=ASC&post_status=future');
while (have_posts()) : the_post(); ?>
<li><?php the_title();?></li>
<?php endwhile; ?>

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


function update($new_instance, $old_instance) {
return $new_instance;
}

WordPress пишем widget

Функция form является панелью управления нашим виджетом, рассмотрим подробнее, что в ней происходит


$title = esc_attr($instance['title']);

Эта строчка получает заголовок нашего виджета, если он есть в БД.


<label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?>
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo $title; ?>" />
</label>

А дальше идет простое поле обычной HTML формы для ввода заголовка нашего виджета, если заголовок уже есть в БД он будет виден в форме. После отправки формы, заголовок будет автоматически записан в БД. Предположим, под заговоком мы хотим разместить описание виджета, достаточно добавить в форму еще одно поле для ввода описания и оно будет записано в БД при отправке формы и будет доступно, как и другие переменные виджета в массиве $instance, в том числе из функции widget.

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


add_action('widgets_init', create_function('', 'return register_widget("FuturePosts");'));

На этом всё, в виджете можно использовать любые php и wordpress функции, например query_posts запрашивает посты вашего блога, можно выводить посты из определенной категории или например, самые комментируемые посты, функциональность ограничивается только вашей фантазией, удачи!

Вот несколько ссылок, которые помогут в создании виджетов:

Страница официальной документации по новому API

Код стандартных виджетов с использованием нового API

Код класса WP_Widget, все функции достаточно подробно описаны

22 комментария к статье Пишем плагин-виджет для WordPress с использованием нового Widgets API

Avatar

Jekyll

29th Июнь 2009 в 12:47

Есть у меня мысль сделать один плагин к WP, но сам я от программирования далек.Поэтому хочу задать глупый вопрос — насколько сложно разобраться в PHP и WP API на уровне, достаточном для выполнения задуманного? Понимаю, что при желании можно все сделать, но, может будут какие-либо советы?

Avatar

Wordpresser

29th Июнь 2009 в 13:14

@Jekyll
Все зависит от того, что хотите реализовать, в принципе выше вполне рабочий плагин, можно сделать по аналогии, все функции php и wp хорошо документированны. Есть и сложные плагины, что бы такой написать нужно хорошо владеть php

Avatar

Flex Guy

30th Июнь 2009 в 12:49

Спасибо. Очень интересная статья. Надо будет попробывать сделать что нибудь. 😉

Avatar

trendbender

30th Июнь 2009 в 17:04

круто)

Avatar

Илья

19th Июль 2009 в 20:40

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

Avatar

Wordpresser

20th Июль 2009 в 09:17

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

Avatar

post

1st Сентябрь 2009 в 06:43

Спасибо! Сделал свой плагин на основе Вашего примера

Avatar

Wordpresser

1st Сентябрь 2009 в 12:45

post :

Спасибо! Сделал свой плагин на основе Вашего примера

Рад что моя статья помогла!

Avatar

RaftKorn

27th Май 2010 в 09:53

WordPresser, подскажите — как сделать так, чтоб при отключении виджета, и повторном его включении сохранялись введенные в нем ранее данные?

Avatar

wordpresser.ru

27th Май 2010 в 21:29

RaftKorn, вообще по идее содержимое виджета должно сохранятся, так как хранится эта информация в базе.

Avatar

Артем

18th Июнь 2010 в 14:42

Помогите найти нужный плагин!!!! Нигде его не видел, уже месяц ищу…

Плагин который для каждой страницы создает виджет с html кодом конкретно для данной страницы. Я сам заполняю html для каждой страницы (ну или поста). Это нужно для того, чтобы я мог прикреплять ссылки или постовые не к посту снизу, а выводить сбоку в виджете!

Ответьте пожалуйста!!! Спасибо.

Avatar

Anna

2nd Август 2010 в 17:45

Большое спасибо!
Мой первый виджет заработал!

Avatar

Денис Шутько

15th Июль 2011 в 10:54

Тут еще нужно в конце добавить обязательно wp_reset_query() для того, чтобы можно было использовать Loop далее в php-файле!

Avatar

Sergey Klay

21st Январь 2012 в 02:20

Настоятельно рекомендую всем WordPress-разработчикам использовать режим отладки в своем _тестовом_ (дома, на localhost) сайте режим отладки. Чтоб можно было сразу видеть где вы допустили ошибку. Для этого в файле wp-config.php вставьте следующие строки:

define( ‘WP_DEBUG’, true );
define( ‘WP_DEBUG_LOG’, true );
define( ‘WP_DEBUG_DISPLAY’, true );

Думаю по названию констант и так понятно назначение этих директив.
После вкючения define( ‘WP_DEBUG’, true ); в папке wp-content создастся файл debug.log, в который буду записываться все ошибки (плагинов, тем, самого движка) вашего WordPress сайта.

Avatar

Sergey Klay

21st Январь 2012 в 02:24

P.S. Прошу прощения, debug.log создается после включения define( ‘WP_DEBUG_LOG’, true );

Avatar

Sergey Klay

21st Январь 2012 в 03:35

Предлагаю поправку №1 )

В функции form() есть такая строка:
$title = esc_attr($instance[‘title’]);
Дело в том, что когда $title пустой PHP генерирует предупреждение:
PHP Notice: Undefined index: title in wp-content/plugins/future-posts/future-posts.php
И правильно делает, что предупреждает 🙂 А дело в том, что как минимум 1 раз $title у вас будет пустым — при установке плагина. Так вот, чтоб не было сего досадного казуса, предлагаю вместо:
$title = esc_attr($instance[‘title’]);
писать так:
if ( isset( $instance[‘title’] ) )
$title = esc_attr( $instance[‘title’] );
Если не всем понятно — это условие, дословно:
«Если $instance[‘title’] не пустой» (1 строчка кода),
назначить $title значение esc_attr( $instance[‘title’] );

Можно кстати сократить, для любителей лаконичности:
$title = (isset( $instance[‘title’] ) ) ? esc_attr( $instance[‘title’] ) : »;
Работать будет так же.

Avatar

Sergey Klay

21st Январь 2012 в 03:42

P.S. Данный сайт как то странно переформатировал ДВЕ одинарные кавычки в строке:
$title = (isset( $instance[‘title’] ) ) ? esc_attr( $instance[‘title’] ) : »;
Имейте ввиду, это не «ёлочки», это _две_одинарные_кавычки_. Это важно.

Avatar

Sergey Klay

21st Январь 2012 в 04:41

Поправка №2

Не знаю как у вас там, в далёком прошлом (судя по дате этого поста), 🙂 а у нас, в 2012-ом, на версии WordPress 3.3.1 строка
query_posts(‘order=ASC&post_status=future’);
для функции widget() не работает.
Залез в базу данных, таблицу wp_posts и увидел, что статус записи регламентируется в поле post_status и отныне статус записей, которые ожидают утверждения (публикации) помечается как pending, а не future.

В итоге, чтоб всё это дело заработало в WordPress 3.3.1 писать нужно так:
query_posts( ‘order=ASC&post_status=pending’ );

Предлагаю автору изменить и дополнить статью, руководствуясь современными реалиями и внесенными поправками 🙂

Avatar

Sergey Klay

22nd Январь 2012 в 05:32

P.S. Автор сайта, отключи эту странную штуку, которая вырезает и изменяет код в сообщениях. В итоге весь код которыя я написал в предыдущем посте изменился, а некоторый исчез вообще.
Не интересно 🙁

Avatar

Sergey Klay

22nd Январь 2012 в 06:03

Хотел ещё улучшить этот виджет, внести пару конструктивных предложений. Но не буду писать что придумал. Сайт всё равно код покоцает 🙁

Avatar

Wordpresser

22nd Январь 2012 в 16:35

Спасибо, Сергей, над комментариями поработаю.

Avatar

Cat

5th Сентябрь 2013 в 16:58

Привет. Все хорошо описано и понятно. Спасибо. Но есть вопрос — как быть, если у меня в виджете будет несколько чекбоксов и я хочу сохранять их одним массивом? Во всех туториалах описаны виджеты в которых будет точно известно количество настроек, переменных и их имена. У меня количество чекбосков будет зависить от количества страниц (ну задумка такая). Как мне в таком случае хранить настройки? Как оформлять форму виджета и сохранение настроек?

Оставить комментарий к "Пишем плагин-виджет для WordPress с использованием нового Widgets API"

Наверх