В этой статье я поделись классом Kama Post Meta Box, с помощью которого можно быстро создавать метаполя для записей, просто указав их в виде массива. Получается своего рода конструктор. К тому же, этот вариант автоматически очищает данные при сохранении и в некоторых случаях может защитить от взлома сайта.
Статью на эту тему я уже писал: «Блок произвольных полей в админке WordPress своими руками». Правда было это давно, но статья по-прежнему актуальна и может пригодится, когда нужно создать произвольные поля для записи, без использования плагинов. Однако в том варианте все нужно делать вручную, включая создание html каждого поля формы — это не удобно. Также, тот вариант требует определенных знаний: умение работать с хуками и т.д.
Покажу на примере, как легко можно создать произвольные поля для записей. Допустим, нам нужно создать 4 SEO поля: title, description, keywords и robots для всех типов записей. Для создания метабокса нужно вызвать класс Kama_Post_Meta_Box с передачей ему параметров:
Прежде чем переходить к остальным примерам, рассмотрим все параметры, которые понимает класс:
new Kama_Post_Meta_Box( array(
'id' => '', // динетификатор блока. Используется как префикс для названия метаполя.
// начните идент. с '_': '_foo', чтобы ID не был префиксом в названии метаполей.
'title' => '', // заголовок блока
'desc' => '', // описание для метабокса. Можно указать функцию/замыкание, она получит $post. С версии 1.9.1
'post_type' => '', // строка/массив. Типы записей для которых добавляется блок: array('post','page').
// По умолчанию: '' - для всех типов записей.
'post_type_feature' => '', // строка. возможность которая должна быть у типа записи,
// чтобы метабокс отобразился. См. post_type_supports()
'post_type_options' => '', // массив. опции типа записи, которые должны быть у типа записи чтобы метабокс отобразился.
// см. первый параметр get_post_types()
'priority' => 'high', // Приоритет блока для показа выше или ниже остальных блоков ('high' или 'low').
'context' => 'normal', // Место где должен показываться блок ('normal', 'advanced' или 'side').
'disable_func' => '', // функция отключения метабокса во время вызова самого метабокса.
// Если вернет что-либо кроме false/null/0/array(), то метабокс будет отключен. Передает объект поста.
'cap' => '', // название права пользователя, чтобы показывать метабокс.
'save_sanitize' => '', // Функция очистки сохраняемых в БД полей. Получает 2 параметра: $metas - все поля для очистки и $post_id
'theme' => 'table', // тема оформления: 'table', 'line'.
// ИЛИ массив паттернов полей: css, fields_wrap, field_wrap, title_patt, field_patt, desc_patt.
// Массив указывается так: [ 'desc_patt' => '<div>%s</div>' ] (за овнову будет взята тема line)
// Массив указывается так: [ 'table' => [ 'desc_patt' => '<div>%s</div>' ] ] (за овнову будет взята тема table)
// ИЛИ изменить тему можно через фильтр 'kp_metabox_theme' - удобен для общего изменения темы для всех метабоксов.
// Массив метаполей, которые будут выводиться
'fields' => array(
// Каждое поле указывается в виде массива, где ключ - это название метаполя, а значение - это массив данных о поле
// реальное название метаполя будет выглядеть как: {id}_{meta_key}
'meta_key' => array(
'type' => '', // тип поля: textarea, select, checkbox, radio, image, wp_editor, hidden, sep_*.
// Или базовые: text, email, number, url, tel, color, password, date, month, week, range.
// 'sep' - визуальный разделитель, для него нужно указать `title` и можно указать `'attr'=>'style="свои стили"'`.
// 'sep' - чтобы удобнее указывать тип 'sep' начните ключ поля с `sep_`: 'sep_1' => [ 'title'=>'Разделитель' ].
// Для типа `image` можно указать тип сохраняемого значения в `options`: 'options'=>'url'. По умолчанию тип = id.
// По умолчанию 'text'.
'title' => '', // заголовок метаполя
'desc' => '', // описание для поля. Можно указать функцию/замыкание, она получит параметры: $post, $meta_key, $val, $name.
'placeholder' => '', // атрибут placeholder
'id' => '', // атрибут id. По умолчанию: $this->opt->id .'_'. $key
'class' => '', // атрибут class: добавляется в input, textarea, select. Для checkbox, radio в оборачивающий label
'attr' => '', // любая строка, будет расположена внутри тега. Для создания атрибутов. Пр: style="width:100%;"
'val' => '', // значение по умолчанию, если нет сохраненного.
'options' => '', // массив: array('значение'=>'название') - варианты для типов 'select', 'radio'.
// Для 'wp_editor' стенет аргументами.
// Для 'checkbox' станет значением атрибута value: <input type="checkbox" value="{options}">.
// Для 'image' определяет тип сохраняемого в метаполе значения: id (ID вложения), url (url вложения).
'callback' => '', // название функции, которая отвечает за вывод поля.
// если указана, то ни один параметр не учитывается и за вывод полностью отвечает указанная функция.
// Все параметры передаются ей... Получит параметры: $args, $post, $name, $val
'sanitize_func' => '', // функция очистки данных при сохранении - название функции или Closure.
// Укажите 'none', чтобы не очищать данные...
// работает, только если не установлен глобальный параметр 'save_sanitize'...
// получит параметр $value - сохраняемое значение поля.
'output_func' => '', // функция обработки значения, перед выводом в поле.
// получит параметры: $post, $meta_key, $value - объект записи, ключ, значение метаполей.
'update_func' => '', // функция сохранения значения в метаполя.
// получит параметры: $post, $meta_key, $value - объект записи, ключ, значение метаполей.
'disable_func' => '', // функция отключения поля.
// Если не false/null/0/array() - что-либо вернет, то поле не будет выведено.
// Получает парамтры: $post, $meta_key
'cap' => '', // название права пользователя, чтобы видеть и изменять поле.
),
'meta_key2' => array( /*...*/ ),
'meta_key3' => array( /*...*/ ),
// ...
),
) );
Создаваемые произвольные поля будут иметь название/ключ, состоящий из объединения основного ID и указанного ключа метаполя: {id}_{meta_key} (смотрите пример ниже).
Самый просто способ узнать название произвольного поля — это посмотреть в исходный код. Для этого фокусируемся на нужном поле, кликаем правой кнопкой и смотрим значение атрибута name в исходном коде элемента:
Получение произвольных полей
Получать созданные поля для использования в темах и плагинах нужно стандартной функцией WordPress: get_post_meta():
// получим значение поля 'my_meta_key' у записи 25
$my_filed = get_post_meta( 25, 'my_meta_key', 1 );
echo $my_filed;
Права
Блок/метабокс будет показан только пользователям, у которых есть право редактировать текущую запись.
Сохранение метаполей будет работать только для пользователей, которые могут редактировать текущую запись.
Этот пример показывает как создавать все поддерживаемые типы метаполей: 'text', 'textarea', 'select', 'checkbox', 'radio', 'wp_editor', 'hidden' и другие: 'email', 'number', 'phone', 'password' и т.д. (обрабатываются как поле 'text').
class_exists('Kama_Post_Meta_Box') && new Kama_Post_Meta_Box(
array(
'id' => 'my',
'title' => 'Мои произвольные поля',
'fields' => array(
'text_field' => array(
'title' => 'Текстовое поле'
),
'number_field' => array(
'type'=>'number', 'title'=>'Числовое поле', 'desc'=>'Число от 0 до 5', 'attr'=>'min="0" max="5"'
),
'textarea_field' => array(
'type'=>'textarea', 'title'=>'Большое текстовое поле', 'desc'=>'Описание чего-либо. Можно использовать html теги.'
),
'select_field' => array(
'type'=>'select', 'title'=>'Выберите значение', 'options'=>array(''=>'Ничего не выбрано', 'val_1'=>'Выбор 1', 'val_2'=>'Выбор 2')
),
'select_field2' => array(
'type'=>'select', 'title'=>'Выберите значение 2', 'options'=>array('Выбор 1', 'Выбор 2'), 'desc'=>'Выбор, где не указывается значение value для тегов option'
),
'checkbox_field' => array(
'type'=>'checkbox', 'title'=>'Галочка', 'desc'=>'отметьте, если хотите :)'
),
'checkbox_field2' => array(
'type'=>'checkbox', 'desc'=>'< только описание для галочки, без заголовка'
),
'radio_field' => array(
'type'=>'radio', 'title'=>'Переключатель', 'desc'=>'Выберите одно из значений', 'options'=>array(''=>'Ничего не выбрано', 'good'=>'хорошо', 'bad'=>'плохо')
),
'radio_field2' => array(
'type'=>'radio', 'desc'=>'Переключатель без заголовка', 'options'=>array(''=>'Не выбрано', 'good'=>'хорошо', 'bad'=>'плохо')
),
'wp_editor_field' => array(
'type'=>'wp_editor', 'title'=>'Текстовое поле с редактором TinyMce'
),
'wp_editor_field2' => array(
'type'=>'wp_editor', 'title'=>'Текстовое поле с редактором WordPress, без TinyMce', 'options'=>array('tinymce'=>0) // список настроек: http://wp-kama.ru/function/wp_editor
),
'hidden_field' => array(
'type'=>'hidden', 'val'=>'foo'
),
'' => array('type'=>'text', 'title'=>''), // заготовка
),
)
);
В результате, появиться такой метаблок на странице редактирования любого типа записи.
А при сохранении будут созданы, такие произвольные поля:
Когда нужно создать метабокс с метаполями только для указанных типов записи, укажите параметр 'post_type' => array('post','page') в котором перечислите нужные типы записей.
class_exists('Kama_Post_Meta_Box') && new Kama_Post_Meta_Box(
array(
'id' => 'my',
'title' => 'Мои произвольные поля',
'post_type' => array('page', 'my_type'), // показывать только на страницах типа: page и my_type
'fields' => array(
'text_field' => array( 'title' => 'Текстовое поле' ),
),
)
);
#3 Своя функция вывода поля
Когда возможностей класса не достаточно и нужно создать поле, которое будет иметь какой-то особенный вывод, используйте параметр callback для создаваемого поля.
В этом случае можно настроить вывод поля как угодно. Для примера давайте создадим несколько полей, которые будут храниться в поле special_field в виде массива.
Когда нужно, чтобы названия метаполей были точно такие же какие вы указали, добавьте в начало id нижнее подчеркивание _.
Это может понадобится, если у вас уже есть метаполя и вам нужно подстроиться под их названия. В этом случае префикс, который добавляется для названия каждого метаполя будет лишний.
Например, у вас уже есть метаполя: foo, bar, views, title и для них нужно создать метабокс:
class_exists('Kama_Post_Meta_Box') && new Kama_Post_Meta_Box(
array(
'id' => '_my', // "_" - значит, что id не будет добавляться в название поля
'title' => 'Мои точные произвольные поля',
'fields' => array(
'foo' => array( 'title' => 'Поле foo' ),
'bar' => array( 'title' => 'Поле bar' ),
'views' => array( 'title' => 'Поле views' ),
'title' => array( 'title' => 'Поле title' ),
),
)
);
Класс автоматически очищает все поля и защищает от XSS атак. Но иногда может быть нужно, очистить определенное поле как-то особенно. В этом случае укажите навзание функции очистки в параметре 'save_sanitize' или используйте фильтр "kpmb_save_sanitize_{id}". Если указана функция или хук очистки, то класс никак не очищает сохраняемые данные, очистка всех полей должна быть в вашей функции очистки.
Допустим, мы создаем поле в котором все символы должны быть прописными, а если они указаны как строчные, то автоматом преобразуем их в прописные и сохраним:
class_exists('Kama_Post_Meta_Box') && new Kama_Post_Meta_Box(
array(
'id' => 'my',
'title' => 'Мои произвольные поля',
'save_sanitize' => 'my_metabox_sanitize_function',
'fields' => array(
'foo_field' => array( 'title'=>'Некое поле' ),
'for_esc' => array( 'title'=>'Специальное поле', 'desc'=>'Поле которое должно содержать только прописные символы.' ),
),
)
);
// функция очистки всех полей
function my_metabox_sanitize_function( $metas, $post_id ){
/*
$metas = сохраняемые поля в массиве
$post = ID записи
*/
// очищаем нужное поле
foreach( $metas as $key => & $val ){
// наше поле
if( $key == 'my_for_esc' )
$val = mb_strtoupper( $val );
// все остальные поля
else
$val = sanitize_text_field( $val );
}
return $metas;
}
В результате получим:
Еще один пример функции очистки
Такой подход используется в классе, если не указать функцию очистки. Он очищает с помощью wp_kses() и обрабатывает массив и все вложенные массивы.
#6 Темы оформления: настройка html и css каждого поля
Можно указать как должны выводиться поля в метабоксе. Для этого есть параметр theme - тема оформления.
В этом параметре можно указать строку или массив:
table (по умолчанию) - поля будут выведены в табличной форме.
line - поля будут выведены линиями. Во всю ширину метабокса, где идет заголовок поля, а под ним само поле.
array() - указывая массив, вы можете сами определить все виды оборачивающих тегов для каждого элемента поля. В массиве можно указать следующие параметры:
Класс позволяет создавать два и более разных блока с одинаковыми id. Следующий пример создаст 2 разных блока метаполя которых будут иметь одинаковый префикс: my_:
Иногда нужно включить метабокс для одной рубрики, но не включать для другой. Для таких "поздних" проверок отключения метабокса, есть параметр: disable_func.
В этот параметр нужно передать название функции, которая будет срабатывать перед выводом метабокса и отключать его, если срабатывает описанное в функции условие. Также, вместо названия функции, можно передать анонимную функцию (замыкание). Далее, если указанная функция, что-нибудь возвращает, то метабокс будет отключен.
#2. Метабокс записи для всех рубрик кроме указанной
Теперь обратный пример: допустим нужно показывать метабокс, когда запись находится в любой категории, кроме категории 2, т.е. для категории 2 его нужно отключить.
new Kama_Post_Meta_Box( array(
'id' => 'mybox',
'title' => 'Виден для всех рубрик, кроме 2',
'post_type' => 'post',
'disable_func' => function($post){
if( in_category(2, $post) ) return 'отключить';
},
'fields' => array(
'fname' => array( 'type'=>'text', 'title'=>'Поле-поле' ),
),
) );
Проверка может быть любой необязательно категории, это могут быть таксономии или произвольные поля или что-то еще.