Очередной блог фрилансера

коротко и полезно о веб-разработке

Menu Close

Анатомия плагина WordPress

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

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

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

Цель

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

Мы создадим плагин-виджет  «Coming Next», который будет выбирать указанное число записей блога, запланированных на будущее и выводить их в сайдбаре блога (или в том месте, где владелец блога разместил виджет). Виджет будет настраиваемый, поэтому пользователь сможет сам решить, сколько записей он хочет выводить, нужно ли отображать краткий анонс записи, а также каким должен быть формат выводимой даты. Внешний вид плагина должен легко настраиваться с помощью CSS.

Вот набросок того, как виджет будет выглядеть в действии:

future-posts

Давайте начнем.

Шаг 1: Шаблон Плагина

Плагины в WordPress представляют собой PHP-файлы, которые хранятся в папке wp-content/plugins, в папке с установленным WordPress-ом.

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

Давайте создадим папку для плагина «Coming Next»:

directory

В созданной директории, мы создадим основной PHP-файл плагина. Давайте назовем его coming-next.php.

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

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

<?php   
/*  
Plugin Name: Coming Next  
Plugin URI: http://nettuts.com  
Description: Отображает будущие публикации в блоге, с кратким содержанием.  
Version: 1.0  
Author: Jarkko Laine  
Author URI: http://jarkkolaine.com  
*/   
?>   

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

plugin

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

Шаг2: Добавление Функциональности

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

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

Давайте сделаем это первыми и создадим в корне плагина «Coming Next» функцию list_upcoming_posts().

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

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

function list_upcoming_posts($num_posts = 1, $show_excerpt = false,    
                             $text_format = "Coming Up on [date]") {   
  $posts = get_posts("numberposts=".$num_posts."&order=ASC&post_status=future");   
  
  echo "<ul class=\"upcoming-posts\">";   
  global $post;   
  $old_post = $post;   
  
  foreach ($posts as $post) :   
    setup_postdata($post);   
    $my_date = the_date('', '', '', FALSE);   
    $coming_up_text = str_replace("[date]", $my_date, $text_format);   
  ?>   
    <li class="upcoming-post">   
      <span class="upcoming-post-date"><?php echo $coming_up_text; ?></span>   
      <span class="upcoming-post-title"><?php the_title(); ?></span>   
      <?php if ($show_excerpt) : ?>   
        <span class="upcoming-post-description">   
          <?php the_excerpt_rss(); ?>   
        </span>   
      <?php endif; ?>   
    </li>   
  <?php   
  endforeach;   
  
  $post = $old_post;   
  setup_postdata($post);   
  echo "</ul>";   
}

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

Затем функция возвращает список, включающий в себя заголовки записей, их запланированные даты, и цитату записи, если значение $show_excerpt установлено в true.

Заметьте, нам необходимо использовать глобальную переменную $post, чтобы установить данные записи (строка 10) для работы функций, таких как the_title(). Теперь, если шаблону блога необходим доступ к текущей записи, после отрисовки плагина, нам нужно вернуть оригинальную запись, после того как мы закончим (строка 7 и 26-27). В противном случае остальная часть контента будет возвращена, с использованием последней записи, которую мы установили функцией setup_postdata().

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

<?php   
if (function_exists("list_upcoming_posts")) {   
  list_upcoming_posts();   
}   
?>   

Создайте запись, с названием «Назад в Будущее» и запланируйте его публикацию на 1 Января 2020 года. Вот что вы должны увидеть:

последние записи в сайдбаре

Шаг 3: Создание Виджета

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

В данном случае, вы еще не знакомы с понятием WordPress Виджетов, вот что документация WordPress говорит об этом:

Виджеты WordPress позволяют легко добавить элементы дизайна, гаджеты, контент, изображения и многое другое к сайдбару WordPress, для персонализации своего блога, без знаний HTML, PHP или другого кода. Множество Плагинов WordPress имеют версию Виджета, для более простого добавления в сайдбар.

