Метабоксы в WordPress

Сейчас у многих слово «метабокс» ассоциируется с каким-нибудь плагином, например «Advanced Custom Fields» или Carbon Fields. Но метабоксы – это стандартный функционал WordPress из коробки.

различные метабоксы в админке WordPress
На этом скриншоте видим метабоксы: «Мишин метабокс», «Отрывок», «Отправить обратные ссылки», «Произвольные поля», «Рубрики», «Метки», «Изображение записи» и кусочек метабокса «Форматы».

А плагины наплодились лишь потому, что при помощи них можно довольно легко сократить количество кода, необходимого для написания метабоксов, причём очень значительно – раз в 10. Ну и некоторые, наиболее ловкие разработчики сделали «ни рыбу ни мясо», подпилив для этого интерфейс в админке. Что вообще смешно – для создания метабокса вы можете воспользоваться интерфейсом в админке, но зато вы никак не сможете воспользоваться этими данными на самом сайте, потому что там то нужно воспользоваться кодом для вывода этих полей (смеюсь уже который год, не могу остановиться).

Кроме того, важный момент – сейчас, когда мы говорим о метабоксах, мы подразумеваем их на тех типах записей, в которых отключен редактор Gutenberg. В самом редакторе Gutenberg метабоксы существуют лишь в качестве обратной совметимости, то есть по сути не поддерживаются. В качестве альтернативы мы должны добавлять поля в сам редактор, например в виде сайдбаров, об этом у меня есть целый видеокурс.

Удаление метабоксов

Любой из метабоксов можно удалить функцией remove_meta_box(). Единственное условие – сам метабокс должен создаваться до удаления, а не наоборот. В этом случае оптимально вешать её на хук add_meta_boxes с высоким приоритетом.

Например в сниппете ниже мы удлаяем метабоксы «Рубрики» и «Отрывок».

add_action( 'add_meta_boxes' , 'true_remove_meta_boxes' );
 
function true_remove_meta_boxes() {
	// метабокс рубрик
	remove_meta_box( 'categorydiv', 'post', 'side' );
	// метабокс отрывка записи
	remove_meta_box( 'postexcerpt', 'post', 'normal' ); 
}

Стандартные метабоксы WordPress

Также для вашего удобства решил перечислить айдишники и описания стандартных метабоксов в WordPress. Конечно, Gutenberg уже пришёл и метабоксы эти есть не всегда, у вас либо тип записи не должен поддерживать Gutenberg, либо включен плагин Classic Editor. И тем не менее.

commentstatusdiv – метабокс с настройками обсуждения.

метабокс настройки обсуждения

commentsdiv – отображает комментарии к текущему посту.

метабокс с комментариями к записи

slugdiv – ярлык записи.

метабокс с ярлыком записи

revisiondiv – редакции записи.

метабокс редакций записи

authordiv – метабокс с автором поста.

метабокс автора записи

postcustom – метабокс управления произвольными полями.

меабокс управления произвольными полями WordPress
Кстати, о том, как добавить счётчик просмотров, я показывал в видеоуроке.

postexcerpt – метабокс с отрывком записи.

Метабокс отрывка записи

trackbackdiv – обратные ссылки.

метабокс с обратными ссылками

categorydiv – Рубрики записи.

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

tagsdiv-post_tag – Метки записи.

метабокс меток записи
Точно так же выглядят метабоксы любой таксономии без иерархии.

postimagediv – метабокс с изображением записи.

метабокс изображения записи

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

метабокс с атрибутами страницы

formatdiv – метабокс с форматами записи.

метабокс с форматами записей

submitdiv – блок с кнопкой «опубликовать».

метабокс с кнопкой опубликовать
Да, этот метабокс тоже можно удалить и вместо него добавить что-то своё!

Создание собственного метабокса

Прежде, чем мы приступим к созданию своего прекрасного SEO-метабокса, хочу также обратить ваше внимание, что мы можем управлять тем, какие стандартные метабоксы отображаются для определённых типов постов, например мы можем задать это при регистрации функцией register_post_type(), или же добавить функциями register_taxonomy_for_object_type() или add_post_type_support().

Ну погнали.

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

SEO метабокс с полями

1. Регистрация метабокса функцией add_meta_box()

Начнём с функции add_meta_box(), про которую вы кстати можете почитать отдельно у меня на блоге. Единственный момент – вы не можете использовать эту функцию внутри functions.php напрямую, вам понадобится либо повесить её на хук admin_menu, либо на add_meta_boxes.

add_action( 'add_meta_boxes', 'true_add_metabox' );
 
function true_add_metabox() {
 
	add_meta_box(
		'seo_metabox', // ID нашего метабокса
		'SEO настройки поста', // заголовок
		'seo_metabox_callback', // функция, которая будет выводить поля в мета боксе
		'page', // типы постов, для которых его подключим
		'normal', // расположение (normal, side, advanced)
		'default' // приоритет (default, low, high, core)
	);
 
}
 
function seo_metabox_callback( $post ) {
 
	echo 'приветик';
 
}

После вставки этого кода, надеюсь вы знаете куда, у нас получается следующее:

Создание SEO-метабокса в WordPress
Ну и как видно на скриншоте, функция seo_metabox_callback() выводит сообщение «приветик» и больше ничего.

2. Добавляем поля в метабокс

Теперь давайте попробуем вывести в метабоксе нечто большее, чем просто «приветик». Например я бы добавил обычное текстовое поле с SEO-заголовком поста и чекбокс для скрытия его от поисковиков.

