Метабоксы в WordPress, удаление стандартных и добавление собственных

В основном метабоксы в WordPress нужны для удобства (ну кроме стандартных разумеется), потому что все настройки, которые вы можете добавить в собственном метабоксе, можно заменить использованием произвольных полей.

remove_meta_box() — удаление метабоксов

remove_meta_box( $id, $page, $context );
  • $id (строка)
    идентификатор метабокса, его можно найти в исходном коде странице, чуть ниже я перечислю айдишники всех стандартных метабоксов.
  • $page (строка)
    тип постов, на странице создания/редактирования которых нужно удалить метабокс, например post, page.
  • $context (строка)
    расположение метабокса, например normal, advanced или side

Простая вставка этой функции куда-либо не прокатит, поэтому привожу пример:

/*
 * удаляем со страницы редактирования постов метабокс с рубриками и цитатой
 */
function remove_category_div() {
	remove_meta_box( 'categorydiv' , 'post' , 'side' ); // рубрики
	remove_meta_box( 'postexcerpt' , 'post' , 'normal' ); // цитата
}
add_action( 'admin_menu' , 'remove_category_div' );

Код вставлять в functions.php текущей темы.

Описание стандартных метабоксов в WordPress

Для того, чтобы не нужно было париться и рыскать в коде, перечислю айдишники стандартных метабоксов.

  • commentstatusdiv — настройки обсуждения,
    метабокс commentstatusdiv
  • commentsdiv — отображает комментарии к текущему посту,
    метабокс commentsdiv в WordPress
  • slugdiv — ярлык записи,
    slugdiv метабокс
  • revisionsdiv — редакции,
    метабокс с редакциями, revisionsdiv
  • authordiv — автор записи,
    authordiv метабокс
  • postcustom — добавление/редактирование произвольных полей,
    postcustom, метабокс произвольных полей
  • postexcerpt — цитата,
    postexcerpt, метабокс цитаты
  • trackbacksdiv — обратные ссылки,
    метабокс trackbacksdiv в WordPress
  • categorydivсписок рубрик,
    categorydiv, метабокс с рубриками
  • tagsdiv-post_tag — метки,
    tagsdiv-post_tag
  • postimagediv — миниатюра записи,
    postimagediv, миниатюра записи
  • pageparentdiv — метабокс с выбором родительской страницы и шаблона страниц,
    pageparentdiv, атрибуты страницы
  • submitdiv — блок с кнопкой «опубликовать».
    submitdiv, метабокс в WordPress

Способы добавления метабоксов

register_post_type()

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

В примере перечислено лишь минимум необходимых параметров, но он все равно рабочий.

function true_register_post_type_example(){
	$args = array(
		'hierarchical' => true,
		'show_ui' => true, 
		/*
		 * присвоив таксономию для поста, мы автоматически подключаем метабокс этой таксономии
		 */
		'taxonomies' => array('category'),
		/*
		 * а теперь прописываем уже сами названия метабоксов,
		 * названия для register_post_type() и для remove_meta_box() будут отличаться!!
		 */
		'supports' => array( 'title', 'editor' )
		/*
		 * Возможные варианты содержимого массива "supports":
		 *
		 * title - заголовок,
		 * editor - редактор,
		 * author - автор записи,
		 * thumbnail - миниатюра записи,
		 * excerpt - поле для цитаты,
		 * trackbacks - обратные ссылки,
		 * custom-fields - произвольные поля,
		 * comments - комментарии,
		 * revisions - редакции,
		 * page-attributes - атрибуты поста, только при 'hierarchical' => true
		 *
		 */
	);
	register_post_type('truepost', $args);
}
 
add_action( 'init', 'true_register_post_type_example' );

register_taxonomy_for_object_type()

Функция приписывает таксономию к уже созданному типу записей, а значит, добавляется и метабокс:

register_taxonomy_for_object_type($taxonomy, $object_type);
  • $taxonomy (строка) (обязательное)
    название таксономии, например post_tag,
  • $object_type (строка) (обязательное)
    тут укажите тип поста, для которого нужно присвоить таксономию, например post, page, game;

Эту функцию тоже просто так не заюзать, поэтому пример:

function true_additional_taxonomies(){
	register_taxonomy_for_object_type('post_tag', 'truepost');
}
 
add_action( 'init', 'true_additional_taxonomies' );

add_post_type_support()

Позволяет добавить какой-нибудь из стандартных боксов.