Если ваша тема поддерживает виджеты, вы можете перейти в раздел «Виджеты», в секции «Внешний вид» в админке WordPress и настроить их в произвольном порядке.

widgets

Для того чтобы сделать наш плагин «Coming Next» виджетом, мы в начале должны создать функцию вывода виджета. Поскольку мы снова можем использовать функцию list_upcoming_posts(), созданную ранее, эта задача будет намного проще.

Вот код для виджета, в самой простой форме:

function widget_coming_next($args) {   
  extract($args, EXTR_SKIP);   
  echo $before_widget;   
  list_upcoming_posts();   
  echo $after_widget;   
}   

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

Функция extract() является стандартной в PHP. Она принимает поля из полученного массива ($args) и создает локальные переменные их вывода. Другой способ получить тоже самое, использовать прямые ссылки массива, с помощью индексов массива «before_widget» и «after_widget».

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

function widget_coming_next_init() {   
  wp_register_sidebar_widget(COMING_NEXT_WIDGET_ID,    
    __('Coming Next'), 'widget_coming_next');   
}   
  
// Register widget to WordPress   
add_action("plugins_loaded", "widget_coming_next_init");

Функция инициализации вызывается wp_register_sidebar_widget(), для регистрации виджета в WordPress. Функции требуется три параметра: уникальный идентификатор для виджета, имя, которое будет использовано на странице Виджетов в панели администрирования, и имя функции, которая исполняет виджет.

Чтобы сделать проще, если нам постоянно нужно менять уникальный идентификатор, я создал константу для него. Этот способ, когда мы используем одну и ту же константу везде, нам нужно будет изменить ее только в одном месте. Добавьте это описание константы в начале виджет-файла, сразу после блока комментария, который идентифицирует плагин:

define(COMING_NEXT_WIDGET_ID, "widget_coming_next");  

Теперь, когда вы проверите страницу «Виджеты», в панели управления, вы увидите новый виджет, который ждет добавления в блог. После активации плагина, список будущих записей появится прямо в том месте, которые вы указали.

coming next

Шаг4: Настройки Виджета

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

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

Вот код для записи и возврата настроек:

function widget_coming_next_control() {   
  $options = get_option(COMING_NEXT_WIDGET_ID);   
  if (!is_array($options)) {   
    $options = array();   
  }   
  
  $widget_data = $_POST[COMING_NEXT_WIDGET_ID];   
  if ($widget_data['submit']) {   
    $options['num_posts'] = $widget_data['num_posts'];   
    $options['coming_up_text'] = $widget_data['coming_up_text'];   
    $options['show_excerpt'] = $widget_data['show_excerpt'];   
  
    update_option(COMING_NEXT_WIDGET_ID, $options);   
  }   
  
  // Render form   
  $num_posts = $options['num_posts'];   
  $coming_up_text = $options['coming_up_text'];   
  $show_excerpt = $options['show_excerpt'];   
     
  // The HTML form will go here   
}

Суть этой функции —  два вызова WordPress API: get_option() в строке 2 и update_option() в строке 13. update_option можно использовать для хранения любой переменной в базе WordPress, в качестве пары ключ-значение, и get_option, для его прочтения.

Например, в вышеуказанном коде, вы можете видеть в строке 13, что update_option() используется для записи массива $options, с ключом COMING_NEXT_WIDGET_ID.

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

Функция widget_coming_next_control() вызывается в обоих случаях, когда форма настроек появляется в первый раз, и когда пользователь нажимает кнопку «Сохранить изменения», для записи настроек. Чтобы определить отправлена форма или нет, мы используем скрытое поле под названием COMING_NEXT_WIDGET_ID[submit].  Если скрытое поле было сохранено, мы читаем параметры из формы и сохраняем их (строки 8-14). И в обоих случаях, сохранены данные или нет, форма перерисовывается.

Говоря о формах, следует заметить, что основная часть пропущена. Скопируйте представленную ниже форму, и вставьте в конце функции, которую мы только что создали (после строки 21, до закрывающей скобки):

