wordpress создание плагина(ов)

Рубрика: wordpress, Дата: 17 March, 2016, Автор:

Привет, сегодня рассмотрим как создать какой то законченный плагин. самый простой. Лучший способ научится создавать плагины это смотреть как создаютплагины другие пользователи в plugin directory.


Содержание:

1 Создание стандартной структуры файлов для плагина
2 Создание плагина заголовка
3 Добавляем стандартную плагин лицензию
4 Активация и деактивация плагина
5 Интернационализация
6 Определение путей
7 Безопастность плагинов
7.1 Nonces
7.2 Валидация данных и Sanitization
8 Hooks: Actions и Filters
9 Плагинов Установки
10 Создание меню и подменю
11 Создание страницы опций
12 Вордпресс интеграция
12.1 Создание meta box
12.2 Shortcode
12.3 Создаем Виджет
12.4 Создание Widget панели управления
12.5 Создание пользовательских таблиц (Custom Tables)
13 Uninstalling Your Plugin
14 Пример создания реального плагина
15 Размещение плагина в плагин директории


 

1 Создание стандартной структуры файлов для плагин

Така

/new-my-plagin (без пробелов и спец-символов)
–new-my-plagin.php (главный плагина файл PHP – файл)
–uninstal.php (файл деинсталяции твоего плагина)
–/js (папка для скриптов js)
–/css (папка для стилей css)
–/includes (папка для дополнительных PHP включений)
–/images (папка для плагина изображений)

2 Создание плагина заголовка

<?php
/*
Plugin Name: New My Plagin
Plugin URI: http://google.ru
Description: This is a brief description of my plugin
Version: 1.0
Author: Hacker Kselax
Author URI: http://kselax.ru
Text Domain: prowp-plugin
License: GPLv2
*/

только требуется Plugin Name, все остальные не обязательные параметры.

3 Добавляем стандартную плагин лицензию

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