add_post_type_support( $post_type, $supports )
  • $post_type (строка) (обязательное)
    тип поста (максимум 20 символов кстати),
  • $supports (строка|массив)
    названия стандартных метабоксов, которые перечислены двумя примерами выше;
function add_some_std_metaboxes() {
	add_post_type_support('game', 'excerpt'); // цитата
	add_post_type_support('truepost', array('excerpt', 'thumbnail')); // цитата и миниатюра
}
 
add_action('init', 'add_some_std_metaboxes');

add_meta_box()

А вот тут уже можно повеселиться, вы сможете добавить абсолютно любой собственный метабокс, неважно, будут ли это поля для указания мета-тегов или же загрузчик изображений в галерею.

add_meta_box($id, $title, $callback, $post_type, $context, $priority, $args);
  • $id (строка) (обязательное)
    HTML-атрибут id для блока div будущего метабокса,
  • $title (строка) (обязательное)
    заголовок,
  • $callback (функция) (обязательное)
    функция которая будет заполнять метабокс, нужно указать название функции в виде строки,
  • $post_type (строка) (обязательное)
    тип записей,
  • $context (строка)
    в какой части страницы вставить метабокс (normal, side, advanced), по умолчанию — advanced,
  • $priority (строка)
    приоритет, чем он выше, тем ближе к верхней части страницы будет располагаться метабокс, (high, core, default или low), по умолчанию — default,
  • $args (массив)
    аргументы для callback-функции.

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

<?php
/*
 * Этап 1. Добавление
 */
function true_meta_boxes() {
	add_meta_box('truediv', 'Настройки', 'true_print_box', 'post', 'normal', 'high');
}
 
add_action( 'admin_menu', 'true_meta_boxes' );
/*
 * также можно использовать и другие хуки:
 * add_action( 'add_meta_boxes', 'tr_meta_boxes' );
 * если версия WordPress ниже 3.0, то
 * add_action( 'admin_init', 'tr_meta_boxes', 1 );
 */
 
/*
 * Этап 2. Заполнение
 */
function true_print_box($post) {
	wp_nonce_field( basename( __FILE__ ), 'seo_metabox_nonce' );
	/*
	 * добавляем текстовое поле
	 */
	$html .= '<label>Заголовок <input type="text" name="seotitle" value="' . get_post_meta($post->ID, 'seo_title',true) . '" /></label> ';
	/*
	 * добавляем чекбокс
	 */
	$html .= '<label><input type="checkbox" name="noindex"';
	$html .= (get_post_meta($post->ID, 'seo_noindex',true) == 'on') ? ' checked="checked"' : '';
	$html .= ' /> Скрыть запись от поисковиков?</label>';
 
	echo $html;
}
 
/*
 * Этап 3. Сохранение
 */
function true_save_box_data ( $post_id ) {
	// проверяем, пришёл ли запрос со страницы с метабоксом
	if ( !isset( $_POST['seo_metabox_nonce'] )
	|| !wp_verify_nonce( $_POST['seo_metabox_nonce'], basename( __FILE__ ) ) )
        return $post_id;
	// проверяем, является ли запрос автосохранением
	if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
		return $post_id;
	// проверяем, права пользователя, может ли он редактировать записи
	if ( !current_user_can( 'edit_post', $post_id ) )
		return $post_id;
	// теперь также проверим тип записи	
	$post = get_post($post_id);
	if ($post->post_type == 'post') { // укажите собственный
		update_post_meta($post_id, 'seo_title', esc_attr($_POST['seotitle']));
		update_post_meta($post_id, 'seo_noindex', $_POST['noindex']);
	}
	return $post_id;
}
 
add_action('save_post', 'true_save_box_data');

В итоге на странице редактирования поста получаем вот такой метабоксик:

собственный метабокс с настройками в вордпресс

Код можно вставить прямо в таком виде в functions.php — и всё будет работать, если конечно у вас нет функций, названия которых совпадают с моими.

Добавление метабоксов с использованием класса

На самом деле это просто потрясающая штука!

  • достаточно один раз описать класс и затем сколько угодно использовать его для добавления метабоксов на сайте,
  • не придется каждый раз париться по поводу HTML полей ввода, как в случае с функцией add_meta_box(),
  • все, что потребуется для создания нового метабокса — добавить несколько параметров в массив;

А теперь у меня для вас подарок! Уже готовый класс со всеми необходимыми типами полей.

Расскажу, как его использовать в двух шагах. Первый шаг — скопируйте к себе следующий блок с кодом. Если не знаете куда его засунуть — суйте в functions.php, не ошибетесь.

<?php
class trueMetaBox {
	function __construct($options) {
		$this->options = $options;
		$this->prefix = $this->options['id'] .'_';
		add_action( 'add_meta_boxes', array( &$this, 'create' ) );
		add_action( 'save_post', array( &$this, 'save' ), 1, 2 );
	}
	function create() {
		foreach ($this->options['post'] as $post_type) {
			if (current_user_can( $this->options['cap'])) {
				add_meta_box($this->options['id'], $this->options['name'], array(&$this, 'fill'), $post_type, $this->options['pos'], $this->options['pri']);
			}
		}
	}
	function fill(){
		global $post; $p_i_d = $post->ID;
		wp_nonce_field( $this->options['id'], $this->options['id'].'_wpnonce', false, true );
		?>
		<table class="form-table"><tbody><?php
		foreach ( $this->options['args'] as $param ) {
			if (current_user_can( $param['cap'])) {
			?><tr><?php
				if(!$value = get_post_meta($post->ID, $this->prefix .$param['id'] , true)) $value = $param['std'];
				switch ( $param['type'] ) {
					case 'text':{ ?>
						<th scope="row"><label for="<?php echo $this->prefix .$param['id'] ?>"><?php echo $param['title'] ?></label></th>
						<td>
							<input name="<?php echo $this->prefix .$param['id'] ?>" type="<?php echo $param['type'] ?>" id="<?php echo $this->prefix .$param['id'] ?>" value="<?php echo $value ?>" placeholder="<?php echo $param['placeholder'] ?>" class="regular-text" /><br />
							<span class="description"><?php echo $param['desc'] ?></span>
						</td>
						<?php
						break;							
					}
					case 'textarea':{ ?>
						<th scope="row"><label for="<?php echo $this->prefix .$param['id'] ?>"><?php echo $param['title'] ?></label></th>
						<td>
							<textarea name="<?php echo $this->prefix .$param['id'] ?>" type="<?php echo $param['type'] ?>" id="<?php echo $this->prefix .$param['id'] ?>" value="<?php echo $value ?>" placeholder="<?php echo $param['placeholder'] ?>" class="large-text" /><?php echo $value ?></textarea><br />
							<span class="description"><?php echo $param['desc'] ?></span>
						</td>
						<?php
						break;							
					}
					case 'checkbox':{ ?>
						<th scope="row"><label for="<?php echo $this->prefix .$param['id'] ?>"><?php echo $param['title'] ?></label></th>
						<td>
							<label for="<?php echo $this->prefix .$param['id'] ?>"><input name="<?php echo $this->prefix .$param['id'] ?>" type="<?php echo $param['type'] ?>" id="<?php echo $this->prefix .$param['id'] ?>"<?php echo ($value=='on') ? ' checked="checked"' : '' ?> />
							<?php echo $param['desc'] ?></label>
						</td>
						<?php
						break;							
					}
					case 'select':{ ?>
						<th scope="row"><label for="<?php echo $this->prefix .$param['id'] ?>"><?php echo $param['title'] ?></label></th>
						<td>
							<label for="<?php echo $this->prefix .$param['id'] ?>">
							<select name="<?php echo $this->prefix .$param['id'] ?>" id="<?php echo $this->prefix .$param['id'] ?>"><option>...</option><?php
								foreach($param['args'] as $val=>$name){
									?><option value="<?php echo $val ?>"<?php echo ( $value == $val ) ? ' selected="selected"' : '' ?>><?php echo $name ?></option><?php
								}
							?></select></label><br />
							<span class="description"><?php echo $param['desc'] ?></span>
						</td>
						<?php
						break;							
					}
				} 
			?></tr><?php
			}
		}
		?></tbody></table><?php
	}
	function save($post_id, $post){
		if ( !wp_verify_nonce( $_POST[ $this->options['id'].'_wpnonce' ], $this->options['id'] ) ) return;
		if ( !current_user_can( 'edit_post', $post_id ) ) return;
		if ( !in_array($post->post_type, $this->options['post'])) return;
		foreach ( $this->options['args'] as $param ) {
			if ( current_user_can( $param['cap'] ) ) {
				if ( isset( $_POST[ $this->prefix . $param['id'] ] ) && trim( $_POST[ $this->prefix . $param['id'] ] ) ) {
					update_post_meta( $post_id, $this->prefix . $param['id'], trim($_POST[ $this->prefix . $param['id'] ]) );
				} else {
					delete_post_meta( $post_id, $this->prefix . $param['id'] );
				}
			}
		}
	}
}

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