function seo_metabox_callback( $post ) {
 
	// сначала получаем значения этих полей
	// заголовок
	$seo_title = get_post_meta( $post->ID, 'seo_title', true );
	// скрытие от поисковиков
	$seo_robots = get_post_meta( $post->ID, 'seo_robots', true );
 
	// одноразовые числа, кстати тут нет супер-большой необходимости их использовать
	wp_nonce_field( 'seopostsettingsupdate-' . $post->ID, '_truenonce' );
 
	echo '<table class="form-table">
		<tbody>
			<tr>
				<th><label for="seo_title">SEO-заголовок</label></th>
				<td><input type="text" id="seo_title" name="seo_title" value="' . esc_attr( $seo_title ) . '" class="regular-text"></td>
			</tr>
			<tr>
				<th>Скрыть из поисковиков</th>
				<td>
					<label><input type="checkbox" name="seo_robots" ' . checked( 'yes', $seo_robots, false ) . ' /> Да</label>
				</td>
			</tr>
		</tbody>
	</table>';
 
}

Во-первых, вот как станет выглядеть наш метабокс, после того, как вы измените содержимое callback-функции.

SEO метабокс с полями

Во-вторых, есть несколько комментариев относительно кода:

  • Для получения значений полей из базы данных мы используем самую обычную функцию для работы с произвольными полямиget_post_meta().
  • Также я добавил nonce-проверку функцией wp_nonce_field(). Я не считаю это 100% обязательным действием в данном контексте, но про одноразовые числа nonce вы можете почитать в отдельном уроке.
  • Не забываем очищать получаемые значения из базы данных! Функцию esc_attr() я использовал перед тем, как выводить значение в качестве HTML-атрибута.
  • Функция checked() нужно для автоматического вывода checked=»checked» в поле, если два значения совпадают. Я решил использовать значение «yes», означающее отмеченный чекбокс, подробнее в следующем шаге.

3. Сохранение значений полей метабокса

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

Создание полей в Gutenberg и то не требует столько кода, убедитесь это, посмотрев мой видеокурс по ним.

add_action( 'save_post', 'true_save_meta', 10, 2 );
 
function true_save_meta( $post_id, $post ) {
 
	// проверка одноразовых полей
	if ( ! isset( $_POST[ '_truenonce' ] ) || ! wp_verify_nonce( $_POST[ '_truenonce' ], 'seopostsettingsupdate-' . $post->ID ) ) {
		return $post_id;
	}
 
	// проверяем, может ли текущий юзер редактировать пост
	$post_type = get_post_type_object( $post->post_type );
 
	if ( ! current_user_can( $post_type->cap->edit_post, $post_id ) ) {
		return $post_id;
	}
 
	// ничего не делаем для автосохранений
	if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) {
		return $post_id;
	}
 
	// проверяем тип записи
	if( 'page' !== $post->post_type ) {
		return $post_id;
	}
 
	if( isset( $_POST[ 'seo_title' ] ) ) {
		update_post_meta( $post_id, 'seo_title', sanitize_text_field( $_POST[ 'seo_title' ] ) );
	} else {
		delete_post_meta( $post_id, 'seo_title' );
	}
	if( isset( $_POST[ 'seo_robots' ] ) && 'on' == $_POST[ 'seo_robots' ] ) {
		update_post_meta( $post_id, 'seo_robots', 'yes' );
	} else {
		delete_post_meta( $post_id, 'seo_robots' );
	}
 
	return $post_id;
 
}

4. Вывод полей на сайте

Для этого мы будем всего лишь использовать функцию get_post_meta(). Получается, нам нужно вывести SEO-тайтл, если он существует и мета-тег роботс.

С SEO-тайтлом лучше всего воспользоваться хуком pre_get_document_title. Также я добавил условие is_page(), ведь наш метабокс и так выводится только для страниц.

add_filter( 'pre_get_document_title', 'true_seo_title', 25 );
 
function true_seo_title(){
 
	if( is_page() && ( $title = get_post_meta( get_the_ID(), 'seo_title', true ) ) ) {
		return $title;
	}
 
	return '';
 
}

Что же делаем с метатегов robots? Думаю, что сгодится хук wp_head, но тут лучше прочекать, как устроена ваша тема.

add_action( 'wp_head', 'true_seo_robots', 25 );
 
function true_seo_robots() {
 
	if( ! is_page() ) {
		return;
	}
 
	if( 'yes' === get_post_meta( get_the_ID(), 'seo_robots', true ) ) {
		echo '<meta name="robots" content="noindex,nofollow" />';
	}
}

Делаем то же самое при помощи Carbon Fields

Я уже говорил, что каждый раз писать весь этот код в некоторых ситуациях может быть нецелесообразно и неэффективно по времени. Поэтому хочу обратить ваше внимание на код, который создаёт точно такой же метабокс при помощи бесплатного плагина Carbon Fields, вот кстати руководство по нему.

use Carbon_Fields\Container;
use Carbon_Fields\Field;
 
add_action( 'carbon_fields_register_fields', 'truemisha_carbon_seo' );
function truemisha_carbon_seo() {
 
	Container::make( 'post_meta', 'SEO настройки поста' )
		->where( 'post_type', '=', 'page' )
		->add_fields( array( 
 
			Field::make( 'text', 'seo_title', 'SEO-заголовок' ),
			Field::make( 'checkbox', 'seo_robots', 'Скрыть из поисковиков' )->set_option_value( 'yes' )
 
		) );
 
}

Это весь код. Чтоооо?

И ещё раз напомню про мой видеокурс по мета-полям в Gutenberg.

Миша

Впервые познакомился с WordPress в 2009 году. Организатор и спикер на конференциях WordCamp. Преподаватель в школе Нетология.

Пишите, если нужна помощь с сайтом или разработка с нуля.

Комментарии — 168

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

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

Полезности из мира WordPress и жизни студии.

Мой телеграм-канал