Как написать плагин для Wordpress

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

Вы идете на «склад» плагинов для wordpress и обнаруживаете, что необходимого плагина для Вас нету. Что же делать? Как быть ? Если вы хотя бы немного знакомы с азами программирования на php, верстке, то Вам не составит труда Самому написать плагин для WordPress.

А теперь отправимся на «кухню» для приготовления нашего плагина.

p.s. Если знаний в php и верстке нету… не расстраивайтесь, попросите кого-либо написать Вам нужный функционал 🙂

UPD: Новая статья Как написать виджет для wordpress и опубликовать в репозитории

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

Я не буду дублировать эту информацию, а сразу перейду непосредственно к написанию кода.

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

Первое, что мы сделаем, это придумаем уникальное название нашему плагину — «AdvUserReviews«.

Далее создадим в директории Вашего сайта «/wp-content/plugins/» новую директорию «advuserreviews». И в ней создадим файл «advuserreviews.php». Это будет основной файл, который будет отвечать за общею инициализацию. (Желательно используйте кодировку для файлов UTF-8).

В самом начале файла необходимо указать основную информацию о плагине

<?php
/*
Plugin Name: Advanced User Reviews
Description: Отзывы о сайте
Version: 1.0
Author: Волков Вячеслав (VeXell)
Author URI: http://vexell.ru/
*/

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

Наш новый плагин мы будем писать в стиле ООП и вся обработка данных будет находится в одном файле. Создадим основной каркас файла.

// Stop direct call
if(preg_match('#' . basename(__FILE__) . '#', $_SERVER['PHP_SELF'])) { die('You are not allowed to call this page directly.'); }

if (!class_exists('AdvUserReviews')) {
class AdvUserReviews {
 // Хранение внутренних данных
 public $data = array();
  // Конструктор объекта
  // Инициализация основных переменных
  function AdvUserReviews()
  {

  }
 }
}

global $rprice;
$rprice = new AdvUserReviews();

Теперь конструктор объекта дополним следующим кодом:

function AdvUserReviews()
{
 global $wpdb;

 // Объявляем константу инициализации нашего плагина
 DEFINE('AdvUserReviews', true);

 // Название файла нашего плагина
 $this->plugin_name = plugin_basename(__FILE__);

 // URL адрес для нашего плагина
 $this->plugin_url = trailingslashit(WP_PLUGIN_URL.'/'.dirname(plugin_basename(__FILE__)));

 // Таблица для хранения наших отзывов
 // обязательно должна быть глобально объявлена перменная $wpdb
 $this->tbl_adv_reviews   = $wpdb->prefix . 'adv_reviews';

 // Функция которая исполняется при активации плагина
 register_activation_hook( $this->plugin_name, array(&$this, 'activate') );

 // Функция которая исполняется при деактивации плагина
 register_deactivation_hook( $this->plugin_name, array(&$this, 'deactivate') );

 //  Функция которая исполняется удалении плагина
 register_uninstall_hook( $this->plugin_name, array(&$this, 'uninstall') );
}

В конструкторе объекта мы используем 3 «хука» или «зацепки» (что это ?): register_activation_hook, register_deactivation_hook и register_uninstall_hook — это функции, которые выполняются при активации, деактивации плагина и его удаления соответственно.

Теперь непосредственно реализуем эти функции.

/**
 * Активация плагина
 */
