Вы уже наверняка сталкивались с настраиваемыми полями в 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 разработчикам вопрос. Но идея определенно здравая, такая возможность многим бы пригодилась.