От автора: с выходом WordPress 4.4 в данной CMS появился новый тип метаданных – метаданные терминов. Теперь вы можете сохранять метаданные для терминов так же, как и для постов. Долгожданное нововведение и логическое дополнение WordPress.
До настоящего времени у нас была возможность добавлять произвольные метаданные к постам и комментариям. Все это можно было использовать для добавления рейтинга к комментариям, выражения своего настроения во время написания комментария, прикрепления цены к товарам и для добавления любой другой подходящей информации к контенту. В последней версии WordPress появилась возможность добавлять метаданные к терминам, позволяя создавать такие функции, как добавление к категориям по умолчанию превьюшек. В этом уроке вы научитесь редактировать, обновлять и вытаскивать метаданные для терминов.
Что под капотом у метаданных для терминов
Логика далеко не нова и уже использовалась в постах, комментариях и для таблицы пользователей. У метаданных терминов появилась своя таблица termmeta с полями term_id, meta_key, meta_value и автоинкрементом meta_id.
Функции метаданных
Для работы с новым типом метаданных, в частности для создания, чтения, обновления и удаления метаданных терминов, были представлены четыре новых функции:
add_term_meta(): добавляет метаданные
update_term_meta(): обновляет существующие метаданные
delete_term_meta(): удаляет метаданные
get_term_meta(): вытягивает метаданные
Под капотом у этих функций код почти такой же, как для функций метаданных постов.
Как использовать метаданные терминов
В последнем проекте мне пришлось добавить дополнительные атрибуты не иерархическим терминам. Отличный шанс протестировать новые метаданные.
В проекте использовалась кастомная категория постов, посты были про дома. В качестве терминов кастомной таксономии были заданы свойства дома (т.е. диван, TV и т.д.). Редактору информации о домах необходимо было получить список свойств домов на основе групп. А группы в свою очередь не должны быть свойствами дома. И я решил добавить эту группу через метаданные терминов.
Я использовал свою таксономию house_feature, но если вы хотите добавить метаданные для категорий постов или тегов, можете воспользоваться стандартными category или post_tag. Сперва я создал свою таксономию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
add_action('init', 'register_feature_taxonomy'); function register_feature_taxonomy() { $labels = array( 'name' => _x( 'Features', 'taxonomy general name', 'my_plugin' ), 'singular_name' => _x('Features', 'taxonomy singular name', 'my_plugin'), 'search_items' => __('Search Feature', 'my_plugin'), 'popular_items' => __('Common Features', 'my_plugin'), 'all_items' => __('All Features', 'my_plugin'), 'edit_item' => __('Edit Feature', 'my_plugin'), 'update_item' => __('Update Feature', 'my_plugin'), 'add_new_item' => __('Add new Feature', 'my_plugin'), 'new_item_name' => __('New Feature:', 'my_plugin'), 'add_or_remove_items' => __('Remove Feature', 'my_plugin'), 'choose_from_most_used' => __('Choose from common Feature', 'my_plugin'), 'not_found' => __('No Feature found.', 'my_plugin'), 'menu_name' => __('Features', 'my_plugin'), ); $args = array( 'hierarchical' => false, 'labels' => $labels, 'show_ui' => true, ); register_taxonomy('house_feature', array('houses'), $args); } |
В последней строчке вам необходимо заменить тип поста houses на свой. Если вы хотите использовать новую таксономию на постах по умолчанию, то поставьте значение post.
В случае если вы используете код из данной статьи в файле темы functions.php или внутри плагина, проверьте, чтобы текст домена my_plugin совпадал с текстом домена темы или плагина. Текст домена my_plugin будет работать в плагине с текстом ссылки my_plugin.
Управление группами, которые я назначил свойствам дома, производится из панели настроек. Также это может быть просто массив. Чтобы быстро и наглядно показать принцип работы метаданных терминов для текущих групп я возьму глобальный массив.
1 2 3 4 5 |
$feature_groups = array( 'bedroom' => __('Bedroom', 'my_plugin'), 'living' => __('Living room', 'my_plugin'), 'kitchen' => __('Kitchen', 'my_plugin') ); |
Для того, чтобы прикрепить к терминам метаданные, необходимо расширить форму редактирования терминов. Сложность в том, что все необходимые нам хуки создаются динамически.
Добавление метаданных к новому термину
Для того, чтобы расширить форму и добавить термин, необходимо воспользоваться хуком {$taxonomy}_add_form_fields. Для нашей таксономии house_feature это house_feature_add_form_fields.
1 2 3 4 5 6 7 8 9 10 11 12 |
add_action( 'house_feature_add_form_fields', 'add_feature_group_field', 10, 2 ); function add_feature_group_field($taxonomy) { global $feature_groups; ?><div class="form-field term-group"> <label for="featuret-group"><?php _e('Feature Group', 'my_plugin'); ?></label> <select class="postform" id="equipment-group" name="feature-group"> <option value="-1"><?php _e('none', 'my_plugin'); ?></option><?php foreach ($feature_groups as $_group_key => $_group) : ?> <option value="<?php echo $_group_key; ?>" class=""><?php echo $_group; ?></option> <?php endforeach; ?> </select> </div><?php } |
Код выше добавляет выпадающий список между оригинальными полями формы и кнопкой отправки.
Форма создания нового термина в кастомной таксономии теперь выглядит так. Для сохранения метаданных термина необходимо запускать специальный хук, created_{$taxonomy}.
1 2 3 4 5 6 7 8 |
add_action( 'created_house_feature', 'save_feature_meta', 10, 2 ); function save_feature_meta( $term_id, $tt_id ){ if( isset( $_POST['feature-group'] ) && '' !== $_POST['feature-group'] ){ $group = sanitize_title( $_POST['feature-group'] ); add_term_meta( $term_id, 'feature-group', $group, true ); } } |
Данные о термине, полученные из глобального массива $_POST, сохраняются с помощью новой функции add_term_meta(). Как и add_post_meta() функция принимает 4 аргумента:
$term_id: ID термина
$meta_key: мета ключ
$meta_value: значение
$unique: может ли ключ использоваться всего раз или нет. По умолчанию стоит false.
Аргумент $unique я задал в true, так как я хочу, чтобы каждое свойство дома находилось только в одной группе.
Обновление термина с помощью метаданных
Даже если у процессов есть что-то общее, все же добавление нового термина и обновление существующего технически отличается в WordPress. Поэтому необходимо добавить и функцию обновления. Для получения поля для группы в форме редактирования, мы использовали хук {$taxonomy}_edit_form_fields.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
add_action( 'house_feature_edit_form_fields', 'edit_feature_group_field', 10, 2 ); function edit_feature_group_field( $term, $taxonomy ){ global $feature_groups; // получаем текущую группу $feature_group = get_term_meta( $term->term_id, 'feature-group', true ); ?><tr class="form-field term-group-wrap"> <th scope="row"><label for="feature-group"><?php _e( 'Feature Group', 'my_plugin' ); ?></label></th> <td><select class="postform" id="feature-group" name="feature-group"> <option value="-1"><?php _e( 'none', 'my_plugin' ); ?></option> <?php foreach( $feature_groups as $_group_key => $_group ) : ?> <option value="<?php echo $_group_key; ?>" <?php selected( $feature_group, $_group_key ); ?>><?php echo $_group; ?></option> <?php endforeach; ?> </select></td> </tr><?php } |
Кроме добавления нового элемента в форму, необходимо еще вытянуть данные о существующих терминах с помощью get_term_meta() и выбрать их. Функция принимает три аргумента:
$term_id: ID термина
$key: ключ метаданных
$single: вернуть одно значение или нет. По умолчанию false и возвращает массив.
Так как я ожидаю на выходе одно значение, я установил $single в true. Для сохранения данных необходимо использовать хук edited_{$taxonomy}.
1 2 3 4 5 6 7 8 9 |
add_action( 'edited_house_feature', 'update_feature_meta', 10, 2 ); function update_feature_meta( $term_id, $tt_id ){ if( isset( $_POST['feature-group'] ) && '' !== $_POST['feature-group'] ){ $group = sanitize_title( $_POST['feature-group'] ); update_term_meta( $term_id, 'feature-group', $group ); } } |
Вместо добавления новых значений метаданных мы переписываем существующие с помощью update_term_meta().
Отображение метаданных терминов в списке терминов
Метаданные сохранены, давайте теперь отобразим их в новой колонке в таблице терминов. Сперва добавим колонку и заголовок к ней. Поиск подходящего хука для добавления новой колонки в таблицу в WordPress опять же процесс немного запутанный, очень много подходящих имен.
В нашем случае можно использовать шаблон manage_edit-{$taxonomy}_columns, хотя хук не совсем так задан.
1 2 3 4 5 6 |
add_filter('manage_edit-house_feature_columns', 'add_feature_group_column' ); function add_feature_group_column( $columns ){ $columns['feature_group'] = __( 'Group', 'my_plugin' ); return $columns; } |
Для добавления контента в колонку воспользуйтесь шаблоном manage_{$taxonomy}_custom_column.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
add_filter('manage_house_feature_custom_column', 'add_feature_group_column_content', 10, 3 ); function add_feature_group_column_content( $content, $column_name, $term_id ){ global $feature_groups; $term_id = absint( $term_id ); $feature_group = get_term_meta( $term_id, 'feature-group', true ); if( !empty( $feature_group ) ){ $content .= esc_attr( $feature_groups[ $feature_group ] ); } return $content; } |
Еще раз, с помощью get_term_meta() мы получаем значения и просто прикрепляем их к существующему контенту. Другие разработчики могут прикрепить что-то другое.
Вот такая задача стояла у меня в проекте, чтобы множество терминов имели одинаковое значение. Добавим колонке групп сортировку. Для этого необходимо всего лишь добавить ее в список сортируемых колонок.
1 2 3 4 5 6 |
add_filter( 'manage_edit-house_feature_sortable_columns', 'add_feature_group_column_sortable' ); function add_feature_group_column_sortable( $sortable ){ $sortable[ 'feature_group' ] = 'feature_group'; return $sortable; } |
Вот так теперь должна выглядеть наша таблица с дополнительной колонкой под метаданные терминов:
Список терминов с таблицей метаданных.
Удаление метаданных термина
При удалении термина, вместе с ним удаляются и соответствующие метаданные. Так что не надо убираться за собой. Однако если потребуется все же удалить метаданные термина, можно воспользоваться функцией delete_term_meta(). Она принимает три аргумента:
$term_id: ID термина
$meta_key: мета ключ
$meta_value: предыдущее значение
Метаданные с заданным значением можно удалить по полю $meta_value.
Получение терминов по мета значению
Как и с постами, вы можете вытянуть термины по мета значениям. Необходимо задать параметр meta_query в функциях get_terms() и wp_get_object_terms(). По следующему запросу я получу все свойства дома по группе kitchen.
1 2 3 4 5 6 7 8 9 10 11 12 |
$args = array( 'hide_empty' => false, // also retrieve terms which are not used yet 'meta_query' => array( array( 'key' => 'feature-group', 'value' => 'kitchen', 'compare' => 'LIKE' ) ) ); $terms = get_terms( 'house_feature', $args ); |
Синтаксис у meta_query такой же, как и у WP_Query, что позволяет использовать различные операторы для compare: NOT LIKE, EXISTS или BETWEEN.
Так как для группировки терминов я использую метаданные, было бы просто замечательно получить результат, отсортированный по мета значению. Но в отличие от WP_Query, тут нельзя использовать orderby => meta_value. Результат можно сортировать только после получения. Для отображения терминов и метаданных необходимо пробежаться циклом по результату выборки и использовать функцию get_term_meta().
1 2 3 4 5 6 7 |
if ( ! empty( $terms ) && ! is_wp_error( $terms ) ){ echo '<ul>'; foreach ( $terms as $term ) { echo '<li>' . $term->name . ' (' . get_term_meta( $term->term_id, 'feature-group', true ) . ')' . '</li>'; } echo '</ul>'; } |
Заключение
Я знаю множество проектов, которые уже сохраняют метаданные в кастомных таксономиях. С распространением WordPress 4.4 большинство из них, вероятнее всего, обновят и будут использовать новую логику метаданных.
Мне теперь не хватает всего одной вещи – это возможности прикрепления метаданных к конкретным связям термин-объект. Если вы знаете, как это сделать, пишите в комментариях.
Автор: Thomas Maier
Источник: //www.smashingmagazine.com/
Редакция: Команда webformyself.