function activate()
{
 global $wpdb;

 require_once(ABSPATH . 'wp-admin/upgrade-functions.php');

 $table = $this->tbl_adv_reviews;

 // Определение версии mysql
 if ( version_compare(mysql_get_server_info(), '4.1.0', '>=') ) {
  if ( ! empty($wpdb->charset) )
   $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
  if ( ! empty($wpdb->collate) )
   $charset_collate .= " COLLATE $wpdb->collate";
 }

 // Структура нашей таблицы для отзывов
 $sql_table_adv_reviews = "
	CREATE TABLE `".$wpdb->prefix."adv_reviews` (
		`ID` INT(10) UNSIGNED NULL AUTO_INCREMENT,
		`review_title` VARCHAR(255) NOT NULL DEFAULT '0',
		`review_text` TEXT NOT NULL,
		`review_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
		`review_user_name` VARCHAR(200) NULL,
		`review_user_email` VARCHAR(200) NULL,
		PRIMARY KEY (`ID`)
	)".$charset_collate.";";

 // Проверка на существование таблицы
 if ( $wpdb->get_var("show tables like '".$table."'") != $table ) {
  dbDelta($sql_table_adv_reviews);
 }

}

/**
 * Деактивация плагина
 */
function deactivate()
{
 return true;
}

/**
 * Удаление плагина
 */
function uninstall()
{
 global $wpdb;
 $wpdb->query("DROP TABLE IF EXISTS {$wpdb->prefix}adv_reviews");
}

Переменная $wpdb отвечает за запросы к базе Данных. Функция dbDelta анализирует текущую структуру таблицы, сравнивает ee с желаемой структурой таблицы, и либо добавляет или изменяет таблицу по мере необходимости.

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

Основная структура нового плагина готова. Теперь необходимо приступить к написанию функциональной части. Для этого в конструктор класса нам необходимо добавить следующие строчки кода:

 // Если мы в адм. интерфейсе
 if ( is_admin() ) {

  // Добавляем стили и скрипты
  add_action('wp_print_scripts', array(&$this, 'admin_load_scripts'));
  add_action('wp_print_styles', array(&$this, 'admin_load_styles'));

  // Добавляем меню для плагина
  add_action( 'admin_menu', array(&$this, 'admin_generate_menu') );

 } else {
  // Добавляем стили и скрипты
  add_action('wp_print_scripts', array(&$this, 'site_load_scripts'));
  add_action('wp_print_styles', array(&$this, 'site_load_styles'));

  add_shortcode('show_reviews', array (&$this, 'site_show_reviews'));
 }

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

  • wp_print_scripts — Добавляем необходимые javascript файлы
  • wp_print_styles — Добавляем необходимые стили
  • admin_menu — Добавляем новое меню в панели управления

Каждому хуку соответствует реализованный метод в нашем классе. В котором выполняются необходимые операции.
Рассмотрим код для подключения стилей и скриптов

/**
 * Загрузка необходимых скриптов для страницы управления
 * в панели администрирования
 */
function admin_load_scripts()
{
 // Регистрируем скрипты
 wp_register_script('advReviewsAdminJs', $this->plugin_url . 'js/admin-scripts.js' );
 wp_register_script('jquery', $this->plugin_url . 'js/jquery-1.4.2.min.js' );

 // Добавляем скрипты на страницу
 wp_enqueue_script('advReviewsAdminJs');
 wp_enqueue_script('jquery');
}

/**
 * Загрузка необходимых стилей для страницы управления
 * в панели администрирования
 */
function admin_load_styles()
{
 // Регистрируем стили
 wp_register_style('advReviewsAdminCss', $this->plugin_url . 'css/admin-style.css' );
 // Добавляем стили
 wp_enqueue_style('advReviewsAdminCss');
}

Здесь используются следующие функции.

wp_register_script — Функция служит для регистрации необходимых скриптов и последующего их подключения. Принимает несколько параметров, но основные из их них два: первый параметр — уникальный идентификатор скрипта, второй — путь к файлу скрипта. Третий параметр — зависимости данного скрипта, четвертый — версия скрипта, пятый — где размещать файл скрипта в <head> страницы или же внизу тега <body>.

wp_enqueue_script — Безопасный путь добавления JavaScript в страницу сгенерированную WordPress. Здесь стоит обратить внимание уже на зарезервированных и включенных идентификаторов скриптов в wordpress . Данная функция может принимать как один параметр — зарегистрированное название скрипта или же она может автоматически регистрировать и загружать необходимые скрипты.

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

wp_register_style — Регистрация нового стиля.
wp_enqueue_style — Добавление нового стиля.

Далее перейдем к следующему хуку — создание меню в панели администрирования.

/**
 * Генерируем меню
 */
function admin_generate_menu()
 {
  // Добавляем основной раздел меню
  add_menu_page('Добро пожаловать в модуль управления отзывами', 'Отзывы', 'manage_options', 'edit-reviews', array(&$this, 'admin_edit_reviews'));

 // Добавляем дополнительный раздел
  add_submenu_page( 'edit-reviews', 'Управление содержимом', 'О плагине', 'manage_options', 'plugin_info', array(&$this,'admin_plugin_info'));
}

Рассмотрим функции для добавления элементов меню.

add_menu_page — Добавляем основной раздел меню. Функция принимиает несколько параметров, а именно:
1 — Название новой страницы
2 — Название раздела в боковом меню
3 — Права доступа
4 — Уникальный идентификатор раздела (slug). Если же следующий параметр — функция — не будет указан, то данный параметр используется, как название вызываемого файла.
5 — Функция для отображения контента выбранной страницы.
6 — Путь к иконке
7 — Расположение в меню

add_submenu_page— Добавление дочернего элемента меню к основному. Функция по параметрам идентична предыдущей, только первым параметром передается уникальный идентификатор или slug родительской страницы.

Теперь, если зайти в панель управления, то мы увидим наше созданное меню.

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

/**
 * Выводим список отзывов для редактирования
 */
public function admin_edit_reviews()
 {
  global $wpdb;

  $action = isset($_GET['action']) ? $_GET['action'] : null ;

  switch ($action) {

  case 'edit':
   // Получаем данные из БД
   $this->data['review'] = $wpdb->get_row("SELECT * FROM `" . $this->tbl_adv_reviews . "` WHERE `ID`= ". (int)$_GET['id'], ARRAY_A);

   // Подключаем страницу для отображения результатов
   include_once('edit_review.php');
  break;

  case 'submit':
   $inputData = array(
    'review_title' 	  => strip_tags($_POST['review_title']),
    'review_text' 	  => strip_tags($_POST['review_text']),
    'review_user_name' 	  => strip_tags($_POST['review_user_name']),
    'review_user_email'   => strip_tags($_POST['review_user_email']),
   );

   $editId=intval($_POST['id']);

   if ($editId == 0) return false;

   // Обновляем существующую запись
   $wpdb->update( $this->tbl_adv_reviews, $inputData, array( 'ID' => $editId ));

   // Показываем список отзывов
   $this->admin_show_reviews();
  break;

  case 'delete':

   // Удаляем существующую запись
   $wpdb->query("DELETE FROM `".$this->tbl_adv_reviews."` WHERE `ID` = '". (int)$_GET['id'] ."'");

   // Показываем список отзывов
   $this->admin_show_reviews();
   break;

   default:
    $this->admin_show_reviews();
  }
}

/**
 * Функция для отображения списка отзывов в адм. панели
 */
private function admin_show_reviews()
{
 global $wpdb;

 // Получаем данные из БД
 $this->data['reviews'] = $wpdb->get_results("SELECT * FROM `" . $this->tbl_adv_reviews . "`", ARRAY_A);

 // Подключаем страницу для отображения результатов
 include_once('view_reviews.php');
}

/**
 * Показываем статическую страницу
 */
public function admin_plugin_info()
{
 include_once('plugin_info.php');
}

Данный код — это основной функционал для управления отзывами на сайте. Особый интерес здесь представляют собой выполнение SQL запросов для получения, обновления и удаления данных.
Например метод $wpdb->get_row — получает одну запись, а метод $wpdb->get_results — группу записей. По умолчанию всегда возвращается объект, но передавая параметр ARRAY_A будет возвращаться массив данных. Более подробно о всех видах SQL запросов в WordPress можно прочитать тут.

Каждое действие зависит от переданного параметра «action», соответственно «edit» -редактирование отзыва, «submit» — сохранение отредактированного отзыва и «delete» — удаление отзыва.

Обмен данными со страницами отображения происходит через свойство объекта «data». Исходный код этих страниц будет выложен в архиве с данным модулем в конце статьи. Тут я их не буду вставлять, так как топик уже оказался достаточно большим.

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

Что бы указать wordpress, когда вызывать наш плагин, необходимо зарегистрировать «shortcode», что и было сделано в конструкторе нашего класса. Подробнее об этом написано здесь.

add_shortcode('show_reviews', array (&$this, 'site_show_reviews'));

Теперь на любой странице сайта можно разместить вот такой код [show_reviews] и это заставит выполнить указанную нами функцию (передается вторым параметром). Ниже представлен исходный код данной функции.

/**
 * Список отзывов на сайте
 */
 public function site_show_reviews($atts, $content=null)
 {
  global $wpdb;

  if (isset($_POST['action']) && $_POST['action'] == 'add-review') {
   $this->add_user_review();
  }

  // Выбираем все отзывы из Базы Данных
  $this->data['reviews'] = $wpdb->get_results("SELECT * FROM `" . $this->tbl_adv_reviews . "`", ARRAY_A);

 ## Включаем буферизацию вывода
 ob_start ();
 include_once('site_reviews.php');
 ## Получаем данные
 $output = ob_get_contents ();
 ## Отключаем буферизацию
 ob_end_clean ();

 return $output;
}

private function add_user_review()
{
 global $wpdb;

 $inputData = array(
  'review_title' 	=> strip_tags($_POST['review_title']),
  'review_text' 	=> strip_tags($_POST['review_text']),
  'review_user_name'    => strip_tags($_POST['review_user_name']),
  'review_user_email'   => strip_tags($_POST['review_user_email']),
 );

 // Добавляем новый отзыв на сайт
 $wpdb->insert( $this->tbl_adv_reviews, $inputData );
}

В принципе тут ничего сложного нету — делается SQL запрос на выборку данных, если же передан параметр «action», то сначала добавляется новый отзыв. Но стоит обратить внимание на буферизацию вывода. Она необходима для того, что бы получить данные вставляемой страницы.

Вот собственно и все. Теперь можно посмотреть, что у нас получилось. А скачать плагин и исходные коды можно вот тут.

Само собой это только пример создания плагина, но и сойдет как простая гостевушка, если ее немного доработать, например, добавить защиту от ботов и постраничный вывод. Удачного кодинга:)

Форма на сайте:

Панель управления плагином:

Редактирование отзыва: