WordPress как на ладони
Очень Удобный и Быстрый Хостинг для сайтов на WordPress. Пользуюсь сам и вам рекомендую!

Метаполя (произвольные поля) для рубрик (таксономий) в WordPress — title, description, keywords…

На сайте есть замечательная статья про создание произвольных полей но вот про метаполя или произвольные поля вроде title для элементов таксономий или терминов или рубрик, меток ничего не нашел.

Подскажите, в какую сторону копать (без плагинов).

Хотелось бы иметь простой класс, чтобы создать метабоксы (metaboxes) для taxonomy (term терминов). Т.е. Как создать метабоксы для таксономий?

3
dmelnik
8.8 лет назад 5
  • 0
    Kama9619

    Как раз по теме создания таких полей в админ-панели, я описывал хук (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

    Теперь у нас есть куда записывать данные таксономий.

    dmelnik 8.8 лет назад

    в теории все понятно, как раз то, что было нужно.

    Но вот на практике - не работает. Данные не сохраняются.

    В этой статье: также было упомянуто про создание поля для картинки в рубриках, было бы здорово реализовать еще и это. Сейчас потыкаю на тестовом варианте, может что и получится.

    сейчас вывод 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 вывод мета для страниц и записей

    <meta name="description" content="<?php echo get_post_meta($post->ID, 'description', true); ?>" />
    <meta name="keywords" content="<?php echo get_post_meta($post->ID, 'keywords', true); ?>" />

    Как возможно подставить вывод сюда, с прописанием условий для категорий? а то запутался

    Kama 8.8 лет назад

    >> Но вот на практике - не работает. Данные не сохраняются.

    Как это не сохраняются, я проверял код у меня все работало...

    Что касается вывода, то созданные метаполя выводятся так:

    <?php echo get_metadata('term', $term->term_id, 'term_seo_description', 1 ); ?>

    Это вывод для поля seo_description

    И т.д. по аналогии. Выводите где нужно и как нужно. Перед выводом проверьте что вы находитесь на странице рубрики. В общем этот код есть в ответе, изучайте...

    dmelnik 8.8 лет назад

    Таблица wp_termmeta создалась, тут все ок, поля в таблице: meta_id, term_id, meta_key, meta_value. Доп. поля в рубрике тоже создались, все как на картинке, выложенной Вами. Но вот при редактировании рубрики, таблица остается пустой т.е.: вбиваем в соответствующие поля в рубрике что-либо, кликаем "сохранить", заходим в рубрику заново, и видим эти поля пустыми. В бд данные также не заносятся

    Kama 8.8 лет назад

    Ой, извиняюсь! Я же забыл зарегистрировать название таблицы. Обновил класс trueTaxonomyMetaBox до версии v1.1, там строки добавил:

    // установим таблицу в $wpdb, если её нет
    global $wpdb;
    if( ! isset( $wpdb->termmeta ) ) $wpdb->termmeta = $wpdb->prefix .'termmeta';
    dmelnik 8.8 лет назад

    здорово, работает. Только Вы ошиблись: поле в таблице по выше написанному коду не "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 стандартного сценария вывода доп полей. Спасибо большое!

    dmelnik 8.8 лет назад

    ага, все вместе получилось так:

    <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);
    	}
    ?>" />
    speker 7.2 года назад

    Для тех кто использует 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 );
    }
    Css 5.1 год назад

    Спасибо! Помогли

    Денис 4.4 года назад

    Превосходно! Спасибо за отличный, структурированный, достаточно объяснённый пример! Очень помогло с переданным сайтом, на котором стоит старый ACF, не умеющий в поля для рубрик (а обновление ломает вёрстку, построенную на других полях).

    Еще бы указать, можно ли поднять их повыше в админке, т.к. они болтаются в самом низу.

    Комментировать
  • 0

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

    то есть, чтобы написать отдельно <title>, <description>, анонс <p>.

    тут нашел решение, но не тестировал, что скажите?

    prizrak 3.5 лет назад

    А если мне нужен select тогда как быть?

    Комментировать
На вопросы могут отвечать только зарегистрированные пользователи. Вход . Регистрация