/* Copyright YEAR PLUGIN_AUTHOR_NAME (email : PLUGIN AUTHOR EMAIL)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License 
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

 4 Активация и деактивация плагина

Когда активируется или деактивируется плагин, вызываются специальные функции и можно выполнять специальные действия, например при активации плагина выполняется функция register _ activation _ hook

//хук вызывается при активации плагина и можно проверить версию ворпдресс и совместима она с вашим плагином или нет
register_activation_hook( __FILE__, 'prowp_instal' );

function prowp_instal(){
	global $wp_version;//получаем версию вордпресс
	//сравниваем версию если 3.2 больше $wp_version, то true
	if(version_compare('3.2', $wp_version, '>'))
	{	
		wp_die( 'this plagin cannot activated because you use old version wordpress, update your wordpress please!'.$wp_version );
	}
}

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

При деактивации вызывается функция  register _deactivation _ hook и так мы можем тоже выполнять какие либо действия, например можно почистить за собой мусор, либо спросить пользователя что вы хотите очистить настройки вашего плагин

//хук вызывается при деактивации плагина, можно например почистить мусор за собой
register_deactivation_hook(__FILE__, 'prowp_deactivate' );

function prowp_deactivate(){
	//do something
	wp_die('do something when deactivate plugin!');
}

dirname( __FILE__ ) – возвращет путь к директори где находится файл

5 Интернационализация.

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

6 Определение путей

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

Определяем путь к директории плагина

//путь абсолютный к плагин директории
echo plugin_dir_path( __FILE__ ); 
//вернет Z:\home\wordpress.my\www\wp-content\plugins\new-my-plagin/

//путь абсолютный к скрипту
echo plugin_dir_path( __FILE__ ) .'js/script.js';
//вернет Z:\home\wordpress.my\www\wp-content\plugins\new-my-plagin/js/script.js

 

Определяем url – пути

 

//возвращает именно урл от корня сайта
echo ' '.plugins_url( 'imges/icon.png', __FILE__ ).' ';
//вернет http://wordpress.my/wp-content/plugins/new-my-plagin/imges/icon.png


//пример с изображением от корня сайта
echo '<img src="' .plugins_url( 'images/icon.png', __FILE__ ). '">';
вернет <img src="http://wordpress.my/wp-content/plugins/new-my-plagin/images/icon.png">

 

 

Список различных функций определения урлов в wordpress

admin_url(); —Admin URL (  http://wordpress.my/wp-admin/ )
site_url() —Site URL для текущего сайта ( http://wordpress.my)
home_url() —Home URL для текущего сайта (http://wordpress.my)
includes_url() —Includes directory URL ( http://wordpress.my//wp?includes/ )
content_url() —Content directory URL ( http://wordpress.my//wp?content)
wp_upload_dir() —Возвращает массив с местной информацией на настройки uploads directory

Пример возврата wp_upload_dir()

wp_upload_dir7 Безопастность плагинов

7.1 Nonces
Cуществует nonces – это когда мы передаем данные из формы и сохраняем в плагине, например настройки какие нибуть плагина, то мы генерируем специальное дополнительное поле.
Добавим в форму специальное поле с помощью функции
wp_nonce_field(), для повышения безопасности следует устанавливать два параметра, первый это ключь с которого будет генерироваться уникальное число и второй это name для input.

<form method="post">
<?php wp_nonce_field( 'prowp_settings_form_save', 'prowp_nonce_field' ); ?>
Enter your name: <input type="text" name="text" /><br />
<input type="submit" name="submit" value="Save Options" />
</form>

Создасться форма с дополнительным сркытым полем

<form method="post">
<input type="hidden" id="prowp_nonce_field"
name="prowp_nonce_field" value="1cfd4c0539" />
<input type="hidden" name="_wp_http_referer"
value="/wp-trunk/contact/" />
Enter your name: <input type="text" name="text" /><br />
<input type="submit" name="submit" value="Save Options" />
</form>

Когда форма отправлена, мы проверяем наше nonce используя функция wp_verify_nonce(), ей передаем два параметра ключ и name, теже самые что были переданы ранее при создании поля и все.

if ( isset( $_POST['submit'] ) ) {
  //check nonce for security
  if(wp_verify_nonce( $_POST['prowp_nonce_field'], 'prowp_settings_form_save')==false)
      return;
 //nonce passed, now do stuff
}

7.2 Валидация данных и Sanitization
Для этого используются функции вида esc_attr_e(), где
esc_: префик для escaping функций
attr: escaping context ( attr , html , textarea , js , sql , url , and  url_raw )
_e : The optional translation suffi x. Available suffixes are __ and _e.

esc_html – заменяет html символы в html сущьности

$text = esc_html( "<>&\"'" );

esc_attr – используется когда нужно экранировать html атрибуты

<input type="text" name="first_name" value="<?php echo esc_attr( $text ); ?>">

esc _ textrea() – используется для эскейпа html <textarea> value

<textarea name="description"><?php echo esc_textarea( $text ); ?></textarea>

esc _ url() – используется для чистки урлов от незаконных символов

<a href="<?php echo esc_url( $url ); ?>">

esc _ js() – используется для чистки строки JavaScript

<script>
	var bwar='<?php echo esc_js( $text ); ?>';
	alert(bwar);
</script>

esc _ sql() – функция экранирует данные использующиеся в MySQL запросе

esc_sql( $sql );

esc_html_e – возвращает переведенный текст, а
esc_html__ – сохраняет в переменную

//escapes, translates, and displays the text
esc_html_e( $text, 'prowp-plugin' );
//escapes, translates, but does NOT display
$text = esc_html__( $text, 'prowp-plugin' );

intval() – функция PHP возвращает целое значение, если строка, то возвращает 0

$variable = 12345;
$variable = intval( $variable );

absint() – функция возвращает результат всегда не негативное целое, только положительное

$variable = 12345;
$variable = absint( $variable );

sanitize_text_field() – функция используется для sanitize данных которые будут сохраняться в базу данных. This function will remove all invalid UTF?8 characters, convert single < into HTML entities, and remove all HTML tags, line breaks, and extra white space.

sanitize_text_field( $text );

sanitize _ email() – эта функция удаляет символы что не содержаться в email ардесах

$sanitized_email = sanitize_email( ' ?ric@loremipsum.com!' );
echo $sanitized_email; //will output: ric@loremipsum.com

wp _ kses() – функция позволяет определять теги которые разрешены и не будут удаляться.

$allowed_tags = array(
  'strong' => array(),
  'a' => array(
    'href' => array(),
    'title' => array()
  )
);
$html = '<a href="#" class="external">link</a>.
This is <b>bold</b> and <strong>strong</strong>';
echo wp_kses( $html, $allowed_tags );

Код выше выведет следующий код без тега <b>

<a href="#">link</a>. This is bold and <strong>strong</strong>

8 Hooks: Actions и Filters

Хуки это правильный способ взаимодейтсвия плагинов с содержимым wordpress. Два типа Хуков может быть использовано Actions и Filters

Action hooks – хуки вызываются событиями в wordpress. Например Action hook вызывается когда новый пост опубликован
add_action() – ринимает 4 параметра как и Filter hooks (смотри ниже)
Пример использования:

add_action( 'comment_post', 'prowp_email_new_comment' );
function prowp_email_new_comment() {
  wp_mail( 'me@example.com', 'New blog comment',
'There is a new comment on your website: http://example.com' );
}

Действие ‘comment_post’ вызывается когда новый комментарий добавляется в wordpress и отсылается письмо на мэйл администратора например.

Несколько общих Action Hooks
–Some of the more common Action hooks are:
–publish_post —Triggered when a new post is published.
–create_category —Triggered when a new category is created.
–switch_theme —Triggered when you switch themes.
–admin_head —Triggered in the <head> section of the admin dashboard.
–wp_head —Triggered in the <head> section of your theme.
–wp_footer —Triggered in the footer section of your theme usually directly before the
</body> tag.
–init —Triggered after WordPress has finished loading, but before any headers are sent. Good place to intercept  $_GET and $_POST HTML requests.
–admin_init —Same as  init but only runs on admin dashboard pages.
–user_register —Triggered when a new user is created.
–comment_post —Triggered when a new comment is created.

Несколько популярных Action Hooks »

wp_head используя этот хук, вы добавляете любой пользовательский код в вашу тему между <head></head>

//добавляет код в тему между <head></head>
add_action( 'wp_head', 'prowp_custom_css' );
function prowp_custom_css() {
?>
<style type="text/css">
a {
	font-size: 14px;
	color: #000000;
	text-decoration: none;
}
a:hover {
	font-size: 14px
	color: #FF0000;
	text-decoration: underline;
}
</style>
<?php
}

wp_footer – используется чтобы добавить пользовательский код в footer темы, например google analytic

add_action( 'wp_footer', 'prowp_site_analytics' );
function prowp_site_analytics() {
?>
<script type="text/javascript">
	alert('hello world!');
</script>
<h1>тут</h1>
<?php
}

 

Filter hooks – модифицируют wordpress содержимое до сохранения в БД или показа на экран. Например ты можешь модифицировать контент после извлечения из БД до показа на экран.
add_filter() – функция выполняет фильтр действие, принимает 4 параметра
–filter_action (string) —The filter to use.
–custom_filter_function (string) —The custom function to pass the filter through.
–priority (integer) —The priority in which this filter should run. When multiple callback
–functions are attached to the same hook, the  priority parameter determines the execution order.
–accepted args (integer) —The number of arguments the function accepts.
Пример использования:

add_filter('the_content', 'prowp_function');

function prowp_function($content){
	$content=$content."hello wordl!";
	return $content;
}

Добавляет “hello world!” в конце к the_content.

В wordpress больше чем 2000 разных фильтров, самые общие из них:
–the_content —Applied to the content of the post, page, or custom post type before
displaying
–the_content_rss —Applied to the content of the post , page, or custom post type for RSS
inclusion
–the_title —Applied to the post, page, or custom post type title before displaying
–comment_text —Applied to the comment text before displaying
–wp_title —Applied to the page <title> header tag before displaying
–the_permalink —Applied to the permalink URL

Несколько примеров фильтров »

Добавляет rss в конец поста

add_filter ( 'the_content', 'prowp_subscriber_footer' );
function prowp_subscriber_footer( $content ) {
    //проверяем если одиночная запись
    if( is_single()|| is_page() ) {
        $content.= '<h3>Enjoyed this article?</h3>';
        $content.= '<p>Subscribe to my
        <a href="'.site_url().'/feed">RSS feed</a>!</p>';
    }
    return $content;
}

Добавляет в конец title

add_filter( 'the_title', 'prowp_custom_title' );
function prowp_custom_title( $title ) {
    $title .= ' - By wordpress.my';
    return $title;
}

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

add_filter( 'default_content', 'prowp_default_content' );
function prowp_default_content( $content ) {
	$content = 'For more great content please subscribe to my RSS feed';
	return $content;
}

 9 Плагинов Установки

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

Сохранение плагина опций
add _ option() и and update _ option() – Обе функции создают опции, но update_options() также и обновляет опцию если она уже создана. На практике используется для создания и обновления только одна функция update_options()

//добавляем новую опцию
add_option( 'prowp_display_mode', 'Spooky' );
//обновляем опцию, если она не создана, то создается новая
update_option( 'prowp_display_mode', 'Scary' );

get_option() – функция возвращает опцию если она создана и если нет то FALSE

echo get_option( 'prowp_display_mode' );

delete_option( ) – функция удаляет опцию

delete_option( 'prowp_display_mode' );
Опции вы должны предворять уникальным префиксом, как мы это делаем prowp_, потому что много плагинов и тем и они все создают свои опции в той же самой таблице, это нужно чтобы небыло конфликта

Array of options
Нужно использовать для опций массив, потому что так будет одна строка в таблице options, функции используются теже самые что и для одиночных опций
Пример кода:

$prowp_options_arr = array(
	'prowp_display_mode' => 'Spooky',
	'prowp_default_movie' => 'Halloween',
	'prowp_default_book' => 'Professional WordPress'
);
//создаем опцию, так же можно ее обновить
update_option( 'prowp_plugin_options', $prowp_options_arr );

$prowp_display_mode = $prowp_options_arr['prowp_display_mode'];
$prowp_default_movie = $prowp_options_arr['prowp_default_movie'];
$prowp_default_book = $prowp_options_arr['prowp_default_book'];
//удаляем опцию
delete_option('prowp_plugin_options');

 10 Создание меню и подменю

Меню могут быть двух видов
1. top-level меню, со своими подпунктами
2. Меню как пункт существующего меню Settings(Настройки)

Top-level Menu – это меню создается когда твой плагин имеет множество страниц настроек. Создается с помощью функции:
add_menu_page( page_title, menu_title, capability,
menu_slug, function, icon_url, position );, где
–page_title —Text used for the HTML title (between <title> tags).
–menu_title —Text used for the menu name in the Dashboard.
–capability —Minimum user capability required to see menu.
–menu_slug —Unique slug name for your menu.
–function —Displays page content for the menu settings page.
–icon_url —Path to custom icon for menu (default: images/generic.png ).
–position —The position in the menu order the menu should appear. By default, the menu
will appear at the bottom of the menu structure.
add _ submenu _ page() – функция создает дополнительные подпункты для подменю

add_submenu_page( parent, page_title, menu_title, capability,
menu_slug,[function] );

Пример кода создающего множественное меню

// create custom plugin settings menu
add_action( 'admin_menu', 'prowp_create_menu' );
function prowp_create_menu() {
	//create new top-level menu
	add_menu_page( 'Halloween Plugin Page', 'Halloween Plugin',
	'manage_options', 'prowp_main_menu', 'prowp_main_plugin_page',
	plugins_url( '/images/wordpress.png', __FILE__ ) );
	//create two sub-menus: settings and support
	add_submenu_page( 'prowp_main_menu', 'Halloween Settings Page',
	'Settings', 'manage_options', 'halloween_settings',
	'prowp_settings_page' );
	add_submenu_page( 'prowp_main_menu', 'Halloween Support Page',
	'Support', 'manage_options', 'halloween_support', 'prowp_support_page' );
}

Появится подпункт, после меню Настройки
top-level menuМы можем передать 7 параметрв в функцию add_menu_page() и определить позицию где будет меню находится

Список позиций меню »

  • Dashboard—2
  • Posts—5
  • Media—10
  • Pages—20
  • Comments—25
  • Appearance—60
  • Plugins—65
  • Users—70
  • Tools—75
  • Settings—80

Добавление в существующее меню 
Большинство плагинов имеют только одну страницу настройки, поэтому ее добавляем в существующее меню
Пример создания:

add_action( 'admin_menu', 'prowp_create_settings_submenu' );
function prowp_create_settings_submenu() {
	add_options_page( 'Halloween Settings Page', 'Halloween Settings',
	'manage_options', 'halloween_settings_menu', 'prowp_settings_page' );
}

add_options_page() – создает подпункт в меню, принимает следующие параметры
1 – Заглавие страницы
2 – Название подпункта меню
3 – Устанавливает, что меню видно только администраторам
4 – Уникальный меню обработчик, для ссылки
5 – Пользовательская функция, что строит страницу

Доступные подменю функции в wordpress »

add_dashboard_page() —Adds submenu items to the Dashboard menu
add_posts_page() —Adds submenu items to the Posts menu
add_media_page() —Adds a submenu item to the Media menu
add_pages_page() —Adds a submenu item to the Pages menu
add_comments_page() —Adds a submenu item to the Comments menu
add_plugins_page() —Adds a submenu item to the Plugins menu
add_theme_page() —Adds a submenu item to the Appearance menu
add_users_page() —Adds a submenu item to the Users page (or Profi le based on role)
add_management_page() —Adds a submenu item to the Tools menu
add_options_page() —Adds a submenu item to the Settings menu

11 Создание страницы опций

Пример страницы меню »

// Создание пользовательского плагин меню
add_action( 'admin_menu', 'prowp_create_menu' );
function prowp_create_menu() {
	//создание топ-уровня меню
	add_menu_page( 'Halloween Plugin Page', 'Halloween Plugin',	'manage_options', 'prowp_main_menu', 'prowp_settings_page' );
	//вызов register settings function
	add_action( 'admin_init', 'prowp_register_settings' );
}

function prowp_register_settings() {
	//Регистрирует наши настройки
	//1 - имя группы связывает опцию со страницей
	//2 - действительное опции имя, должно быть уникальным
	//3 - callback функция sanitize опции данные
	register_setting( 'prowp-settings-group', 'prowp_options',
	'prowp_sanitize_options' );
}

function prowp_sanitize_options( $input ) {
	$input['option_name'] = sanitize_text_field( $input['option_name'] );
	$input['option_email'] = sanitize_email( $input['option_email'] );
	$input['option_url'] = esc_url( $input['option_url'] );
	return $input;
}

function prowp_settings_page() {
?>
	<div class="wrap">
		<h2>Halloween Plugin Options</h2>
		<form method="post" action="options.php">
			<!-- устанавливает связь между опциями и их значениями 
			Добавляет nonce
			устанавливает связь со страницей куда переадресовывать форму-->
			<?php settings_fields( 'prowp-settings-group' ); ?>
			<!-- получаем опции в переменную -->
			<?php $prowp_options = get_option( 'prowp_options' ); ?>
			<table class="form-table">
			<tr valign="top">
			<th scope="row">Name</th>
			<td><input type="text" name="prowp_options[option_name]"
			value="<?php echo esc_attr( $prowp_options['option_name']
			); ?>" /></td>
			</tr>
			<tr valign="top">
			<th scope="row">Email</th>
			<td><input type="text" name="prowp_options[option_email]"
			value="<?php echo esc_attr( $prowp_options['option_email']
			); ?>" /></td>
			</tr>
			<tr valign="top">
			<th scope="row">URL</th>
			<td><input type="text" name="prowp_options[option_url]"
			value="<?php echo esc_url( $prowp_options['option_url'] );
			?>" /></td>
			</tr>
			</table>
			<p class="submit">
			<input type="submit" class="button-primary" value="Save Changes" />
			</p>
		</form>
	</div>
<?php
}

Пример Top-level Menu на 3 пункта »

//создаем пользовательское плагин меню на несколько пунктов
add_action('admin_menu', 'prowp_create_menu');
function prowp_create_menu(){
	//создаем новое top-level menu
	//1 - title страницы
	//2 - title пункта
	//3 - видно в админке только администратору
	//4 - уникальный slug
	//5 - callback function
	add_menu_page( 'My_menu_title', 'My_menu', 'manage_options', 'prowp_main_menu', 'prowp_main_menu_page' );
	//создаем подменю
	//1 - родительский слог
	//2 - title страницы
	//3 - title пункта
	//4 - видно только администратору
	//5 - уникальный slug
	//6 - callback function
	add_submenu_page( 'prowp_main_menu', 'My_menu Settings Page', 'Settings', 'manage_options', 'my_menu_settings', 'prowp_settings_page' );
	add_submenu_page( 'prowp_main_menu', 'My_menu Support Page', 'Support', 'manage_options', 'my_menu_support', 'prowp_support_page' );

	//регистрируем установки меню
	add_action( 'admin_init', 'prowp_register_settings' );
}

function prowp_register_settings() {
	//регистрируем настройки для главной страницы
	register_setting( 'prowp-settings-group1', 'prowp_options1', 'prowp_sanitize_options1' );
	//регистрируем настройки для субстраницы Settings
	register_setting( 'prowp-settings-group2', 'prowp_options2', 'prowp_sanitize_options2' );
	//регистрируем настройки для субстраницы Support
	register_setting( 'prowp-settings-group3', 'prowp_options3', 'prowp_sanitize_options3' );
}

function prowp_sanitize_options1($input){
	$input['name']=sanitize_text_field($input['name']);
	$input['emale']=sanitize_email($input['emale']);
	return $input;
}
function prowp_sanitize_options2($input){
	$input['name']=sanitize_text_field($input['name']);
	$input['emale']=sanitize_email($input['emale']);
	return $input;
}
function prowp_sanitize_options3($input){
	$input['name']=sanitize_text_field($input['name']);
	$input['emale']=sanitize_email($input['emale']);
	$input['url']=esc_url($input['url']);
	return $input;
}

// функции отображения 3 страниц настроек
function prowp_main_menu_page(){
?>

<div class="wrap">
	<h2>My_menu Options</h2>
	<form method="post" action="options.php">
		<!-- связываем форму с опциями -->
		<?php settings_fields( 'prowp-settings-group1' ); ?>
		<!-- получаем данные -->
		<?php $prowp_options = get_option( 'prowp_options1' ); ?>
		<table class="form-table">
			<tr valid="top">
				<th scope="row">Name1:</th>
				<td><input type="text" name="prowp_options1[name]" value="<?php echo esc_attr($prowp_options['name']); ?>"></td>
			</tr>
			<tr valid="top">
				<th scope="row">Email1:</th>
				<td><input type="text" name="prowp_options1[emale]" value="<?php echo esc_attr($prowp_options['emale']); ?>">
				</td>
			</tr> 
		</table>
		
		<p class="submit">
			<input type="submit" class="button-primary" value="Save Changes">
		</p>
	</form>
</div>


<?php
}

function prowp_settings_page(){
?>
<div class="wrap">
	<h2>Setting Options</h2>
	<form method="post" action="options.php">
		<!-- связываем форму с опциями -->
		<?php settings_fields( 'prowp-settings-group2' ); ?>
		<!-- получаем данные -->
		<?php $prowp_options = get_option( 'prowp_options2' ); ?>
		<table class="form-table">
			<tr valid="top">
				<th scope="row">Name2:</th>
				<td><input type="text" name="prowp_options2[name]" value="<?php echo esc_attr($prowp_options['name']); ?>"></td>
			</tr>
			<tr valid="top">
				<th scope="row">Email2:</th>
				<td><input type="text" name="prowp_options2[emale]" value="<?php echo esc_attr($prowp_options['emale']); ?>">
				</td>
			</tr> 
		</table>
		
		<p class="submit">
			<input type="submit" class="button-primary" value="Save Changes">
		</p>
	</form>
</div>
<?php
}

function prowp_support_page(){
?>
<div class="wrap">
	<h2>Setting Options</h2>
	<form method="post" action="options.php">
		<!-- связываем форму с опциями -->
		<?php settings_fields( 'prowp-settings-group3' ); ?>
		<!-- получаем данные -->
		<?php $prowp_options = get_option( 'prowp_options3' ); ?>
		<table class="form-table">
			<tr valid="top">
				<th scope="row">Name3:</th>
				<td><input type="text" name="prowp_options3[name]" value="<?php echo esc_attr($prowp_options['name']); ?>"></td>
			</tr>
			<tr valid="top">
				<th scope="row">Email3:</th>
				<td><input type="text" name="prowp_options3[emale]" value="<?php echo esc_attr($prowp_options['emale']); ?>">
				</td>
			</tr> 
			<tr valid="top">
				<th scope="row">Url:</th>
				<td><input type="text" name="prowp_options3[url]" value="<?php echo esc_attr($prowp_options['url']); ?>">
				</td>
			</tr> 
		</table>
		
		<p class="submit">
			<input type="submit" class="button-primary" value="Save Changes">
		</p>
	</form>
</div>
<?php
}

Пример меню как встроенный пункт в готовое меню »

add_action( 'admin_menu', 'prowp_create_settings_submenu' );
function prowp_create_settings_submenu() {
	add_options_page( 'Halloween Settings Page', 'Halloween Settings',	'manage_options', 'halloween_settings_menu', 'prowp_settings_page' );

	//call register settings function
	add_action( 'admin_init', 'prowp_register_settings' );
}

function prowp_register_settings() {
//register our settings
register_setting( 'prowp-settings-group', 'prowp_options',
'prowp_sanitize_options' );
}

function prowp_sanitize_options( $input ) {
	$input['option_name'] = sanitize_text_field( $input['option_name'] );
	$input['option_email'] = sanitize_email( $input['option_email'] );
	$input['option_url'] = esc_url( $input['option_url'] );
	return $input;
}

//функция отображающая форму на странице меню
function prowp_settings_page(){
?>
<div class="wrap">
	<h2>Halloween Plugin Options</h2>
	<form method="post" action="options.php">
	<!-- связываем опции со страницей -->
	<?php settings_fields( 'prowp-settings-group' ); ?>
	<!-- получаем опции из БД -->
	<?php $prowp_options = get_option( 'prowp_options' ); ?>
	<table class="form-table">
	<tr valign="top">
		<th scope="row">Name</th>
		<td><input type="text" name="prowp_options[option_name]"
		value="<?php echo esc_attr( $prowp_options['option_name']
		); ?>" /></td>
	</tr>
	<tr valign="top">
		<th scope="row">Email</th>
		<td><input type="text" name="prowp_options[option_email]"
		value="<?php echo esc_attr( $prowp_options['option_email']
		); ?>" /></td>
	</tr>
	<tr valign="top">
		<th scope="row">URL</th>
		<td><input type="text" name="prowp_options[option_url]"
		value="<?php echo esc_url( $prowp_options['option_url'] );
		?>" /></td>
	</tr>
	</table>

	<p class="submit">
		<input type="submit" class="button-primary" value="Save Changes" />
	</p>

	</form>
</div>
<?php
}

В вордпресс можно создать опции в какой то готовой странице, например в странице Настройки -> Чтение

Создание секции опций встроенных в готовую страницу »

//выполняет наши настройки секции функций
add_action( 'admin_init', 'prowp_settings_init' );
function prowp_settings_init() {
	//создаем новые настрокйи секцию в Settings > Reading page
	//1 - уникальный ID для секции
	//2 - показывает имя выводящееся на странице
	//3 - callback function
	//4 - идентификатор куда добавляется секция, по умолчанию в wordpress существует (general , writing , reading , discussion , media , and  permalink )
	add_settings_section( 'prowp_setting_section',
	'Halloween Plugin Settings', 'prowp_setting_section', 'reading' );
	//регистрируем две настройки опции
	//1 - уникальный id поля
	//2 - заглавие поля показаное сразу слева поля
	//3 - callback function
	//4 - идентификатор страницы (reading)
	//5 - идентификатор секции куда добавляется поле
	add_settings_field( 'prowp_setting_enable_id', 'Enable Halloween Feature?',	'prowp_setting_enabled', 'reading', 'prowp_setting_section' );
	add_settings_field( 'prowp_saved_setting_name_id', 'Your Name',	'prowp_setting_name', 'reading', 'prowp_setting_section' );
	
	// регистрируем опции
	//1 - идентификатор страницы
	//2 - название опции
	//3 - callback function sanitize
	register_setting( 'reading', 'prowp_setting_values',
	'prowp_sanitize_settings' );
}

//функция sanitize данные, которые сохраняются в БД
function prowp_sanitize_settings( $input ) {
	$input['enabled'] = ( $input['enabled'] == 'on' ) ? 'on' : '';
	$input['name'] = sanitize_text_field( $input['name'] );
	return $input;
}

//функция рисует секцию
function prowp_setting_section() {
	echo '<p>Configure the Halloween plugin options below</p>';
}
//функция добавляет поле
function prowp_setting_enabled() {
	//получаем опции из БД
	$prowp_options = get_option( 'prowp_setting_values' );

	//показываем чекбокс
	echo '<input '.checked( $prowp_options['enabled'], 'on', false ).'	name="prowp_setting_values[enabled]" type="checkbox" /> Enabled';
}
//функция еще добавляет одно поле
function prowp_setting_name() {
	//получаем опции из БД
	$prowp_options = get_option( 'prowp_setting_values' );
	//показывает текстовое поле формы
	echo '<input type="text" name="prowp_setting_values[name]"	value="'.esc_attr( $prowp_options['name'] ).'" />';
}

reading

Еще один пример меню-секции writing »

//выполняет наши настройки секции функций
add_action( 'admin_init', 'prowp_settings_init' );
function prowp_settings_init() {
	//создаем новые настрокйи секцию в Settings > Reading page
	//1 - уникальный ID для секции
	//2 - показывает имя выводящееся на странице
	//3 - callback function
	//4 - идентификатор куда добавляется секция, по умолчанию в wordpress существует (general , writing , reading , discussion , media , and  permalink )
	add_settings_section( 'prowp_setting_section',
	'Пользовательская секция', 'prowp_setting_section', 'writing' );
	//регистрируем две настройки опции
	//1 - уникальный id поля
	//2 - заглавие поля показаное сразу слева поля
	//3 - callback function
	//4 - идентификатор страницы (reading)
	//5 - идентификатор секции куда добавляется поле
	add_settings_field( 'prowp_setting_enable_id', 'Имя:',	'prowp_setting_enabled', 'writing', 'prowp_setting_section' );
	add_settings_field( 'prowp_saved_setting_name_id', 'Твой майл:', 'prowp_setting_name', 'writing', 'prowp_setting_section' );
	
	// регистрируем опции
	//1 - идентификатор страницы
	//2 - название опции
	//3 - callback function sanitize
	register_setting( 'writing', 'prowp_setting_values1',
	'prowp_sanitize_settings' );
}

//функция sanitize данные, которые сохраняются в БД
function prowp_sanitize_settings( $input ) {
	$input['name'] = sanitize_text_field($input['name']);
	$input['mail'] = sanitize_email($input['mail']);
	return $input;
}

//функция рисует секцию
function prowp_setting_section() {
	echo '<p>Настроим опции далее</p>';
}
//функция добавляет поле
function prowp_setting_enabled() {
	//получаем опции из БД
	$prowp_options = get_option( 'prowp_setting_values1' );

	//показывает текстовое поле name формы
	echo '<input type="text" name="prowp_setting_values1[name]"	value="'.esc_attr( $prowp_options['name'] ).'" />';
}
//функция еще добавляет одно поле
function prowp_setting_name() {
	//получаем опции из БД
	$prowp_options = get_option( 'prowp_setting_values1' );
	//показывает текстовое поле формы
	echo '<input type="text" name="prowp_setting_values1[mail]"	value="'.esc_attr( $prowp_options['mail'] ).'" />';
}

writing

12 Вордпресс интеграция

Интеграция твоего плагина в вордпресс это существенный шаг взаимодействия с твоим плагином в админ панели. Вордпресс имеет много плащадок куда твой плагин может быть интегрирован: meta box, sidebar and dashboard widgets, and custom shortcodes. Это все мы рассмотрим дальше.

12.1 Создание meta box
add_meta_box( $id, $title, $callback, $page, $context, $priority, $callback_args ); – функция создает meta box в плагине, где параметры
–$id —The HTML ID attribute for the meta box
–$title —The title displayed in the header of the meta box
–$callback —The custom function name to display your meta box information
–$page —The page you want your meta box to display on ( ‘post’ , ‘page’ , or custom post type name)
–$context —The part of the page where the meta box should be displayed (  ‘normal’ ,
‘advanced’ , or ‘side’ )
–$priority —The priority within the context where the meta box should display (  ‘high’ , ‘core’ , ‘default’ , or  ‘low’ )
–$callback_args —Arguments to pass into your callback function

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

Пример создания Meta box для постов с данными из option »

//создаем данные для теста
$data=get_option('prowp_test_variable');
if(strcmp($data['name'],'')==0)
{
	wp_die('end');
	$data['name']='test';
	update_option( 'prowp_test_variable', $data);
}


add_action( 'add_meta_boxes', 'prowp_meta_box_init' );
// meta box functions for adding the meta box and saving the data
function prowp_meta_box_init() {
	// создаем наш пользовательский metabox
	add_meta_box( 'prowp-meta', 'Product Information',
	'prowp_meta_box', 'post', 'side', 'default' );
}

function prowp_meta_box( $post, $box ) {
	// получаем данные из БД
	$data=get_option( 'prowp_test_variable');
	
	//nonce for security
	wp_nonce_field( plugin_basename( __FILE__ ), 'prowp_save_meta_box' );
	echo "имя: ";
	echo '<input type="text" name="prowp_name" value="'.$data["name"].'" />';
}

//хук сохраняет наши метаданные когда пост сохраняется
add_action( 'save_post', 'prowp_save_meta_box' );
function prowp_save_meta_box( $post_id ) {
	// process form data if $_POST is set
	//если пост
	if( isset( $_POST['prowp_name'] ) ) {
		// if auto saving skip saving our meta box data
		//если авто-сохранение, пропустить пропустить сохранение наших метабокс
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
		return;
		//check nonce for security
		//проверяем nonce для безопасности
		wp_verify_nonce( plugin_basename( __FILE__ ), 'prowp_save_meta_box' );
		// save the meta box data as post meta using the post ID as a unique prefix
		//сохраняем данные
		
		$data['name']=$_POST['prowp_name'];
		update_option( 'prowp_test_variable', $data);
	}
}

Вот нормальный пример создания метаданных. Метаданные добавляются в таблицу postmeta и когда мы удаляем пост, то метаданные сами удаляются

Пример создания Metabox для постов »

//хук создает метабокс
add_action( 'add_meta_boxes', 'prowp_meta_box_init' );
// meta box functions for adding the meta box and saving the data
//метабокс функция для добавления мета-бокс и сохранения данных
function prowp_meta_box_init() {
	// создаем наш пользовательский metabox
	//1 - HTML ID attribute
	//2 - title в метабоксе
	//3 - callback function
	//4 - тип постов ('post','page',or custom post type name)
	//5 - размещение ('normal','advanced',or 'side')
	//6 - приоритет ('high','core','default',or 'low')
	add_meta_box( 'prowp-meta', 'Product Information',
	'prowp_meta_box', 'post', 'side', 'default' );
}

function prowp_meta_box( $post, $box ) {
	// retrieve the custom meta box values
	// получаем пользовательские мета-бокс значения
	//1 - ID - поста
	//2 - meta_key - уникальный ключ для метаданного
	//3 - true - вернет значение в виде строки, если в значении сеарилизованный массив, то вернет нормальный массив
	$prowp_featured = get_post_meta( $post->ID, '_prowp_type', true );
	$prowp_price = get_post_meta( $post->ID, '_prowp_price', true );
	//nonce for security
	//нонсе для безопасности
	//1 - Уникальный идентификатор для создаваемого поля. Имя именно этого проверочного поля.
	//2 - Параметр аттрибута name у HTML тега input.
	wp_nonce_field( plugin_basename( __FILE__ ), 'prowp_save_meta_box' );
	// custom meta box form elements
	//пользовательский мета бокс форма элементов
	echo '<p>Price: <input type="text" name="prowp_price"
	value="'.esc_attr( $prowp_price ).'" size="5" /></p>';
	echo '<p>Type:
	<select name="prowp_product_type" id="prowp_product_type">
	<option value="normal" ' .selected( $prowp_featured, 'normal', false ). '>Normal
	</option>
	<option value="special" ' .selected( $prowp_featured, 'special', false ). '>Special
	</option>
	<option value="featured" ' .selected( $prowp_featured, 'featured', false ). '>Featured
	
	</option>
	<option value="clearance" ' .selected( $prowp_featured, 'clearance', false ). '>Clearance
	</option>
	</select></p>';
}

// hook to save our meta box data when the post is saved
//хук сохраняет нашего метабокс данные когда пост сохранен
add_action( 'save_post', 'prowp_save_meta_box' );
function prowp_save_meta_box( $post_id ) {
	// process form data if $_POST is set
	// проверяем существования элемента из формы
	if( isset( $_POST['prowp_product_type'] ) ) {
		// if auto saving skip saving our meta box data
		// если авто-сохранение, пропускаем сохранение
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
		return;
		//check nonce for security
		//1 - значение уникальное из поля.
                //2 - ключь 
                if(wp_verify_nonce($_POST['prowp_save_meta_box'],plugin_basename( __FILE__ ))==false)
                return;
		// save the meta box data as post meta using the post ID as a unique prefix
		// сохраняем метабокс данные как post meta используя post ID и уникальный префикс
		//1 - post ID
		//2 - meta_key
		//3 - сами данные которые добавляются
		update_post_meta( $post_id, '_prowp_type',
		sanitize_text_field( $_POST['prowp_product_type'] ) );
		update_post_meta( $post_id, '_prowp_price',
		sanitize_text_field( $_POST['prowp_price'] ) );
	}
}

12.2 Shortcode

Простой шорткод »

add_shortcode( 'mytwitter', 'prowp_twitter' );
function prowp_twitter() {
	return '<a href="http://twitter.com/williamsba">@williamsba</a>';
}

Шорткод с параметрами »

add_shortcode( 'mytwitter', 'prowp_twitter' );
function prowp_twitter( $atts, $content = null ) {
	extract( shortcode_atts( array(
		'person' => 'brad' // set attribute default
	), $atts ) );

	if ( $person == 'brad' ) {
		return '<a href="http://twitter.com/williamsba">@williamsba</a>';
	}elseif ( $person == 'david' ) {
		return '<a href="http://twitter.com/mirmillo">@mirmillo</a>';
	}elseif ( $person == 'lisa' ) {
		return '<a href="http://twitter.com/lisasabinwilson">@lisasabinwilson</a>';
	}
}

12.3 Создаем Виджет

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

Пример создания widget »

//регистрируем виджет
add_action( 'widgets_init', 'prowp_register_widgets' );
function prowp_register_widgets() {
	register_widget( 'prowp_widget' );
}

class prowp_widget extends WP_Widget {
	function __construct() {
		//1 - classname - имя класса который добавляется
		//когда виджет отображается
		//2 - описание виджета, добавляется в виджеты
		$widget_ops = array(
			'classname' => 'prowp_widget_class',
			'description' => 'Example widget that displays a user's bio.' );
		//1 - похоже на название класса
		//2 - название виджета
		//3 - передаем опции виджета
		parent::__construct( 'prowp_widget', 'Bio Widget', $widget_ops );
	}


	function form( $instance ) {
		//определяем по умолчанию значения виджета
		$defaults = array(
			'title' => 'My Bio',
			'name' => 'Michael Myers',
			'bio' => '' );
		//вытягиваем установленное значение, ели оно
		//есть, нет то по умолчанию будет
		$instance = wp_parse_args( (array) $instance, $defaults );
		$title = $instance['title'];
		$name = $instance['name'];
		$bio = $instance['bio'];
		//отображаем 3 поля
		// $this->get_field_name - массив полей
		?>
		<p>Title:
		<input class="widefat"
		name="<?php echo $this->get_field_name( 'title' ); ?>"	type="text" value="<?php echo esc_attr( $title ); ?>" /></p>
		<p>Name:
		<input class="widefat"
		name="<?php echo $this->get_field_name( 'name' ); ?>" type="text" value="<?php echo esc_attr( $name ); ?>" /></p>
		<p>Bio:
		<textarea class="widefat" name="<?php echo $this->get_field_name( 'bio' ); ?>" >
		<?php echo esc_textarea( $bio ); ?></textarea></p>
		<?php
	}

	//обновляем виджет при нажатии на сохранить
	//1 - массив значений для каждого установленого поля
	//2 - старые значения
	function update( $new_instance, $old_instance ) {
		$instance = $old_instance;
		$instance['title'] = sanitize_text_field( $new_instance['title'] );
		$instance['name'] = sanitize_text_field( $new_instance['name'] );
		$instance['bio'] = sanitize_text_field( $new_instance['bio'] );
		return $instance;
	}

	//функция отображает твой виджет
	function widget( $args, $instance ) {
		//извлекаем args параметры в 
		//символьную таблицу
		extract( $args );
		echo $before_widget;
		//фильтруем заголовок
		//1 - название фильтра
		//2 - значение что нужно отфильтровать
		$title = apply_filters( 'widget_title', $instance['title'] );
		$name = ( empty( $instance['name'] ) ) ? ' ' : $instance['name'];
		$bio = ( empty( $instance['bio'] ) ) ? ' ' : $instance['bio'];
		//вывод title и дальше остальных данных
		if ( !empty( $title ) ) { echo $before_title . esc_html( $title )
		. $after_title; };
		echo '<p>Name: ' . esc_html( $name ) . '</p>';
		echo '<p>Bio: ' . esc_html( $bio ) . '</p>';
		echo $after_widget;
	}
}

 12.4 Создание Widget панели управления

Dashboard Widget »

//виджет для панели управления
add_action( 'wp_dashboard_setup', 'prowp_add_dashboard_widget' );
// call function to create our dashboard widget
// функция создает наш панели управления виджет
//1 - виджет id slug. Это класимя и ключ в массиве виджетов
//2 - отображает имя в dashboard
//3 - callback function
function prowp_add_dashboard_widget() {
	//
	wp_add_dashboard_widget(
		'prowp_dashboard_widget',
		'Pro WP Dashboard Widget',
		'prowp_create_dashboard_widget'
	);
}

// function to display our dashboard widget content
// функция отображает наш виджет в панели управления
function prowp_create_dashboard_widget() {
	echo '<p>Hello World! This is my Dashboard Widget</p>';
}

12.5 Создание пользовательских таблиц (Custom Tables)

Иногда бывает нужно создать в БД свою пользовательскую таблицу, для настроек или сохранения данных плагина. Она обычно создается при активации плагина register_activation_hook в ее callback function

Пример создания пользовательской таблицы »

//хук вызывается при активации плагина
//и в функции создается пользовательская таблица в БД
register_activation_hook( __FILE__, 'prowp_instal' );

function prowp_instal(){
	//нужен чтобы получить префикс таблиц
	global $wpdb;
	//define the custom table name
	//определяем пользовательское таблицы имя
	$table_name = $wpdb->prefix .'prowp_data';
	//build the query to create our new table
	// строим запрос создания новой таблицы
	$sql = "CREATE TABLE " .$table_name ." (
	id mediumint(9) NOT NULL AUTO_INCREMENT,
	time bigint(11) DEFAULT '0' NOT NULL,
	name tinytext NOT NULL,
	text text NOT NULL,
	url VARCHAR(55) NOT NULL,
	UNIQUE KEY id (id)
	);";
	//ABSPATH - абсолютный путь к директории wordpress
	require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
	//execute the query to create our table
	//выполняем запрос чтобы создать нашу таблицу
	dbDelta( $sql );
	//set the table structure version
	//устанавливаем версию таблицы
	$prowp_db_version = '1.0';
	//save the table structure version number
	//добавляем таблицы версию номер
	add_option( 'prowp_db_version', $prowp_db_version );

	//проверяем версию и если что обновляем
	$installed_ver = get_option( 'prowp_db_version' );
	if( $installed_ver != $prowp_db_version ) {
		//update database table here
		//обновляем базу данных таблицы сдесь
		//.....
		
		
		//update table version
		//обновляем версию таблицы
		update_option( 'prowp_db_version', $prowp_db_version );
	}
}

13. Uninstalling Your Plugin

Удалить настройкти твоего плагина можно используя файл uninstall.php. Он вызывается когда мы удаляем файлы плагина из админки. В него просто добавляем код

<?php
// If uninstall/delete not called from WordPress then exit
//Если удалить не вызвано из вордпресс то выход
if( !defined( 'ABSPATH' ) && !defined( 'WP_UNINSTALL_PLUGIN' ))
	exit();
// Delete option from options table
// удаляем опции из таблицы
delete_option( 'prowp_setting_values1' );
// Delete any other options, custom tables/data, files
//удаляем любые другие опции, пользовательские таблицы данных и файлы

?>

И существует еще хук, но предпочтительней использовать файл для удаления, во пример кода с хуком

register_uninstall_hook( __FILE__, 'prowp_uninstall_hook' );
function prowp_uninstall_hook() {
	delete_option( 'prowp_setting_values' );
	//remove any additional options and custom tables
}

 14 Пример создания реального плагина

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

И так приведу пример плагина из книги про вордпресс
This plugin will include the following features:
–Settings page using the Settings API
–Widget for displaying newest products using the Widget class
–Post meta box for adding product metadata
–Shortcode support to easily display product data in a post
–Internationalization support using translation functions

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

Скачать плагин: halloween-store

Код плагина (2 файла) »

halloween-store.php

<?php
/*
Plugin Name: Halloween Store
Plugin URI: http://webdevstudios.com/support/wordpress-plugins/
Description: Create a Halloween Store to display product information
Version: 1.0
Author: Brad Williams
Author URI: http://webdevstudios.com
License: GPLv2
*/

/*  Copyright 2013  Brad Williams  (email : brad@webdevstudios.com)

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

// Call function when plugin is activated
// функция вызывается когда плагин активирован
register_activation_hook( __FILE__, 'halloween_store_install' );

function halloween_store_install() {
	
    //setup default option values
    //устанавливаем по умолчанию опцию в значение $
    $hween_options_arr = array(
        'currency_sign' => '$'
    );

    //save our default option values
    //сохраняем по умолчанию опцию в таблицу опций
    update_option( 'halloween_options', $hween_options_arr );
	
}


// Action hook to initialize the plugin
// Action hook инициализирует плагин
add_action( 'init', 'halloween_store_init' );

//Initialize the Halloween Store
//Инициализация плагина
function halloween_store_init() {

	//register the products custom post type
    //регистрация products пользовательского типа
	$labels = array(
		'name' => __( 'Products', 'halloween-plugin' ),
		'singular_name' => __( 'Product', 'halloween-plugin' ),
		'add_new' => __( 'Add New', 'halloween-plugin' ),
		'add_new_item' => __( 'Add New Product', 'halloween-plugin' ),
		'edit_item' => __( 'Edit Product', 'halloween-plugin' ),
		'new_item' => __( 'New Product', 'halloween-plugin' ),
		'all_items' => __( 'All Products', 'halloween-plugin' ),
		'view_item' => __( 'View Product', 'halloween-plugin' ),
		'search_items' => __( 'Search Products', 'halloween-plugin' ),
		'not_found' =>  __( 'No products found', 'halloween-plugin' ),
		'not_found_in_trash' => __( 'No products found in Trash', 'halloween-plugin' ),
		'menu_name' => __( 'Products', 'halloween-plugin' )
	  );
	
	  $args = array(
		'labels' => $labels,
		'public' => true,
		'publicly_queryable' => true,
		'show_ui' => true, 
		'show_in_menu' => true, 
		'query_var' => true,
		'rewrite' => true,
		'capability_type' => 'post',
		'has_archive' => true, 
		'hierarchical' => false,
		'menu_position' => null,
		'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' )
	  ); 
	  
      // зарегистрировали пользовательский тип
	  register_post_type( 'halloween-products', $args );

}

// Action hook to add the post products menu item
// Action hook добавляет типов products меню пункт
add_action( 'admin_menu', 'halloween_store_menu' );

//create the Halloween Masks sub-menu
//создаем маску для суб-меню, добавляется в настройки
function halloween_store_menu() {
	
    add_options_page( __( 'Halloween Store Settings Page', 'halloween-plugin' ), __( 'Halloween Store Settings', 'halloween-plugin' ), 'manage_options', 'halloween-store-settings', 'halloween_store_settings_page' );
	
}

//build the plugin settings page
//строим плагина настроек страницу
function halloween_store_settings_page() {
	
    //load the plugin options array
    //загружаем плагина опции массив
    $hween_options_arr = get_option( 'halloween_options' );
	
	//set the option array values to variables
    //устанавливаем опции массив значения переменных
	$hs_inventory = ( ! empty( $hween_options_arr['show_inventory'] ) ) ? $hween_options_arr['show_inventory'] : '';
	$hs_currency_sign = $hween_options_arr['currency_sign'];
    //идет отображение формы
    ?>
    <div class="wrap">
    <h2><?php _e( 'Halloween Store Options', 'halloween-plugin' ) ?></h2>

    <form method="post" action="options.php">
        <?php settings_fields( 'halloween-settings-group' ); ?>
        <table class="form-table">
            <tr valign="top">
            <th scope="row"><?php _e( 'Show Product Inventory', 'halloween-plugin' ) ?></th>
            <td><input type="checkbox" name="halloween_options[show_inventory]" <?php echo checked( $hs_inventory, 'on' ); ?> /></td>
            </tr>

            <tr valign="top">
            <th scope="row"><?php _e( 'Currency Sign', 'halloween-plugin' ) ?></th>
            <td><input type="text" name="halloween_options[currency_sign]" value="<?php echo esc_attr( $hs_currency_sign ); ?>" size="1" maxlength="1" /></td>
            </tr>
        </table>

        <p class="submit">
        <input type="submit" class="button-primary" value="<?php _e( 'Save Changes', 'halloween-plugin' ); ?>" />
        </p>

    </form>
    </div>
<?php
}

// Action hook to register the plugin option settings
// хук регистрирует плагина опции настройки
add_action( 'admin_init', 'halloween_store_register_settings' );

function halloween_store_register_settings() {
	
    //register the array of settings
    //регистрируем массив настроек
    register_setting( 'halloween-settings-group', 'halloween_options', 'halloween_sanitize_options' );
	
}

function halloween_sanitize_options( $options ) {
	
	$options['show_inventory'] = ( ! empty( $options['show_inventory'] ) ) ? sanitize_text_field( $options['show_inventory'] ) : '';
	$options['currency_sign'] = ( ! empty( $options['currency_sign'] ) ) ? sanitize_text_field( $options['currency_sign'] ) : '';
	
	return $options;
	
}

//Action hook to register the Products meta box
//хукж регистрирует продукт метабокс
add_action( 'add_meta_boxes', 'halloween_store_register_meta_box' );

function halloween_store_register_meta_box() {
	
    // create our custom meta box 
    // создаем пользовательский метабокс
	add_meta_box( 'halloween-product-meta', __( 'Product Information','halloween-plugin' ), 'halloween_meta_box', 'halloween-products', 'side', 'default' );
	
}

//build product meta box
//строим продук мета бокс
function halloween_meta_box( $post ) {

    // retrieve our custom meta box values
    //получаем значение пользовательских мета бокс данных
    $hween_sku = get_post_meta( $post->ID, '_halloween_product_sku', true );
    $hween_price = get_post_meta( $post->ID, '_halloween_product_price', true );
    $hween_weight = get_post_meta( $post->ID, '_halloween_product_weight', true );
    $hween_color = get_post_meta( $post->ID, '_halloween_product_color', true );
    $hween_inventory = get_post_meta( $post->ID, '_halloween_product_inventory', true );

	//nonce field for security
    //nonce поле для безопасности
	wp_nonce_field( 'meta-box-save', 'halloween-plugin' );
	
    // display meta box form
    // показать мета - бокс форму
    echo '<table>';
    echo '<tr>';
    echo '<td>' .__('Sku', 'halloween-plugin').':</td><td><input type="text" name="halloween_product_sku" value="'.esc_attr( $hween_sku ).'" size="10"></td>';
    echo '</tr><tr>';
    echo '<td>' .__('Price', 'halloween-plugin').':</td><td><input type="text" name="halloween_product_price" value="'.esc_attr( $hween_price ).'" size="5"></td>';
    echo '</tr><tr>';
    echo '<td>' .__('Weight', 'halloween-plugin').':</td><td><input type="text" name="halloween_product_weight" value="'.esc_attr( $hween_weight ).'" size="5"></td>';
    echo '</tr><tr>';
    echo '<td>' .__('Color', 'halloween-plugin').':</td><td><input type="text" name="halloween_product_color" value="'.esc_attr( $hween_color ).'" size="5"></td>';
    echo '</tr><tr>';
    echo '<td>Inventory:</td><td><select name="halloween_product_inventory" id="halloween_product_inventory">
            <option value="In Stock"' .selected( $hween_inventory, 'In Stock', false ). '>' .__( 'In Stock', 'halloween-plugin' ). '</option>
            <option value="Backordered"' .selected( $hween_inventory, 'Backordered', false ). '>' .__( 'Backordered', 'halloween-plugin' ). '</option>
            <option value="Out of Stock"' .selected( $hween_inventory, 'Out of Stock', false ). '>' .__( 'Out of Stock', 'halloween-plugin' ). '</option>
            <option value="Discontinued"' .selected( $hween_inventory, 'Discontinued', false ). '>' .__( 'Discontinued', 'halloween-plugin' ). '</option>
        </select></td>';
    echo '</tr>';

    //display the meta box shortcode legend section
    echo '<tr><td colspan="2"><hr></td></tr>';
    echo '<tr><td colspan="2"><strong>' .__( 'Shortcode Legend', 'halloween-plugin' ).'</strong></td></tr>';
    echo '<tr><td>' .__( 'Sku', 'halloween-plugin' ) .':</td><td>[hs show=sku]</td></tr>';
    echo '<tr><td>' .__( 'Price', 'halloween-plugin' ).':</td><td>[hs show=price]</td></tr>';
    echo '<tr><td>' .__( 'Weight', 'halloween-plugin' ).':</td><td>[hs show=weight]</td></tr>';
    echo '<tr><td>' .__( 'Color', 'halloween-plugin' ).':</td><td>[hs show=color]</td></tr>';
    echo '<tr><td>' .__( 'Inventory', 'halloween-plugin' ).':</td><td>[hs show=inventory]</td></tr>';
    echo '</table>';
}

// Action hook to save the meta box data when the post is saved
//хук для сохранения метабокс данных когда пост сохранен
add_action( 'save_post','halloween_store_save_meta_box' );

//save meta box data
//сохраняем метабокс данные
function halloween_store_save_meta_box( $post_id ) {

	//verify the post type is for Halloween Products and metadata has been posted
    //проверяем пост тип для Hallween Products и метаданые должны быть отправлены
	if ( get_post_type( $post_id ) == 'halloween-products' && isset( $_POST['halloween_product_sku'] ) ) {
		
		//if autosave skip saving data
        //если автосохранение, то пропустить сохранение данных
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) 
			return;

		//check nonce for security
        //проверяем nonce для безопасности
		check_admin_referer( 'meta-box-save', 'halloween-plugin' );

		// save the meta box data as post metadata
        //сохранить мета бокс данные как пост метаданные
		update_post_meta( $post_id, '_halloween_product_sku', sanitize_text_field( $_POST['halloween_product_sku'] ) );
		update_post_meta( $post_id, '_halloween_product_price', sanitize_text_field( $_POST['halloween_product_price'] ) );
		update_post_meta( $post_id, '_halloween_product_weight', sanitize_text_field( $_POST['halloween_product_weight'] ) );
		update_post_meta( $post_id, '_halloween_product_color', sanitize_text_field( $_POST['halloween_product_color'] ) );
		update_post_meta( $post_id, '_halloween_product_inventory',sanitize_text_field( $_POST['halloween_product_inventory'] ) );

	}
	
}

// Action hook to create the products shortcode
//хук создает продуктов шорткод
add_shortcode( 'hs', 'halloween_store_shortcode' );

//create shortcode
//создаем шорткод
function halloween_store_shortcode( $atts, $content = null ) {
    global $post;
	
    extract( shortcode_atts( array(
        "show" => '' //задаем по умолчанию если не создано
    ), $atts ) );

    //load options array
    //загружаем опций массив
    $hween_options_arr = get_option( 'halloween_options' );

    if ( $show == 'sku') {
		
        $hs_show = get_post_meta( $post->ID, '_halloween_product_sku', true );
		
    }elseif ( $show == 'price' ) {
		
        $hs_show = $hween_options_arr['currency_sign']. get_post_meta( $post->ID, '_halloween_product_price', true );
		
    }elseif ( $show == 'weight' ) {
		
        $hs_show = get_post_meta( $post->ID, '_halloween_product_weight', true );
		
    }elseif ( $show == 'color' ) {
		
        $hs_show = get_post_meta( $post->ID, '_halloween_product_color', true );
		
    }elseif ( $show == 'inventory' ) {
		
        $hs_show = get_post_meta( $post->ID, '_halloween_product_inventory', true );
		
    }

	//return the shortcode value to display
    //возвращаем шорткод значение для показа
    return $hs_show;
}

// Action hook to create plugin widget
//создает плагин виджет
add_action( 'widgets_init', 'halloween_store_register_widgets' );

//register the widget
//регистрируем виджет
function halloween_store_register_widgets() {
	
    register_widget( 'hs_widget' );
	
}

//hs_widget class
//виджет класс
class hs_widget extends WP_Widget {

    //process our new widget
    //процесс наш новый виджет
    function hs_widget() {
		
        $widget_ops = array(
			'classname'   => 'hs-widget-class',
			'description' => __( 'Display Halloween Products','halloween-plugin' ) );
        $this->WP_Widget( 'hs_widget', __( 'Products Widget','halloween-plugin'), $widget_ops );
		
    }

    //build our widget settings form
    //строим наш виджет настроект форму
    function form( $instance ) {
		
        $defaults = array( 
			'title'           => __( 'Products', 'halloween-plugin' ), 
			'number_products' => '3' );
		
        $instance = wp_parse_args( (array) $instance, $defaults );
        $title = $instance['title'];
        $number_products = $instance['number_products'];
        ?>
            <p><?php _e('Title', 'halloween-plugin') ?>: 
				<input class="widefat" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" /></p>
            <p><?php _e( 'Number of Products', 'halloween-plugin' ) ?>: 
				<input name="<?php echo $this->get_field_name( 'number_products' ); ?>" type="text" value="<?php echo esc_attr( $number_products ); ?>" size="2" maxlength="2" />
			</p>
        <?php
    }

    //save our widget settings
    //сохраняем нашего виджета настройки
    function update( $new_instance, $old_instance ) {
		
        $instance = $old_instance;
        $instance['title'] = sanitize_text_field( $new_instance['title'] );
        $instance['number_products'] = absint( $new_instance['number_products'] );

        return $instance;
		
    }

    //display our widget
    //показываем наш виджет
    function widget( $args, $instance ) {
        global $post;
		
        extract( $args );

        echo $before_widget;
        $title = apply_filters( 'widget_title', $instance['title'] );
        $number_products = $instance['number_products'];

        if ( ! empty( $title ) ) { echo $before_title . esc_html( $title ) . $after_title; };

		//custom query to retrieve products
        //пользовательский запрос получить продукты
		$args = array(
			'post_type'			=>	'halloween-products',
			'posts_per_page'	=>	absint( $number_products )
		);
		
        $dispProducts = new WP_Query();
        $dispProducts->query( $args );
		
        while ( $dispProducts->have_posts() ) : $dispProducts->the_post();

            //load options array
            //загружаем опций массив
            $hween_options_arr = get_option( 'halloween_options' );

            //load custom meta values
            //загружаем пользовательские мета значения
            $hs_price = get_post_meta( $post->ID, '_halloween_product_price', true );
            $hs_inventory = get_post_meta( $post->ID, '_halloween_product_inventory', true );
            ?>
			<p>
				<a href="<?php the_permalink(); ?>" rel="bookmark" title="<?php the_title_attribute(); ?> Product Information">
				<?php the_title(); ?>
				</a>
			</p>
			<?php
			echo '<p>' .__( 'Price', 'halloween-plugin' ). ': '.$hween_options_arr['currency_sign'] .$hs_price .'</p>';

            //check if Show Inventory option is enabled
            //проверяем если показано инвентарь опция включено
            if ( $hween_options_arr['show_inventory'] ) {
				
				//display the inventory metadata for this product
                //показать метаданные для этого продукта
                echo '<p>' .__( 'Stock', 'halloween-plugin' ). ': ' .$hs_inventory .'</p>';
				
            }
            echo '<hr>';

        endwhile;
		
		wp_reset_postdata();

        echo $after_widget;
    }
}

uninstall.php

<?php
//if uninstall/delete not called from WordPress exit
if( ! defined( 'ABSPATH' ) && ! defined( 'WP_UNINSTALL_PLUGIN' ) )
    exit ();

// Delete options array from options table
delete_option( 'halloween_options' );

 

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

Показать »

simple-add-product-plagin.php

<?php
/*
Plugin Name: simple-add-product-plagin
Plugin URI: http://kselax.ru/
Description: Create a simple store to display product information
Version: 1.0
Author: Hacker Kselax
Author URI: http://kselax.ru
License: GPLv2
*/
 