Теперь шаг второй — создаем объекты и передаем им все параметры метабоксов.

В следующем блоке кода я создаю два метабокса, один по центру с несколькими полями, второй тоже по центру с одним полем — чекбоксом.

$options = array(
	array( // первый метабокс
		'id'	=>	'meta1', // ID метабокса, а также префикс названия произвольного поля
		'name'	=>	'Доп. настройки 1', // заголовок метабокса
		'post'	=>	array('post'), // типы постов для которых нужно отобразить метабокс
		'pos'	=>	'normal', // расположение, параметр $context функции add_meta_box()
		'pri'	=>	'high', // приоритет, параметр $priority функции add_meta_box()
		'cap'	=>	'edit_posts', // какие права должны быть у пользователя
		'args'	=>	array(
			array(
				'id'			=>	'field_1', // атрибуты name и id без префикса, например с префиксом будет meta1_field_1
				'title'			=>	'Текст', // лейбл поля
				'type'			=>	'text', // тип, в данном случае обычное текстовое поле
				'placeholder'		=>	'плейсхолдер, например введите email', // атрибут placeholder
				'desc'			=>	'пример использования текстового поля ввода в метабоксе', // что-то типа пояснения, подписи к полю
				'cap'			=>	'edit_posts'
			),
			array(
				'id'			=>	'terms',
				'title'			=>	'Чекбокс',
				'type'			=>	'checkbox', // чекбокс
				'desc'			=>	'пример чекбокса',
				'cap'			=>	'edit_posts'
			),
			array(
				'id'			=>	'textfield',
				'title'			=>	'Текстовое поле',
				'type'			=>	'textarea', // большое текстовое поле
				'placeholder'		=>	'сюда тоже можно забацать плейсхолдер',
				'desc'			=>	'пример использования большого текстового поля ввода в метабоксе',
				'cap'			=>	'edit_posts'
			),
			array(
				'id'			=>	'select1',
				'title'			=>	'Выпадающий список',
				'type'			=>	'select', // выпадающий список
				'desc'			=>	'тут тоже можно написать пояснение к полю, значения же задаются через ассоциативный массив',
				'cap'			=>	'edit_posts',
				'args'			=>	array('value_1' => 'Значение 1', '2' => 'Значение 2', 'Значение_3' => 'Значение 3' ) // элементы списка задаются через массив args, по типу value=>лейбл
			)
		)
	),
	array( // второй метабокс
		'id'	=>	'meta2',
		'name'	=>	'Доп. настройки 2',
		'post'	=>	array('post', 'page'), // не только для постов, но и для страниц
		'pos'	=>	'normal',
		'pri'	=>	'high',
		'cap'	=>	'edit_posts',
		'args'	=>	array(
			array(
				'id'			=>	'featured',
				'title'			=>	'На главную',
				'desc'			=>	'Отображать пост на главной странице',
				'type'			=>	'checkbox',
				'cap'			=>	'edit_posts'
			)
		)
	)
);
 
foreach ($options as $option) {
	$truemetabox = new trueMetaBox($option);
}

Вот скриншот получившихся метабоксов из админки, со страницы редактирования записи:

метабоксы в вордпресс

Обращение к метаданным поста/страницы

Понятное дело, что потом все эти настройки нужно как-то задействовать на сайте. Для этого отлично подойдет функция:

get_post_meta($post_id, $key, $single);
  • $post_id (целое) (обязательное)
    ID поста или страницы,
  • $key (строка) (обязательное)
    значение произвольного поля,
  • $single (логическое)
    если true — возвращает строку, false — массив, по умолчанию — false;

Пример использования — выведем значение произвольного поля meta1_field_1, то есть текстового поля из предыдущего примера:

echo get_post_meta($post->ID, 'meta1_field_1', true);

По мере совершенствования класса содержимое этого поста будет обновляться.

Миша Рудрастых Разработчик WordPress WooCommerce

Миша Рудрастых

Впервые познакомился с WordPress в 2009 году, и после двух лет мучений с Joomla и самописными движками это был просто бальзам на душу. С 2014 года меня можно встретить на WordCamp — официальной конфе по WP в Москве, иногда там выступаю. Также в настоящее время веду курсы по WordPress в Epic Skills в Питере.