?>   
<P>   
  <label for="<?php echo COMING_NEXT_WIDGET_ID;?>-num-posts">   
    Number of posts to show:   
  </label>   
  <input class="widefat"    
    type="text"   
    name="<?php echo COMING_NEXT_WIDGET_ID; ?>[num_posts]"    
    id="<?php echo COMING_NEXT_WIDGET_ID; ?>-num-posts"    
    value="<?php echo $num_posts; ?>"/>   
</P>   
<P>   
  <LABEL for="<?php echo COMING_NEXT_WIDGET_ID;?>-coming-up-text">   
    "Coming Up Next" text (use the [date] tag to    
    display the publish date):   
  </LABEL>   
  <input class="widefat" type="text"    
    name="<?php echo COMING_NEXT_WIDGET_ID; ?>[coming_up_text]"    
    id="<?php echo COMING_NEXT_WIDGET_ID; ?>-coming-up-text"    
    value="<?php echo $coming_up_text; ?>"/>   
</P>   
<P>   
  <LABEL for="<?php echo COMING_NEXT_WIDGET_ID;?>-show-excerpt">   
    Show excerpt:   
  </LABEL>   
  <select class="widefat"   
    name="<?php echo COMING_NEXT_WIDGET_ID; ?>[show_excerpt]"   
    id="<?php echo COMING_NEXT_WIDGET_ID;?>-show-exceprt">   
    <option value="1" <?php echo ($show_excerpt == "1") ? "selected" : ""; ?>>   
      Yes   
    </option>   
    <option value="0" <?php echo ($show_excerpt == "1") ? "" : "selected"; ?>>   
      No   
    </option>   
  </select>   
</P>   
<input type="hidden"    
  name="<?php echo COMING_NEXT_WIDGET_ID; ?>[submit]"    
  value="1"/>   
<?php  

Если вы внимательно посмотрите на форму, то заметите отсутствие открывающих и закрывающих тэгов формы. Это потому что все активные виджеты помещаются в одну и ту же форму, возвращаемую WordPress, и сохраняются после нажатия кнопки «Сохранить Изменения».  Это будет весьма полезно, когда вы решите написать виджет, который можно добавлять много раз, такой как текстовый виджет WordPress  (для этого вам понадобятся знания о множественных виджетах и обо всех их различных состояниях в одно и то же время). Но сейчас, это просто значит, что вам нужно быть осторожным с именованием полей в части своей формы.

В этом плагине, я решил использовать константу COMING_NEXT_WIDGET_ID в качестве идентификатора, для описания полей, принадлежащих виджету. Использование записи widget_id[field_id] в имени параметров наших input-тэгов, очень удобно для нас, поскольку они передаются в массив с field_id в качестве индекса массива.

После создания функции экранных настроек, мы должны заставить WordPress использовать их. Это делается следующим хуком. Добавьте это в функцию widget_coming_next_init(), которую мы создали ранее:

wp_register_widget_control(COMING_NEXT_WIDGET_ID,    
    __('Coming Next'), 'widget_coming_next_control');   

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

settings

Последнее, но не менее важное, мы должны сделать отрисовку виджета, с настройками описанными в блоке настроек. Это на самом деле очень просто: все что нам нужно, это прочитать настройки используя функцию get_option(). Замените ранее созданную функцию отрисовки виджета, на новую версию:

function widget_coming_next($args) {   
  extract($args, EXTR_SKIP);   
  $options = get_option(COMING_NEXT_WIDGET_ID);   
  
  // Query the next scheduled post   
  $num_posts = $options["num_posts"];   
  $show_excerpt = $options["show_excerpt"];   
  $coming_up_text = $options["coming_up_text"];   
  
  echo $before_widget;   
  list_upcoming_posts($num_posts, $show_excerpt, $coming_up_text);   
  echo $after_widget;   
}

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

final

Перевод статьи «Anatomy of a WordPress Plugin«, автор Jarkko Laine.