Метаполя (произвольные поля) для рубрик (таксономий) в WordPress — title, description, keywords…
На сайте есть замечательная статья про создание произвольных полей но вот про метаполя или произвольные поля вроде title для элементов таксономий или терминов или рубрик, меток ничего не нашел.
Подскажите, в какую сторону копать (без плагинов).
Хотелось бы иметь простой класс, чтобы создать метабоксы (metaboxes) для taxonomy (term терминов). Т.е. Как создать метабоксы для таксономий?
Как раз по теме создания таких полей в админ-панели, я описывал хук (taxonomy)_edit_form_fields. Рекомендую к прочтению.
Шаг 1: (с версии WP 4.4 не нужен)
Шаг 1 устарел с версии WordPress 4.4. поэтому я убрал его вниз ответа...
Шаг 2:
Нужно вывести поля при редактировании термина. Для этого предлагаю использовать класс от Миши Рудрастых (я его немного изменил). Добавляем его в functions.php в самое начало или в плагин:
/* * Бэкэнд для добавления настроек на страницу редактирования элементов таксономий * Взято из статьи: http://truemisha.ru/blog/wordpress/metadannyie-v-taksonomiyah.html * ver 1.2 * Нужно PHP 5.3+ */ class trueTaxonomyMetaBox { private $opt; private $prefix; function __construct( $option ) { $this->opt = (object) $option; $this->prefix = $this->opt->id .'_'; // префикс настроек foreach( $this->opt->taxonomy as $taxonomy ){ add_action( $taxonomy . '_edit_form_fields', array( &$this, 'fill'), 10, 2 ); // хук добавления полей } // установим таблицу в $wpdb, если её нет global $wpdb; if( ! isset( $wpdb->termmeta ) ) $wpdb->termmeta = $wpdb->prefix .'termmeta'; add_action('edit_term', array( &$this, 'save'), 10, 1 ); // хук сохранения значений полей } function fill( $term, $taxonomy ){ foreach( $this->opt->args as $param ){ $def = array('id'=>'', 'title'=>'', 'type'=>'', 'desc'=>'', 'std'=>'', 'args'=>array() ); $param = (object) array_merge( $def, $param ); $meta_key = $this->prefix . $param->id; $meta_value = get_metadata('term', $term->term_id, $meta_key, true ) ?: $param->std; echo '<tr class ="form-field">'; echo '<th scope="row"><label for="'. $meta_key .'">'. $param->title .'</label></th>'; echo '<td>'; // select if( $param->type == 'wp_editor' ){ wp_editor( $meta_value, $meta_key, array( 'wpautop' => 1, 'media_buttons' => false, 'textarea_name' => $meta_key, //нужно указывать! 'textarea_rows' => 10, //'tabindex' => null, //'editor_css' => '', //'editor_class' => '', 'teeny' => 0, 'dfw' => 0, 'tinymce' => 1, 'quicktags' => 1, //'drag_drop_upload' => false ) ); } // select elseif( $param->type == 'select' ){ echo '<select name="'. $meta_key .'" id="'. $meta_key .'"> <option value="">...</option>'; foreach( $param->args as $val => $name ){ echo '<option value="'. $val .'" '. selected( $meta_value, $val, 0 ) .'>'. $name .'</option>'; } echo '</select>'; if( $param->desc ) echo '<p class="description">' . $param->desc . '</p>'; } // checkbox elseif( $param->type == 'checkbox' ){ echo ' <label> <input type="hidden" name="'. $meta_key .'" value=""> <input name="'. $meta_key .'" type="'. $param->type .'" id="'. $meta_key .'" '. checked( $meta_value, 'on', 0) .'> '. $param->desc .' </label> '; } // textarea elseif( $param->type == 'textarea' ){ echo '<textarea name="'. $meta_key .'" type="'. $param->type .'" id="'. $meta_key .'" value="'. $meta_value .'" class="large-text">'. esc_html( $meta_value ) .'</textarea>'; if( $param->desc ) echo '<p class="description">' . $param->desc . '</p>'; } // text else{ echo '<input name="'. $meta_key .'" type="'. $param->type .'" id="'. $meta_key .'" value="'. $meta_value .'" class="regular-text">'; if( $param->desc ) echo '<p class="description">' . $param->desc . '</p>'; } echo '</td>'; echo '</tr>'; } } function save( $term_id ){ foreach( $this->opt->args as $field ){ $meta_key = $this->prefix . $field['id']; if( ! isset($_POST[ $meta_key ]) ) continue; if( $meta_value = trim($_POST[ $meta_key ]) ){ update_metadata('term', $term_id, $meta_key, $meta_value, ''); } else { delete_metadata('term', $term_id, $meta_key, '', false ); } } } }Далее используя добавленный класс, создаем поля для элементов таксономий
add_action('init', 'register_additional_term_fields'); function register_additional_term_fields(){ new trueTaxonomyMetaBox( array( 'id' => 'txseo', // id играет роль префикса названий полей 'taxonomy' => array('category','post_tag'), // названия таксономий, для которых нужно добавить ниже перечисленные поля 'args' => array( array( 'id' => 'seo_title', // атрибуты name и id без префикса, получится "txseo_seo_title" 'title' => 'SEO Заголовок', 'type' => 'text', 'desc' => 'Укажите альтернативное название термина для SEO.', 'std' => '', // по умолчанию ), array( 'id' => 'seo_description', 'title' => 'SEO Описание', 'type' => 'text', 'desc' => 'meta тег description.', 'std' => '', // по умолчанию ) ) ) ); }И вот что должно получиться:
Шаг 3:
Выводим имеющиеся поля в заголовки рубрик и в head часть документа.
add_action('wp_head', 'add_taxseo_head_meta_fields'); function add_taxseo_head_meta_fields(){ if( ! is_tax() && ! is_category() && ! is_tag() ) return; // выходим если не таксы $term = get_queried_object(); echo '<meta name="description" content="'. get_metadata('term', $term->term_id, 'txseo_seo_description', 1 ) .'">'. "\n"; } //apply_filters( 'wp_title', $title, $sep, $seplocation ); add_filter('wp_title', 'add_taxseo_wp_title', 20, 3); function add_taxseo_wp_title( $title, $sep, $seplocation ){ if( ! is_tax() && ! is_category() && ! is_tag() ) return $title; // выходим если не таксы $term = get_queried_object(); $title = get_metadata('term', $term->term_id, 'txseo_seo_title', 1 ); return esc_html( $title ); }Можно делать без хуков, а напрямую, тут уже от имеющихся плагинов зависит...
Главное тут мы получаем метаполя с помощью get_metadata()
$description = get_metadata('term', $term->term_id, 'txseo_seo_description', 1 ) $title = get_metadata('term', $term->term_id, 'txseo_seo_title', 1 ); // с версии WP 4.4 можно использовать встроенные функции $description = get_term_meta( $term->term_id, 'txseo_seo_description', 1 ); $title = get_term_meta( $term->term_id, 'txseo_seo_title', 1 );Шаг 1: (с версии WP 4.4 не нужен)
Тут главная проблема, что некуда записывать данные. Во многих источниках данные пишут в опции, а это плохо. Хорошо если создать специальную таблицу метаданных для таксономий.
Этот шаг не нужен с версии 4.4. В этой версии, наконец, была создана таблица метаполей для элементов таксономий! Поэтому если у вас WP 4.4 и выше, переходите сразу к шагу 2.
Запускаете один раз эту функцию, потом код можно удалить. Для запуска можно в functions.php сунуть:
## Функция создания таблицы метаданных таксономий, вешается на register_activation_hook() # register_activation_hook( __FILE__, 'create_termmeta_table'); function create_termmeta_table(){ global $wpdb; $charset_collate = ''; if ( ! empty($wpdb->charset) ) $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset"; if ( ! empty($wpdb->collate) ) $charset_collate .= " COLLATE $wpdb->collate"; /* * Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that. * As of 4.2, however, we moved to utf8mb4, which uses 4 bytes per character. This means that an index which * used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters. */ $max_index_length = 191; $tables = $wpdb->get_results("show tables like '{$wpdb->prefix}termmeta'"); if (!count($tables)){ $wpdb->query("CREATE TABLE {$wpdb->prefix}termmeta ( meta_id bigint(20) unsigned NOT NULL auto_increment, term_id bigint(20) unsigned NOT NULL default '0', meta_key varchar(255) default NULL, meta_value longtext, PRIMARY KEY (meta_id), KEY term_id (term_id), KEY meta_key (meta_key($max_index_length)) ) $charset_collate;"); } } // запуск create_termmeta_table();Эта функцию создаст новую таблицу в БД, termmeta - термины для таксономий.
Подробнее в этой статье: http://wp-kama.ru/note/taxonomy-metadata-metadannyie-dlya-taksonomiy
Теперь у нас есть куда записывать данные таксономий.
в теории все понятно, как раз то, что было нужно.
Но вот на практике - не работает. Данные не сохраняются.
В этой статье: также было упомянуто про создание поля для картинки в рубриках, было бы здорово реализовать еще и это. Сейчас потыкаю на тестовом варианте, может что и получится.
сейчас вывод title для записей и страниц происходит вот так:
<?php if ( get_post_meta($post->ID, 'title', true) ) : echo get_post_meta($post->ID, 'title', true); else : wp_title('-', true, 'right'); ?><?php bloginfo('name'); endif; ?>также, в header.php вывод мета для страниц и записей
Как возможно подставить вывод сюда, с прописанием условий для категорий? а то запутался
Как это не сохраняются, я проверял код у меня все работало...
Что касается вывода, то созданные метаполя выводятся так:
<?php echo get_metadata('term', $term->term_id, 'term_seo_description', 1 ); ?>Это вывод для поля
seo_descriptionИ т.д. по аналогии. Выводите где нужно и как нужно. Перед выводом проверьте что вы находитесь на странице рубрики. В общем этот код есть в ответе, изучайте...
Таблица wp_termmeta создалась, тут все ок, поля в таблице: meta_id, term_id, meta_key, meta_value. Доп. поля в рубрике тоже создались, все как на картинке, выложенной Вами. Но вот при редактировании рубрики, таблица остается пустой т.е.: вбиваем в соответствующие поля в рубрике что-либо, кликаем "сохранить", заходим в рубрику заново, и видим эти поля пустыми. В бд данные также не заносятся
Ой, извиняюсь! Я же забыл зарегистрировать название таблицы. Обновил класс trueTaxonomyMetaBox до версии v1.1, там строки добавил:
здорово, работает. Только Вы ошиблись: поле в таблице по выше написанному коду не "term_seo_description", а "txseo_seo_description". Получилось что-то вроде вот этого:
<meta name="description" content="<?php if( ! is_tax() && ! is_category() && ! is_tag() ) return; // выходим если не таксы $term = get_queried_object(); echo get_metadata('term', $term->term_id, 'txseo_seo_description', 1 ); ?>" />Осталось дописать вывод в else стандартного сценария вывода доп полей. Спасибо большое!
ага, все вместе получилось так:
<meta name="description" content="<?php if( is_tax() || is_category() || is_tag() ) { //выводим, если страница архива, категории или страница меток $term = get_queried_object(); // магия echo get_metadata('term', $term->term_id, 'txseo_seo_description', true ); // собственно, сам вывод } else { // если что-то другое (страница или запись) echo get_post_meta($post->ID, 'description', true); } ?>" />Для тех кто использует All in One Seo Pack третий шаг нужно изменить
add_action('init', 'register_additional_term_fields'); function register_additional_term_fields(){ new trueTaxonomyMetaBox( array( 'id' => 'txseo', // id играет роль префикса названий полей 'taxonomy' => array('category','post_tag'), // названия таксономий, для которых нужно добавить ниже перечисленные поля 'args' => array( array( 'id' => 'seo_title', // атрибуты name и id без префикса, получится "txseo_seo_title" 'title' => 'SEO Заголовок', 'type' => 'text', 'desc' => 'Укажите альтернативное название термина для SEO.', 'std' => '', // по умолчанию ), array( 'id' => 'seo_description', 'title' => 'SEO Описание', 'type' => 'text', 'desc' => 'meta тег description.', 'std' => '', // по умолчанию ) ) ) ); } add_filter('aioseop_description', 'add_taxseo_head_meta_fields'); function add_taxseo_head_meta_fields($descr){ if( ! is_tax() && ! is_category() && ! is_tag() ) return $descr; // выходим если не таксы $term = get_queried_object(); $descr = get_metadata('term', $term->term_id, 'txseo_seo_description', 1 ); return $descr; } //apply_filters( 'wp_title', $title, $sep, $seplocation ); add_filter('aioseop_title', 'add_taxseo_wp_title', 5, 3); function add_taxseo_wp_title( $title, $sep, $seplocation ){ if( ! is_tax() && ! is_category() && ! is_tag() ) return $title; // выходим если не таксы $term = get_queried_object(); $title = get_metadata('term', $term->term_id, 'txseo_seo_title', 1 ); return esc_html( $title ); }Спасибо! Помогли
Превосходно! Спасибо за отличный, структурированный, достаточно объяснённый пример! Очень помогло с переданным сайтом, на котором стоит старый ACF, не умеющий в поля для рубрик (а обновление ломает вёрстку, построенную на других полях).
Еще бы указать, можно ли поднять их повыше в админке, т.к. они болтаются в самом низу.
Огромное спасибо, полезный материал, но подскажите, как добавить возможность к выше упомянутому, а именно возможность добавить абрац, так как описание дублируется в дескрипшн.
тут нашел решение, но не тестировал, что скажите?
А если мне нужен select тогда как быть?