Блок произвольных полей в админке WordPress своими руками
Чтобы не создавать произвольные поля полностью в ручную, можно использовать мой PHP класс для удобно создания метаполей записи.
Чтобы вывести подобный блок для элементов таксономий, смотрите описание события: (taxonomy)_edit_form_fields. Также смотрите ответ на вопрос: Метаполя для рубрик (таксономий) в WordPress
Вводная часть
Прежде чем погружаться в создание метабокса произвольных полей, следует отметить, что WordPress — платформа которая, пожалуй, как никакая другая поддается расширению с наименьшими усилиями. В частности, именно поэтому под WordPress написано так много плагинов — все очень просто, нужно лишь знать азы PHP и понимать принцип работы системы.
Каждый, кто достаточно близко знаком с WordPress неоднократно встречался с понятием «произвольные поля» и с их помощью решал некоторые нетривиальные задачи.
Произвольные поля в WordPress — очень удобный инструмент, когда нужно «прикрепить» к конкретному посту какие-либо дополнительные данные. Такими данными может быть что угодно, начиная от логических true/false (1/0), заканчивая объемными текстами, массивами и прочим.
К примеру, мы можем создать новое произвольное поле Title
и в его значение написать текст (альтернативный заголовок поста), затем в коде шаблона использовать следующий код, чтобы вывести этот текст:
<h1><?php echo get_post_meta( $post_id, 'title', true ); ?></h1>
Функцию get_post_meta() можно использовать где угодно в шаблоне или плагине, т.е. за пределами Цикла WordPress.
Другой пример: используя произвольные поля мы можем выполнять или не выполнять действия, в зависимости от значения мета-поля. Например, размещая в произвольное поле логические цифры 1
или 0
мы можем выводить или не выводить какую-либо информацию для текущего поста.
Произвольные поля используются в WordPress сплошь и рядом, различными плагинами оценки постов (WP-PostRatings), SEO плагинами (Platinum SEO Pack), позволяющими указать Title, Description, Keywords поста, моим плагином для создания миниатюр (Kama Thumbnail) и многими другими плагинами. Можно сказать, что каждая вторая нестандартная задача связанная с постами решается через мета-поля (произвольные поля)!
Поэтому если вы еще не умеете ими пользоваться, то самое время научиться! Ниже мы поговорим о том, как создать отдельный блок с нужными нам произвольными полями и как сделать это без плагинов.
Прежде чем начать создание
В WordPress есть дефолтный блок произвольных полей. Но он часто не подходит, потому что там для добавления поля нужно вписывать ключ и значение, и нет никакого поясняющего описания для чего нужно конкретное поле.
Гораздо удобнее иметь блок, куда можно вписывать только значения, и где каждое поле будет иметь осмысленное название и описание. Блок, который мы сейчас создадим будет выглядеть так:
Заметка: Если создать произвольное поле ключ которого начинается на _
(нижнее подчеркивание), например _my_special_key
, то такое поле будет считаться "внутренним" и не будет выводиться в выпадающем списке произвольных полей в админке. Создать такое поле можно только запросом к БД, например, используя функции add_post_meta() или update_post_meta().
Создаем мета блок произвольных полей
Для создания мета-блока нам понадобятся:
- хук add_meta_boxes.
- хук save_post.
- функция add_meta_box().
- Немного знаний HTML и PHP.
Добавляем следующий код в файл темы functions.php или в плагин:
#1. Создадим новый мета блок для постов
Назовем его "Дополнительные поля":
// подключаем функцию активации мета блока (my_extra_fields) add_action( 'add_meta_boxes', 'my_extra_fields_meta_box', 1 ); function my_extra_fields_meta_box() { $post_type = 'post'; add_meta_box( 'extra_fields', 'Дополнительные поля', 'extra_fields_box_func', $post_type, 'normal', 'high' ); }
#2. Заполним этот блок полями html формы
Для этого создадим функцию-коллбэк extra_fields_box_func
, название которой мы указали в параметре add_meta_box(). Именно она отвечает за содержание мета блока:
<?php // код блока function extra_fields_box_func( $post ) { ?> <p> Заголовок страницы (title): <label> <input type="text" name="extra[title]" value="<?= get_post_meta( $post->ID, 'title', 1 ) ?>" style="width:50%"/> </label> </p> <p> Описание статьи (description): <textarea type="text" name="extra[description]" style="width:100%;height:50px;"><?= get_post_meta( $post->ID, 'description', 1 ) ?></textarea> </p> <p> Видимость поста: <?php $mark_v = get_post_meta( $post->ID, 'robotmeta', true ) ?> <label><input type="radio" name="extra[robotmeta]" value="" <?php checked( $mark_v, '' ) ?> /> index,follow</label> <label><input type="radio" name="extra[robotmeta]" value="nofollow" <?php checked( $mark_v, 'nofollow' ) ?> /> nofollow</label> <label><input type="radio" name="extra[robotmeta]" value="noindex" <?php checked( $mark_v, 'noindex' ) ?> /> noindex</label> <label><input type="radio" name="extra[robotmeta]" value="noindex,nofollow" <?php checked( $mark_v, 'noindex,nofollow' ) ?> /> noindex,nofollow</label> </p> <p> Выберите значение: <select name="extra[select]"> <?php $sel_v = get_post_meta( $post->ID, 'select', true ) ?> <option value="0">---</option> <option value="1" <?php selected( $sel_v, '1' ) ?> >Выбери меня</option> <option value="2" <?php selected( $sel_v, '2' ) ?> >Нет, меня</option> <option value="3" <?php selected( $sel_v, '3' ) ?> >Лучше меня</option> </select> </p> <input type="hidden" name="extra_fields_nonce" value="<?= wp_create_nonce( 'extra_fields_nonce_id' ) ?>"/> <?php }
Все названия полей я оформил в массив extra[]
, чтобы потом проще было обработать эти данные.
Скрытое Поле name="extra_fields_nonce"
, нужно для защиты при сохранении данных.
#3. Сохраняем данные
Мы уже создали блок произвольных полей, теперь нужно обработать данные при сохранении поста. Обработать, значит записать их в в базу данных или удалить от туда. Для этого используем хук save_post, который срабатывает в момент сохранения поста. В этот момент мы получим данные из массива extra[]
и обработаем них:
// обновление полей при сохранении add_action( 'save_post', 'my_extra_fields_save_on_update', 0 ); function my_extra_fields_save_on_update( $post_id ) { // базовая проверка if( empty( $_POST['extra'] ) || ! wp_verify_nonce( $_POST['extra_fields_nonce'], 'extra_fields_nonce_id' ) || wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ){ return false; } $extra = $_POST['extra']; // Все ОК! Теперь, нужно сохранить/удалить данные // Очищаем все данные $extra = array_map( 'sanitize_text_field', $extra ); foreach( $extra as $key => $value ){ // удаляем поле если значение пустое if( ! $value ){ delete_post_meta( $post_id, $key ); } else { update_post_meta( $post_id, $key, $value ); // add_post_meta() работает автоматически } } return $post_id; }
Вот и все! блок произвольных полей готов!
Блок произвольных полей для произвольного типа записей
Если нужно создать блок для другого типа записи, допустим page
(для страниц), то регистрируем еще один мета блок и описываем его html код в новой функции, которую так же нужно указать при регистрации блока (extra_fields_box_page_func
).
Функцию обработки полей при сохранении поста создавать уже не надо, главное указать названия полей в виде массивов extra[]
:
function my_extra_fields() { add_meta_box( 'extra_fields', 'Дополнительные поля', 'extra_fields_box_func', 'post', 'normal', 'high' ); add_meta_box( 'extra_fields', 'Дополнительные поля', 'extra_fields_box_page_func', 'page', 'normal', 'high' ); } // html код блока для типа записей page function extra_fields_box_page_func() { ?> <!-- Здесь поля html формы --> <?php }
Сложности с типом checkbox
Недостатком такого метода является то, что массив extra[]
, обязательно должен быть определен, пусть даже он передает пустое значение иначе поле не будет обработано при сохранении данных.
В связи с этим, возникает проблема при использовании типа checkbox
: <input type="checkbox"
, потому что checkbox передает данные только, если галочка выставлена и вообще ничего не передает, если галки нет. А нам нужно, чтобы он передавал пустое значение, чтобы код удалял значение, если оно было сохранено до этого.
Чтобы обойти этот "недуг" я сделал так: перед полем чекбокс создаем hidden поле с name атрибутом, таким же как у чекбокса и пустым значением. В результате получается, если галочка есть, то значение hidden поля перебивается, если галки нет, то берется пустое значение hidden поля.
Т.е. checkbox нужно вызывать так:
<input type="hidden" name="extra[my_checkbox]" value="" /> <input type="checkbox" name="extra[my_checkbox]" value="1" />
Такой же трюк иногда может пригодится и для поля с типом radio.
Создание метабокса используя PHP класс
Этот пример показывает как создать одно поле, в котором будет храниться массив данных. Массив можно расширять или уменьшать через нажатие на + или удалить (работает на скрипте).
Это пример создание поля "повторитель", как у плагина ACF (поле repeater в платной версии).
В результате получим такой метабокс:
GitHubПлагины для создания блоков произвольных полей
-
Advanced Custom Fields (ACF) — самый популярный и гибкий плагин для создания произвольных полей. С хорошей документацией.
-
Custom Field Suite — похож на ACF, только менее навороченный.
-
CMB2 — CMB2 инструмент для разработчиков для создания: метабоксов, метаполей. Позволяет легко управлять записями, элементами таксономий, пользователями, комментариями или создавать произвольные страницы настроек.
- Custom Field Template — настоящий комбайн. С ним можно создать любую форму, для любых типов постов, указать формы для отдельных постов и рубрик. Думаю в большинстве случаев, можно обойтись без такого комбайна.
Заключение
Простота в настройке блока произвольных полей при создании его таким способом теряется! Я ни в коем случае не хочу сказать, что создавать блоки таким способом лучше чем использовать плагины. Однако, такой подход более гибок, потому что мы можем создать абсолютно любые поля и расположить/стилизовать их как нам вздумается.
К тому же, обычно нет нужды создавать по несколько таких блоков и часто их редактировать, как это можно делать используя плагины. К примеру, на этом сайте я использую такой подход и совсем небольшой код в functions.php избавляет меня от необходимости использовать очередной плагин.
Это скорее обучающая статья и для многих плагины реализующие эту задачу будут более подходящим решением.