/*  Copyright 2016  Hacker Kselax  (email : neovich@mail.ua)
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
 
// вызывается когда плагин активируется
register_activation_hook( __FILE__, 'simple_add_store_install' );
 
function simple_add_store_install() {

    //регистрируем новый тип данных
    simple_add_store_init();
    //сброс данных
    flush_rewrite_rules();

    //устанавливаем по умолчанию опцию в значение $
    $hween_options_arr = array(
         'currency_sign' => '$',
         'currency_sign2' => '#'
    );
 
    //сохраняем по умолчанию опцию в таблицу опций
    update_option( 'simple_add_options', $hween_options_arr );
    
}

// == 1. Регистрируем новый продукт ==
// Action hook инициализирует плагин
add_action( 'init', 'simple_add_store_init' );
 
//Инициализация плагина
function simple_add_store_init() {
    //регистрация products пользовательского типа
    $labels = array(
        'name' => __( 'Products', 'simple-add-plugin' ),
        'singular_name' => __( 'Product', 'simple-add-plugin' ),
        'add_new' => __( 'Add New', 'simple-add-plugin' ),
        'add_new_item' => __( 'Add New Product', 'simple-add-plugin' ),
        'edit_item' => __( 'Edit Product', 'simple-add-plugin' ),
        'new_item' => __( 'New Product', 'simple-add-plugin' ),
        'all_items' => __( 'All Products', 'simple-add-plugin' ),
        'view_item' => __( 'View Product', 'simple-add-plugin' ),
        'search_items' => __( 'Search Products', 'simple-add-plugin' ),
        'not_found' =>  __( 'No products found', 'simple-add-plugin' ),
        'not_found_in_trash' => __( 'No products found in Trash', 'simple-add-plugin' ),
        'menu_name' => __( 'Products', 'simple-add-plugin' )
      );
     
      $args = array(
        'labels' => $labels,//принимает массив надписей
        'public' => true,//устанавливает публичный доступ admin or front-end
        'publicly_queryable' => true,//определяет может ли твой контент быть публично доступен из front-end твоего сайта
        'show_ui' => true, //определяет создается ли UI в админ панели (default public argument)
        'show_in_menu' => true, //определяет показывать или нет админ меню для твоего типа
        'query_var' => true,//аргумент устанавливает запрос переменную для постов этого типа
        'rewrite' =>  array('slug' => 'product' ),//создает уникальные постоянные ссылки для этого типа
        'capability_type' => 'post',//аргумент название строка или массив возможностей для этого типа
        'has_archive' => true, //включает типу иметь архив страницу
        'hierarchical' => false, //позволяет определить иерархию
        'menu_position' => null,//устанавливает позицию где показывается пользовательский тип в админ меню
        //title - устанавливает пост title
        //editor - разрешает текстовый редактор
        //thumbnail - добавляет метабокс мениатюры
        //excerpt - показывает цитаты редактор
        'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt' )
      ); 
       
      // зарегистрировали пользовательский тип
      //1 - идентификатор продутка и slug для ссылки
      //2 - массив параметров
      register_post_type( 'simple-add-products', $args );
}

//делаем чтобы products были доступны на главной странице
add_action('pre_get_posts', 'prefix_pre_get_posts');
function prefix_pre_get_posts($query) {
    if($query->is_home()){
          $query->set('post_type', array('simple-add-products','post'));
    }
     return $query;
}
 

// == 2. Создаем страницу настроек для продукта и регистрируем опции ==
// Action hook  меню настроек, пункт в setting
add_action( 'admin_menu', 'simple_add_store_menu' );

//создаем маску для суб-меню, добавляя item в настройки
function simple_add_store_menu() {
    //добавляет пункт в меню setting
    //1 - страницы title
    //2 - отображение пунтка в меню
    //3 - кому видно меню, только администратору
    //4 - уникальный дескриптор
    //5 - callback function
    add_options_page( __( 'Simple Add Store Settings Page', 'simple-add-plugin' ), __( 'Simple Add Store Settings', 'simple-add-plugin' ), 'manage_options', 'simple-add-store-settings', 'simple_add_store_settings_page' );
     
}
 
//строим плагина настроек страницу
function simple_add_store_settings_page() {
    //загружаем плагина опции массив
    $hween_options_arr = get_option( 'simple_add_options' );
     
    //устанавливаем опции из массива значения
    $hs_inventory = ( ! empty( $hween_options_arr['show_inventory'] ) ) ? $hween_options_arr['show_inventory'] : '';
    $hs_currency_sign = $hween_options_arr['currency_sign'];
    $hs_currency_sign2 = $hween_options_arr['currency_sign2'];
    //идет отображение формы
    ?>
    <div class="wrap">
    <h2><?php _e( 'Simple Add Store Options', 'simple-add-plugin' ) ?></h2>
 
    <form method="post" action="options.php">
        <?php 
        //связываем страницу с групой установок
        settings_fields('simple-add-settings-group'); 
        ?>
        <table class="form-table">
            <tr valign="top">
            <th scope="row"><?php _e( 'Show Product Inventory', 'simple-add-plugin' ) ?></th>
            <td><input type="checkbox" name="simple_add_options[show_inventory]" <?php echo checked( $hs_inventory, 'on' ); ?> /></td>
            </tr>
 
            <tr valign="top">
            <th scope="row"><?php _e( 'Currency Sign', 'simple-add-plugin' ) ?></th>
            <td><input type="text" name="simple_add_options[currency_sign]" value="<?php echo esc_attr( $hs_currency_sign ); ?>" size="1" maxlength="1" /></td>
            </tr>

            <tr valign="top">
            <th scope="row"><?php _e( 'Currency Sign2', 'simple-add-plugin' ) ?></th>
            <td><input type="text" name="simple_add_options[currency_sign2]" value="<?php echo esc_attr( $hs_currency_sign2 ); ?>" size="1" maxlength="1" /></td>
            </tr>
        </table>
 
        <p class="submit">
        <input type="submit" class="button-primary" value="<?php _e( 'Save Changes', 'simple-add-plugin' ); ?>" />
        </p>
 
    </form>
    </div>
<?php
}
 
// хук регистрирует плагина опции для страницы
add_action( 'admin_init', 'simple_add_store_register_settings' );
function simple_add_store_register_settings() {
    //регистрируем массив настроек
    //1 - группа идентификатор для связи страницы
    //2 - название опции (в данном случае массив)
    //3 - callback function sanitize
    register_setting( 'simple-add-settings-group', 'simple_add_options', 'simple_add_sanitize_options' );
     
}
//функция sanitize опции страницы настроек плагина
function simple_add_sanitize_options( $options ) {
    $options['show_inventory'] = ( ! empty( $options['show_inventory'] ) ) ? sanitize_text_field( $options['show_inventory'] ) : '';
    $options['currency_sign'] = ( ! empty( $options['currency_sign'] ) ) ? sanitize_text_field( $options['currency_sign'] ) : '';
    $options['currency_sign2'] = ( ! empty( $options['currency_sign2'] ) ) ? sanitize_text_field( $options['currency_sign2'] ) : '';
    return $options;  
}

// == 3. Создаем метабокс ==
//хукж регистрирует продукт метабокс
add_action( 'add_meta_boxes', 'simple_add_store_register_meta_box' );
function simple_add_store_register_meta_box() {
    // создаем пользовательский метабокс
    //1 - id для html
    //2 - title метабокса
    //3 - callback function
    //4 - идентификатор типа поста
    //5 - размещение
    //6 - приоритет
    add_meta_box( 'simple-add-product-meta', __( 'Product Information','simple-add-plugin' ), 'simple_add_meta_box', 'simple-add-products', 'side', 'default' );
}
 
//строим продук мета бокс
function simple_add_meta_box( $post ) {
    //получаем значение пользовательских мета бокс данных для поста
    //1 - id поста
    //2 - ключ мета данных
    //3 - возвращает в виде строки значение
    $hween_sku = get_post_meta( $post->ID, '_simple_add_product_sku', true );
    $hween_price = get_post_meta( $post->ID, '_simple_add_product_price', true );
    $hween_weight = get_post_meta( $post->ID, '_simple_add_product_weight', true );
    $hween_color = get_post_meta( $post->ID, '_simple_add_product_color', true );
    $hween_inventory = get_post_meta( $post->ID, '_simple_add_product_inventory', true );
 
    //nonce поле для безопасности
    //1 - ключ для генерациии
    //2 - имя name
    wp_nonce_field( 'meta-box-save', 'simple-add-plugin' );
     
    // показать мета - бокс форму
    echo '<table>';
    echo '<tr>';
    echo '<td>' .__('Sku', 'simple-add-plugin').':</td><td><input type="text" name="simple_add_product_sku" value="'.esc_attr( $hween_sku ).'" size="10"></td>';
    echo '</tr><tr>';
    echo '<td>' .__('Price', 'simple-add-plugin').':</td><td><input type="text" name="simple_add_product_price" value="'.esc_attr( $hween_price ).'" size="5"></td>';
    echo '</tr><tr>';
    echo '<td>' .__('Weight', 'simple-add-plugin').':</td><td><input type="text" name="simple_add_product_weight" value="'.esc_attr( $hween_weight ).'" size="5"></td>';
    echo '</tr><tr>';
    echo '<td>' .__('Color', 'simple-add-plugin').':</td><td><input type="text" name="simple_add_product_color" value="'.esc_attr( $hween_color ).'" size="5"></td>';
    echo '</tr><tr>';
    echo '<td>Inventory:</td><td><select name="simple_add_product_inventory" id="simple_add_product_inventory">
            <option value="In Stock"' .selected( $hween_inventory, 'In Stock', false ). '>' .__( 'In Stock', 'simple-add-plugin' ). '</option>
            <option value="Backordered"' .selected( $hween_inventory, 'Backordered', false ). '>' .__( 'Backordered', 'simple-add-plugin' ). '</option>
            <option value="Out of Stock"' .selected( $hween_inventory, 'Out of Stock', false ). '>' .__( 'Out of Stock', 'simple-add-plugin' ). '</option>
            <option value="Discontinued"' .selected( $hween_inventory, 'Discontinued', false ). '>' .__( 'Discontinued', 'simple-add-plugin' ). '</option>
        </select></td>';
    echo '</tr>';
 
    //display the meta box shortcode legend section
    //показать метабокс шорткод легенд секцию
    echo '<tr><td colspan="2"><hr></td></tr>';
    echo '<tr><td colspan="2"><strong>' .__( 'Shortcode Legend', 'simple-add-plugin' ).'</strong></td></tr>';
    echo '<tr><td>' .__( 'Sku', 'simple-add-plugin' ) .':</td><td>[hs show=sku]</td></tr>';
    echo '<tr><td>' .__( 'Price', 'simple-add-plugin' ).':</td><td>[hs show=price]</td></tr>';
    echo '<tr><td>' .__( 'Weight', 'simple-add-plugin' ).':</td><td>[hs show=weight]</td></tr>';
    echo '<tr><td>' .__( 'Color', 'simple-add-plugin' ).':</td><td>[hs show=color]</td></tr>';
    echo '<tr><td>' .__( 'Inventory', 'simple-add-plugin' ).':</td><td>[hs show=inventory]</td></tr>';
    echo '</table>';
}
 
//хук для сохранения метабокс данных когда пост сохраняется
add_action( 'save_post','simple_add_store_save_meta_box' );
//сохраняем метабокс данные
function simple_add_store_save_meta_box( $post_id ) {
    //проверяем пост тип для Hallween Products и метаданые должны быть отправлены
    if ( get_post_type( $post_id ) == 'simple-add-products' && isset( $_POST['simple_add_product_sku'] ) ) {
        //если автосохранение, то пропустить сохранение данных
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) 
            return;

        //проверяем nonce для безопасности
        check_admin_referer( 'meta-box-save', 'simple-add-plugin' );

        //сохранить мета бокс данные как пост метаданные
        update_post_meta( $post_id, '_simple_add_product_sku', sanitize_text_field( $_POST['simple_add_product_sku'] ) );
        update_post_meta( $post_id, '_simple_add_product_price', sanitize_text_field( $_POST['simple_add_product_price'] ) );
        update_post_meta( $post_id, '_simple_add_product_weight', sanitize_text_field( $_POST['simple_add_product_weight'] ) );
        update_post_meta( $post_id, '_simple_add_product_color', sanitize_text_field( $_POST['simple_add_product_color'] ) );
        update_post_meta( $post_id, '_simple_add_product_inventory',sanitize_text_field( $_POST['simple_add_product_inventory'] ) );
    }
}

// == 4. Создаем шорткоды продуктов ==

//хук создает продуктов шорткод
add_shortcode( 'hs', 'simple_add_store_shortcode' );
function simple_add_store_shortcode( $atts, $content = null ) {
    global $post;
    //разбиваем асоциативный массив на переменные
    extract( shortcode_atts( array(
        "show" => '' //задаем по умолчанию если не существует
    ), $atts ) );
 
    //загружаем опций массив
    $hween_options_arr = get_option( 'simple_add_options' );
    //проверяем параметры шорткода и отображаем нужные метаданные
    if ($show == 'sku') {
        //возвращает значение метаданных
        //1 - ид записи
        //2 - название метаданого
        //3 - данные возвратить в виде строки
        $hs_show = get_post_meta( $post->ID, '_simple_add_product_sku', true );  
    }elseif ( $show == 'price' ) { 
        $hs_show = $hween_options_arr['currency_sign']. get_post_meta( $post->ID, '_simple_add_product_price', true );
    }elseif ( $show == 'weight' ) {
        $hs_show = get_post_meta( $post->ID, '_simple_add_product_weight', true ); 
    }elseif ( $show == 'color' ) {
        $hs_show = get_post_meta( $post->ID, '_simple_add_product_color', true );  
    }elseif ( $show == 'inventory' ) {
        $hs_show = get_post_meta( $post->ID, '_simple_add_product_inventory', true );    
    }

    //возвращаем шорткод значение для показа
    return $hs_show;
}

// == 5. Создаем плагин виджет ==

//хук создает видежт
add_action( 'widgets_init', 'simple_add_store_register_widgets' );
function simple_add_store_register_widgets() {
    //регисрируем наш класс виджета  
    register_widget( 'hs_widget' );
}
 
//определяем виджет класс
class hs_widget extends WP_Widget {

    //конструктор процесс наш новый виджет
    function hs_widget() {
        //параметры
        //1 - имя класса в который будет обернут виджет
        //2 - описание виджета
        $widget_ops = array(
            'classname'   => 'hs-widget-class',
            'description' => __( 'Display Products','simple-add-plugin' ) );
        //родительский конструктор
        //1 - имя класса создаваемогу
        //2 - название виджета
        //3 - опции с настройками
        $this->WP_Widget( 'hs_widget', __( 'Products Widget','simple-add-plugin'), $widget_ops );
         
    }
 
    //строим наш виджет настроек форму (админка)
    function form( $instance ) {
        //значения по умолчанию
        $defaults = array( 
            'title' => __( 'Products', 'simple-add-plugin' ), 
            'number_products' => '3' );
        //объединяем массивы, параметры первого массива при совпадении
        //заменяют параметры второго массива
        $instance = wp_parse_args( (array) $instance, $defaults );
        $title = $instance['title'];
        $number_products = $instance['number_products'];
        //отображаем сам виджет
        //$this->get_field_name( 'title') и другие это просто член
        //класса родителя для который хранит настройки
        ?>
            <p><?php _e('Title', 'simple-add-plugin') ?>: 
                <input class="widefat" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" /></p>
            <p><?php _e( 'Number of Products', 'simple-add-plugin' ) ?>: 
                <input name="<?php echo $this->get_field_name( 'number_products' ); ?>" type="text" value="<?php echo esc_attr( $number_products ); ?>" size="2" maxlength="2" />
            </p>
        <?php
    }
 
    //сохраняем нашего виджета настройки
    function update( $new_instance, $old_instance ) {
         
        $instance = $old_instance;
        $instance['title'] = sanitize_text_field( $new_instance['title'] );
        //absint - возвращает только положительное целое число
        $instance['number_products'] = absint( $new_instance['number_products'] );
 
        return $instance;
         
    }

    //показываем наш виджет в теме вордпресс (front-end)
    function widget( $args, $instance ) {
        //получаем глобальную переменную
        global $post;
        //разбиваем на переменные асоциативный массив
        extract( $args );
        //вывод переменной что перед виджетом
        echo $before_widget;
        //фильтр который фильтрует title для виджета
        $title = apply_filters( 'widget_title', $instance['title'] );
        $number_products = $instance['number_products'];
        //вывод титла
        if ( ! empty( $title ) ) { echo $before_title . esc_html( $title ) . $after_title; };
 
        //custom query to retrieve products
        //пользовательский запрос получить продукты
        //1 - тип продукта
        //2 - количество записей
        $args = array(
            'post_type'         =>   'simple-add-products',
            'posts_per_page'    =>   absint( $number_products )
        );
        //готовим новый объект
        $dispProducts = new WP_Query();
        $dispProducts->query( $args );//идет запрос
        //вывод в цикле продуктов
        while ( $dispProducts->have_posts() ) : $dispProducts->the_post();
            //загружаем опций массив
            $hween_options_arr = get_option( 'simple_add_options' );
            //загружаем пользовательские мета значения
            //1 - id поста
            //2 - название метаданных
            //3 - возврат в виде строки
            $hs_price = get_post_meta( $post->ID, '_simple_add_product_price', true );
            $hs_inventory = get_post_meta( $post->ID, '_simple_add_product_inventory', true );
            //вывод продукта используя теги вордпресс
            ?>
            <p>
                <a href="<?php the_permalink(); ?>" rel="bookmark" title="<?php the_title_attribute(); ?> Product Information">
                <?php the_title(); ?>
                </a>
            </p>
            <?php
            //вывод цены
            echo '<p>' .__( 'Price', 'simple-add-plugin' ). ': '.$hween_options_arr['currency_sign'] .$hs_price .$hween_options_arr['currency_sign2'] .'</p>';
            //проверяем если показано инвентарь опция включено
            if ( $hween_options_arr['show_inventory'] ) {
                //показать метаданные inventory для этого продукта
                echo '<p>' .__( 'Stock', 'simple-add-plugin' ). ': ' .$hs_inventory .'</p>';  
            }
            echo '<hr>';
 
        endwhile;
        //возвращает глобальную переменную $post в соответствие с текущим постом,
        //нужно каждый раз использовать после произволльного цикла
        wp_reset_postdata();
        //вывод после виджета переменную
        echo $after_widget;
    }
}

uninstall.php

<?php
//if uninstall/delete not called from WordPress exit
if( ! defined( 'ABSPATH' ) && ! defined( 'WP_UNINSTALL_PLUGIN' ) )
    exit ();

// Delete options array from options table
delete_option( 'simple_add_options' );

15 Размещение плагина в плагин директории

Эту тему пока отложим, позже возможно добавлю описание как разместить плагины в хранилищи.

 

 

 

 

 

Комментарии:


Оставить комментарий

Your email address will not be published. Required fields are marked *