Вы уже наверняка сталкивались с настраиваемыми полями в WordPress. Они используются для добавления дополнительных данных на страницах и в постах. Вложения к постам тоже сохраняются как отдельные настраиваемые поля. Сегодня мы с вами разберемся, как добавить настраиваемые поля так, чтобы медиа-вложения содержали дополнительные данные, а не только те, которые доступны по умолчанию.
| Скачать исходники |
Что конкретно мы сделаем
Для начала мы напишем плагин, чтобы управлять вложениями и привязанными к ним полями. В плагине будет набор настроек, которые надо будет связать воедино и сохранить в БД сайта. Для этого используем:
- attachment_fields_to_edit — для управления формой редактирования
- attachment_fields_to_save — для сохранения настраиваемых полей
1. Создание плагина
В этой части ничего особо разбирать не будем. Здесь достаточно просто создать новую папку в папке с плагинами wp-content/plugins/media-fields и добавить в нее файл под названием plugin.php. Еще надо добавить файл custom_media_fields.php, в котором и будут все наши настройки. Вот как изначально должен выглядеть ваш файл plugin.php:
/*
Plugin Name: Wptuts+ Custom Media Fields
Plugin URI:
Description: Create attachments custom fields
Version: 0.1
Author: Guillaume Voisin
Author URI: http://wp.tutsplus.com/author/guillaumevoisin
License: GPL2
*/
require_once( plugin_dir_path( __FILE__ ) . '/custom_media_fields.php' );
Class Wptuts_Custom_Media_Fields {
private $media_fields = array();
function __construct( $fields ) {
}
public function applyFilter( $form_fields, $post = null ) {
}
function saveFields( $post, $attachment ) {
}
}
$cmf = new Wptuts_Custom_Media_Fields( $attchments_options );Вот это и будет нашей основой для дальнейшей работы. А теперь перейдем к опциям.
2. Определяем параметры
В другом файле пропишем параметры для вложений. В этом пошаговом руководстве рассмотрим опции для вложенных изображений и улучшения работы с ними. К примеру, добавим к нашим фотографиям и картинкам копирайт, описание, водяной знак, рейтинг и другие поля:
$themename = "twentytwelve";
$attchments_options = array(
'image_copyright' => array(
'label' => __( 'Image copyright', $themename ),
'input' => 'text',
'helps' => __( 'If your image is protected by copyrights', $themename ),
'application' => 'image',
'exclusions' => array( 'audio', 'video' ),
'required' => true,
'error_text' => __( 'Copyright field required', $themename )
),
'image_author_desc' => array(
'label' => __( 'Image author description', $themename ),
'input' => 'textarea',
'application' => 'image',
'exclusions' => array( 'audio', 'video' ),
),
'image_watermark' => array(
'label' => __( 'Image watermark', $themename ),
'input' => 'checkbox',
'application' => 'image',
'exclusions' => array( 'audio', 'video' )
),
'image_stars' => array(
'label' => __( 'Image rating', $themename ),
'input' => 'radio',
'options' => array(
'0' => 0,
'1' => 1,
'2' => 2,
'3' => 3,
'4' => 4
),
'application' => 'image',
'exclusions' => array( 'audio', 'video' )
),
'image_disposition' => array(
'label' => __( 'Image disposition', $themename ),
'input' => 'select',
'options' => array(
'portrait' => __( 'portrtait', $themename ),
'landscape' => __( 'landscape', $themename )
),
'application' => 'image',
'exclusions' => array( 'audio', 'video' )
)
);В связанном массиве будут следующие параметры:
- label — отображает имя поля
- input — тип вводимых данных
- helps — подсказка в помощь пользователю при заполнении полей
- application — применяемый тип MIME для вложения
- exclusions — что исключить из вложений
- required — является ли это поле обязательным? (значение по умолчанию — false)
- error_text — опциональное поле для описания ошибки
- options — для выбора переключений между radio и select
- show_in_modal — показывать ли поле в модальном формате или нет (по умолчанию — true)
- show_in_edit — показывать ли классический формат редактора для полей (по умолчанию — true)
- extra_rows — дополнительные строки для отображения контента
- tr — дополнительные строки с тегом "tr"
Выделенные опции — это те, которые надо будет настроить вручную, а остальные уже заполнены по умолчанию в WordPress и будут обрабатываться автоматически. Поскольку дело мы имеем с изображениями, то параметру application надо присвоить значение "image". Так будут обрабатываться все виды изображений, в которых тип данных совпадает с image/jpeg, image/png и аналогичными. Можно исключить gif, заполнив поле исключений.
Разобрались с опциями — самое время переходить к более тонкой настройке кода.
3. Немного кода
У нас 2 настраиваемые функции, которые включены в состав конструктора:
function __construct( $fields ) {
$this->media_fields = $fields;
add_filter( 'attachment_fields_to_edit', array( $this, 'applyFilter' ), 11, 2 );
add_filter( 'attachment_fields_to_save', array( $this, 'saveFields' ), 11, 2 );
}Рассмотрим подробнее.
attachment_fields_to_edit
Здесь есть 2 параметра:
- $form_fields — массив полей в форме с редактированием вложений
- $post — объект самого вложения
Для объединения наших собственных полей будем использовать $form_fields для проверки каждого из них на соблюдение параметров и требований ко вложениям.
public function applyFilter( $form_fields, $post = null ) {
// If our fields array is not empty
if ( ! empty( $this->media_fields ) ) {
// We browse our set of options
foreach ( $this->media_fields as $field => $values ) {
// If the field matches the current attachment mime type
// and is not one of the exclusions
if ( preg_match( "/" . $values['application'] . "/", $post->post_mime_type) && ! in_array( $post->post_mime_type, $values['exclusions'] ) ) {
// We get the already saved field meta value
$meta = get_post_meta( $post->ID, '_' . $field, true );
// Define the input type to 'text' by default
$values['input'] = 'text';
// And set it to the field before building it
$values['value'] = $meta;
// We add our field into the $form_fields array
$form_fields[$field] = $values;
}
}
}
// We return the completed $form_fields array
return $form_fields;
}На этом шаге надо улучшить форму редактирования вложений путем добавления наших настраиваемых полей. Нужно учесть, что вложения могут быть разных типов и вывод тоже разный (переключатели, выбор из заранее заданных вариантов, отметка "галочкой" и т.д.)
Приступим к редактированию. Начнем с замены $values['input'] = 'text'; следующим кодом:
switch ( $values['input'] ) {
default:
case 'text':
$values['input'] = 'text';
break;
case 'textarea':
$values['input'] = 'textarea';
break;
case 'select':
// Select type doesn't exist, so we will create the html manually
// For this, we have to set the input type to 'html'
$values['input'] = 'html';
// Create the select element with the right name (matches the one that WordPress creates for custom fields)
$html = '<select name="attachments[' . $post->ID . '][' . $field . ']">';
// If options array is passed
if ( isset( $values['options'] ) ) {
// Browse and add the options
foreach ( $values['options'] as $k => $v ) {
// Set the option selected or not
if ( $meta == $k )
$selected = ' selected="selected"';
else
$selected = '';
$html .= '<option' . $selected . ' value="' . $k . '">' . $v . '</option>';
}
}
$html .= '</select>';
// Set the html content
$values['html'] = $html;
break;
case 'checkbox':
// Checkbox type doesn't exist either
$values['input'] = 'html';
// Set the checkbox checked or not
if ( $meta == 'on' )
$checked = ' checked="checked"';
else
$checked = '';
$html = '<input' . $checked . ' type="checkbox" name="attachments[' . $post->ID . '][' . $field . ']" id="attachments-' . $post->ID . '-' . $field . '" />';
$values['html'] = $html;
break;
case 'radio':
// radio type doesn't exist either
$values['input'] = 'html';
$html = '';
if ( ! empty( $values['options'] ) ) {
$i = 0;
foreach ( $values['options'] as $k => $v ) {
if ( $meta == $k )
$checked = ' checked="checked"';
else
$checked = '';
$html .= '<input' . $checked . ' value="' . $k . '" type="radio" name="attachments[' . $post->ID . '][' . $field . ']" id="' . sanitize_key( $field . '_' . $post->ID . '_' . $i ) . '" /> <label for="' . sanitize_key( $field . '_' . $post->ID . '_' . $i ) . '">' . $v . '</label><br />';
$i++;
}
}
$values['html'] = $html;
break;
}Теперь можно создавать и более общие элементы HTML. Проверим, как выглядит наша форма редактирования вложений. Должно получиться что-то наподобие:

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

Теперь наши поля отображаются в форме редактирования для вложений, и мы можем их сохранить в БД. Для этой цели нам и нужна вторая функция:
attachment_fields_to_save
Она включает 2 параметра:
- $post — массив для идентификации вложения
- $attachment — все поля, связанные со вложением в данном посте
Теперь заполним функцию saveFields из предыдущей секции.
function saveFields( $post, $attachment ) {
// If our fields array is not empty
if ( ! empty( $this->media_fields ) ) {
// Browser those fields
foreach ( $this->media_fields as $field => $values ) {
// If this field has been submitted (is present in the $attachment variable)
if ( isset( $attachment[$field] ) ) {
// If submitted field is empty
// We add errors to the post object with the "error_text" parameter we set in the options
if ( strlen( trim( $attachment[$field] ) ) == 0 )
$post['errors'][$field]['errors'][] = __( $values['error_text'] );
// Otherwise we update the custom field
else
update_post_meta( $post['ID'], '_' . $field, $attachment[$field] );
}
// Otherwise, we delete it if it already existed
else {
delete_post_meta( $post['ID'], $field );
}
}
}
return $post;
}Ну вот, мы сохранили настраиваемые поля в БД и они доступны для front-end.
Будьте внимательны при экспериментах с полями и параметром post. В первом случае нам нужен object, а во втором — array.
Подсказка: использование update_post_meta создаст значение meta, если оно еще не создано.
Подсказка: Надо добавить префикс к настраиваемым полям вида "_", чтобы они не отображались в списке мета-боксов для настраиваемых полей на страницах редактирования постов.
Проверяем и учитываем ошибки
На момент выхода версии 3.5 ошибки не отображались для форм редактирования вложений. Не смотря на заявление, что этот недостаток исправлен, изучение кода показало, что никаких изменений нет (http://core.trac.wordpress.org/ticket/13810). Для процесса сохранения ajax-кода всё еще не было правок в файле ajax-actions.php следующего вида:
$errors = $post['errors']; // @todo return me and display me!
А вот теперь ошибки должны обрабатываться корректно.
4. Front End
Для использования настраиваемых полей в ваших шаблонах оформления вам надо просто заполнить значение мета-данных так, как вы обычно это делаете для постов. И не забудьте добавить префикс "_". Например, вот так:
echo "<ul>"; echo " <li><strong>Copyright</strong>: " . get_post_meta( get_the_ID(), '_image_copyright', true ) . "</li>"; echo " <li><strong>Rating</strong>: " . get_post_meta( get_the_ID(), '_image_stars', true ) . "</li>"; echo " <li><strong>Author description</strong>: " . get_post_meta( get_the_ID(), '_image_author_desc', true ) . "</li>"; echo " <li><strong>Image disposition</strong>: " . get_post_meta( get_the_ID(), '_image_disposition', true ) . "</li>"; echo " <li><strong>Watermark?</strong> " . ( get_post_meta( get_the_ID(), '_image_watermark', true ) == "on" ? "yes" : "no" ) . "</li>"; echo "</ul>";

И еще немного
Есть еще несколько улучшений, которые стоит учесть в зависимости от ваших целей и задач:
- Настройки можно внести в БД, чтобы сделать редактирование и добавление / удаление более гибким процессом.
- Можно использовать значения по умолчанию для всех вложений, если не задан пользовательский параметр или не указано конкретное значение.
- К модальному отображению не помешает добавить немного стилистического оформления для настраиваемых полей.
Если у вас остались вопросы или пожелания, не стесняйтесь, спрашивать можно в комментариях к этому уроку.





















Комментарии к записи: 2
Здравствуйте, подскажите пожалуйста, есть ли способы сделать сортировку медиа (в медиагаллерее) по созданным полям, или по добавленным к ним таксономиям? В сторону каких фильтров копать? Стандартная сортировка по дате загрузки катастрофически неудобна
В данном конкретном плагине такой возможности нет. Какие фильтры тут искать и применять — это скорее к WP разработчикам вопрос. Но идея определенно здравая, такая возможность многим бы пригодилась.