WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru

add_meta_box() WP 2.5.0

Добавляет дополнительные блоки (meta box) на страницы редактирования/создания постов, постоянных страниц или произвольных типов записей в админ-панели.

Нужно вызывать на хуке add_meta_boxes.

Используйте wp_add_dashboard_widget(), чтобы добавить метабокс на странице админ-панели «Консоль», «Консоль мультисайта».

Все зарегистрированные данные находятся в глобальном массиве $wp_meta_boxes, который содержит многомерный массив всех зарегистрированных метабоксов. Содержит их ID, параметры (args), функции обратного вызова (callback) и заголовки всех типов записей, включая произвольные.

Гутенберг

Отключение Gutenberg редактора через метабокс

Если метабокс не работает с Гутенберг, и обновить его для работы с ним невозможно, то через метабокс можно отключить Gutenberg редактор.

Для этого нужно передать аргумент __block_editor_compatible_meta_box = false в параметр $callback_args (параметры передаваемые колбэк функции). После этого WordPress вернется к классическому редактору с привычным метабоксом:

add_meta_box( 'my-meta-box', 'My Meta Box', 'my_meta_box_callback', null, 'normal', 'high',
	array(
		'__block_editor_compatible_meta_box' => false,
	)
);

Поддержка Gutenberg редактора

Когда метабокс полностью поддерживает редактор блоков Gutenberg, можно отключить поддержку классического редактора, добавив аргумент __back_compat_meta_box = false. Теперь, когда используется гутенберг, этот метабокс больше не будет отображаться в области метабоксов, так как теперь он существует только для обратной совместимости. Но он по прежнему будет отображаться в Классическом редакторе (если гутенберг вдруг отключен).

add_meta_box( 'my-meta-box', 'My Meta Box', 'my_meta_box_callback', null, 'normal',  'high', 
   array(
		'__back_compat_meta_box' => false,
	)
);

Хуков нет.

Возвращает

Ничего не возвращает.

Использование

add_meta_box( $id, $title, $callback, $screen, $context, $priority, $callback_args );
$id(строка) (обязательный)
id атрибут HTML тега, контейнера блока.
По умолчанию: нет
$title(строка) (обязательный)
Заголовок/название блока. Виден пользователям.
По умолчанию: нет
$callback(строка) (обязательный)

Функция, которая выводит на экран HTML содержание блока. Должна выводить результат на экран.

Получает объект поста в качестве первого параметра.

По умолчанию: нет

$screen(строка/массив/WP_Screen)

Название экрана для которого добавляется блок. Смотрите get_current_screen(). Например может быть:

  • Для типов записей: post, page, link, attachment или custom_post_type
  • Или для других страниц админки: link, comment.
  • Можно указать несколько типов в массиве: array('post', 'page'). C версии 4.4.

По умолчанию: null (текущий экран)

$context(строка)
Место где должен показываться блок: normal, advanced или side.
По умолчанию: 'advanced'
$priority(строка)
Приоритет блока для показа выше или ниже остальных блоков: high или low. Также можно указать core, default.
По умолчанию: 'default'
$callback_args(массив)

Аргументы, которые нужно передать в callback функцию указанную в параметре $callback. callback функция получит данные поста (объект $post) и аргументы переданные в этом параметре.

По умолчанию: null

Примеры

#1 Метабокс для постов и страниц

Пример добавления произвольного блока на страницы редактирования/создания постов и постоянных страниц:

## Добавляем блоки в основную колонку на страницах постов и пост. страниц
add_action('add_meta_boxes', 'myplugin_add_custom_box');
function myplugin_add_custom_box(){
	$screens = array( 'post', 'page' );
	add_meta_box( 'myplugin_sectionid', 'Название мета блока', 'myplugin_meta_box_callback', $screens );
}

// HTML код блока
function myplugin_meta_box_callback( $post, $meta ){
	$screens = $meta['args'];

	// Используем nonce для верификации
	wp_nonce_field( plugin_basename(__FILE__), 'myplugin_noncename' );

	// Поля формы для введения данных
	echo '<label for="myplugin_new_field">' . __("Description for this field", 'myplugin_textdomain' ) . '</label> ';
	echo '<input type="text" id= "myplugin_new_field" name="myplugin_new_field" value="whatever" size="25" />';
}

## Сохраняем данные, когда пост сохраняется
add_action( 'save_post', 'myplugin_save_postdata' );
function myplugin_save_postdata( $post_id ) {
	// Убедимся что поле установлено.
	if ( ! isset( $_POST['myplugin_new_field'] ) )
		return;

	// проверяем nonce нашей страницы, потому что save_post может быть вызван с другого места.
	if ( ! wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename(__FILE__) ) )
		return;

	// если это автосохранение ничего не делаем
	if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
		return;

	// проверяем права юзера
	if( ! current_user_can( 'edit_post', $post_id ) )
		return;

	// Все ОК. Теперь, нужно найти и сохранить данные
	// Очищаем значение поля input.
	$my_data = sanitize_text_field( $_POST['myplugin_new_field'] );

	// Обновляем данные в базе данных.
	update_post_meta( $post_id, '_my_meta_value_key', $my_data );
}

#2 Новая вкладка аккордеона (метабокс в меню аккордеона)

Этот пример показывает, как добавить дополнительный элемент аккордеона на странице настроек меню WordPress.

<?php
add_action( 'admin_head-nav-menus.php', 'register_my_meta_box_accordion_nav_menus' );
function register_my_meta_box_accordion_nav_menus() {
	add_meta_box( 'my-custom-meta-box', 'Мой метабокс', 'render_my_meta_box_accordion_nav_menus', 'nav-menus', 'side' );
}

function render_my_meta_box_accordion_nav_menus() {
	?>
	<div class="my-custom-meta-box" id="my-custom-meta-box">
		Контент метабокса
	</div>
	<?php
}

Получим:

#2.1 Вкладка аккордеона с контентом (рабочий код)

Готовый код, который добавляет новый элемент в меню навигации (в аккордион) и заполняет его, давая возможность выбрать элемент медиабиблиотке (файл, картинку) и добавить его в меню:

<?php
/**
 * Регистрация и добавление вкладки в аккардионе для созданию меню
 *
 * @link https://gist.github.com/nikolov-tmw/8698598
 */
add_action( 'admin_head-nav-menus.php', 'register_menu_files_metabox' );
function register_menu_files_metabox() {
	add_meta_box( 'menu-media-files-metabox', 'Файлы', 'render_menu_files_metabox', 'nav-menus', 'side', 'default' );
}

/**
 * Вывод на экран метабокса "Файлы"
 *
 * @param string $object Не используется.
 * @param array  $args   Параметры и аргументы.
 */
function render_menu_files_metabox( $object, $args ) {
	global $nav_menu_selected_id;
	$files_ext = [ 'xlsx', 'pdf', 'zip' ];

	$my_items = get_posts( [
		'numberposts'    => - 1,
		'post_type'      => 'attachment',
		'post_mime_type' => get_mime_files_extension( $files_ext ),
	] );

	$walker       = new Walker_Nav_Menu_Checklist();
	$removed_args = [
		'action',
		'customlink-tab',
		'edit-menu-item',
		'menu-item',
		'page-tab',
		'_wpnonce',
	]; ?>
	<div id="tab-files-div">
	<div id="tabs-panel-list-files" class="tabs-panel tabs-panel-active">
		<p>Отображаются только файлы с расширением <b><?php echo implode( ', ', $files_ext ); ?></b>.</p>

		<ul id="tab-files-checklist-pop" class="categorychecklist form-no-clear">
			<?php echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $my_items ), 0, (object) [ 'walker' => $walker ] ); ?>
		</ul>

		<p class="button-controls">
			<span class="list-controls">
				<a href="<?php
				echo esc_url( add_query_arg(
					[
						'list-files' => 'all',
						'selectall'  => 1,
					],
					remove_query_arg( $removed_args )
				) );
				?>#menu-media-files-metabox" class="select-all"><?php _e( 'Select All' ); ?></a>
			</span>

			<span class="add-to-menu">
				<input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?>
					   class="button-secondary submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>"
					   name="add-tab-files-menu-item" id="submit-tab-files-div"/>
				<span class="spinner"></span>
			</span>
		</p>
	</div>
	<?php
}

/**
 * Возвращает mime типы расширений файлов
 *
 * @param array $files_ext расширения файлов
 *
 * @return array
 */
function get_mime_files_extension( $files_ext ) {

	// Получает список разрешенных mime типов.
	$mimes = get_allowed_mime_types();

	// Поиск mime типа в массиве расширений.
	$need_mimes = [];
	foreach ( $files_ext as $file_ext ) {
		foreach ( $mimes as $type => $mime ) {
			if ( false !== strpos( $type, $file_ext ) ) {
				$need_mimes[] = $mime;
			}
		}
	}

	return $need_mimes;
}

/**
 * Заменяет ссылку на страницу медиафайла ссылкой на сам медиафайл
 *
 * @param string $link    ссылка на страницу медиафайла
 * @param string $post_id ID медиафайла
 *
 * @return string
 */
add_filter( 'attachment_link', 'change_attachment_link', 1000, 2 );
function change_attachment_link( $link, $post_id ) {
	return wp_get_attachment_url( $post_id );
}

Получим:

Новая вкладка аккордеона с добавление медиафайла

Основа взята из файла custom-menu-panel.php, найденного на просторах github и реализующий добавления кастомных объектов для списка.

#3 Класс PHP

Этот пример показывает, как добавить дополнительный блок в стиле ООП:

/**
 * Вызываем класс на странице редактирования поста.
 */
function call_someClass() {
	new someClass();
}

if ( is_admin() ) {
	add_action( 'load-post.php', 'call_someClass' );
	add_action( 'load-post-new.php', 'call_someClass' );
}

class someClass {

	/**
	 * Устанавливаем хуки в момент инициализации класса.
	 */
	public function __construct() {
		add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
		add_action( 'save_post', array( $this, 'save' ) );
	}

	/**
	 * Добавляем дополнительный блок.
	 */
	public function add_meta_box( $post_type ){

			// Устанавливаем типы постов к которым будет добавлен блок
			$post_types = array('post', 'page');

			if ( in_array( $post_type, $post_types )) {
				add_meta_box(
					'some_meta_box_name',
					__( 'Some Meta Box Headline', 'myplugin_textdomain' ),
					array( $this, 'render_meta_box_content' ),
					$post_type,
					'advanced',
					'high',
				);
			}
	}

	/**
	 * Сохраняем данные при сохранении поста.
	 *
	 * @param int $post_id ID поста, который сохраняется.
	 */
	public function save( $post_id ) {

		/*
		 * Нам нужно сделать проверку, чтобы убедится что запрос пришел с нашей страницы,
		 * потому что save_post может быть вызван еще где угодно.
		 */

		// Проверяем установлен ли nonce.
		if ( ! isset( $_POST['myplugin_inner_custom_box_nonce'] ) )
			return $post_id;

		$nonce = $_POST['myplugin_inner_custom_box_nonce'];

		// Проверяем корректен ли nonce.
		if ( ! wp_verify_nonce( $nonce, 'myplugin_inner_custom_box' ) )
			return $post_id;

		// Если это автосохранение ничего не делаем.
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
			return $post_id;

		// Проверяем права пользователя.
		if ( 'page' == $_POST['post_type'] ) {

			if ( ! current_user_can( 'edit_page', $post_id ) )
				return $post_id;

		} else {

			if ( ! current_user_can( 'edit_post', $post_id ) )
				return $post_id;
		}

		// OK, все чисто, можно сохранять данные.

		// Очищаем поле input.
		$mydata = sanitize_text_field( $_POST['myplugin_new_field'] );

		// Обновляем данные.
		update_post_meta( $post_id, '_my_meta_value_key', $mydata );
	}

	/**
	 * Код дополнительного блока.
	 *
	 * @param WP_Post $post Объект поста.
	 */
	public function render_meta_box_content( $post ) {

		// Добавляем nonce поле, которое будем проверять при сохранении.
		wp_nonce_field( 'myplugin_inner_custom_box', 'myplugin_inner_custom_box_nonce' );

		// Получаем существующие данные из базы данных.
		$value = get_post_meta( $post->ID, '_my_meta_value_key', true );

		// Выводим поля формы, используя полученные данные.
		echo '<label for="myplugin_new_field">';
		echo __( 'Description for this field', 'myplugin_textdomain' );
		echo '</label> ';
		echo '<input type="text" id="myplugin_new_field" name="myplugin_new_field"';
		echo ' value="' . esc_attr( $value ) . '" size="25" />';
	}

}

#4 Использование параметра $callback_args

В первом параметре передаются другие данные записи (массив $_POST).

Во втором массив аргументов $callback_args.

// Эта функция добавляет Блок который передает доп. параметры `callback` функции my_metabox_callback()
function add_my_meta_box() {
	$var1 = "this";
	$var2 = "that";
	$callback_args = array( 'foo'=>$var1,'bar'=>$var2 );
	add_meta_box( 'metabox_id', 'Metabox Title', 'my_metabox_callback', 'page', 'normal', 'low', $callback_args );
}

// $post - это объект содержащий данные глобального массива $_POST
// $metabox - это массив с агрументами: metabox_id, title, callback 
// и новыми переданными аргументами в параметре $callback_args 
function my_metabox_callback( $post, $metabox ){

	echo 'Last Modified: ' . $post->post_modified; // время последнего изменения поста
	echo $metabox['args']['foo']; // раз
	echo $metabox['args']['bar']; // два
	echo get_post_meta( $post->ID, 'my_custom_field', true ); // значение произвольно поля

}

Код add meta box: wp-admin/includes/template.php WP 5.2.1

<?php
function add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null ) {
	global $wp_meta_boxes;

	if ( empty( $screen ) ) {
		$screen = get_current_screen();
	} elseif ( is_string( $screen ) ) {
		$screen = convert_to_screen( $screen );
	} elseif ( is_array( $screen ) ) {
		foreach ( $screen as $single_screen ) {
			add_meta_box( $id, $title, $callback, $single_screen, $context, $priority, $callback_args );
		}
	}

	if ( ! isset( $screen->id ) ) {
		return;
	}

	$page = $screen->id;

	if ( ! isset( $wp_meta_boxes ) ) {
		$wp_meta_boxes = array();
	}
	if ( ! isset( $wp_meta_boxes[ $page ] ) ) {
		$wp_meta_boxes[ $page ] = array();
	}
	if ( ! isset( $wp_meta_boxes[ $page ][ $context ] ) ) {
		$wp_meta_boxes[ $page ][ $context ] = array();
	}

	foreach ( array_keys( $wp_meta_boxes[ $page ] ) as $a_context ) {
		foreach ( array( 'high', 'core', 'default', 'low' ) as $a_priority ) {
			if ( ! isset( $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ] ) ) {
				continue;
			}

			// If a core box was previously added or removed by a plugin, don't add.
			if ( 'core' == $priority ) {
				// If core box previously deleted, don't add
				if ( false === $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ] ) {
					return;
				}

				/*
				 * If box was added with default priority, give it core priority to
				 * maintain sort order.
				 */
				if ( 'default' == $a_priority ) {
					$wp_meta_boxes[ $page ][ $a_context ]['core'][ $id ] = $wp_meta_boxes[ $page ][ $a_context ]['default'][ $id ];
					unset( $wp_meta_boxes[ $page ][ $a_context ]['default'][ $id ] );
				}
				return;
			}
			// If no priority given and id already present, use existing priority.
			if ( empty( $priority ) ) {
				$priority = $a_priority;
				/*
				* Else, if we're adding to the sorted priority, we don't know the title
				* or callback. Grab them from the previously added context/priority.
				*/
			} elseif ( 'sorted' == $priority ) {
				$title         = $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ]['title'];
				$callback      = $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ]['callback'];
				$callback_args = $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ]['args'];
			}
			// An id can be in only one priority and one context.
			if ( $priority != $a_priority || $context != $a_context ) {
				unset( $wp_meta_boxes[ $page ][ $a_context ][ $a_priority ][ $id ] );
			}
		}
	}

	if ( empty( $priority ) ) {
		$priority = 'low';
	}

	if ( ! isset( $wp_meta_boxes[ $page ][ $context ][ $priority ] ) ) {
		$wp_meta_boxes[ $page ][ $context ][ $priority ] = array();
	}

	$wp_meta_boxes[ $page ][ $context ][ $priority ][ $id ] = array(
		'id'       => $id,
		'title'    => $title,
		'callback' => $callback,
		'args'     => $callback_args,
	);
}

Cвязанные функции

Из метки: metabox (метабоксы виджеты)

Еще из раздела: Админ-панель

39 комментов
Полезные 2 Вопросы 2 Все
  • Роман cайт: cdelayremont.ru

    караул, не работает админка wp
    пишет после ввода логина и пароля
    Fatal error: Call to undefined function convert_to_screen() in /home/p46318/www/***.ru/wp-admin/includes/deprecated.php on line 880

    function add_contextual_help( $screen, $help ) {
    _deprecated_function( __FUNCTION__, '3.3', 'get_current_screen()->add_help_tab()' );

    if ( is_string( $screen ) )
    $screen = convert_to_screen( $screen );/ошибка тут/

    WP_Screen::add_old_compat_help( $screen, $help );
    }
    прошу Вас помощи, как специалиста wpsmile
    по яндексу Вы первый по запросу function convert_to_screen laugh
    буду очень благодарен, если поможете
    подписался на Ваш блог

    Ответить7.1 лет назад #
    • Kama7482

      А что делали то, с чего вдруг ошибка появилась? Функция convert_to_screen была отменена судя по всему, от сюда PHP ошибка. Надо убрать использование этой функции каким-то образом.

      П.С. я не специалист по WP smile

      Ответить7.1 лет назад #
  • Роман cайт: cdelayremont.ru

    только обновил WP, ну и меню поредактировал (увеличил в размере)
    переустановка движка думаете поможет?
    ну раз ведёте блог по wp, то явно понимаете больше остальныхsmile

    Ответить7.1 лет назад #
  • Nik

    При обновлении в полях формы почему-то не сохраняется введеный текст (поле остается пустым). Подскажите, пожалуйста, как сделать чтобы он сохранялся. Можно на примере этой строчки echo ''; Так же хотелось бы узнать каким образом выводить в шаблоне текст из полей? Скажем я создам поле для заголовка, который нужно будет вывести на главной страничке.

    2
    Ответить7 лет назад #
  • Кирилл

    Замечательная функция, а вот чтобы добавить дополнительные блоки на страницу редактирования тегов... Есть такая функция? А то не могу найти.

    Ответить4.5 года назад #
    • Kama7482

      Функции нет, есть хуки.

      Добавление полей

      add_action( '(taxonomy)_edit_form_fields', 'callback_function', 10, 2);
      function callback_function(){
      	echo 'Дополнительные поля';
      }

      Вот еще код для добавки полей:

      <?php
      add_action('(taxonomy)_edit_form_fields','category_edit_form_fields');
      add_action('(taxonomy)_edit_form', 'category_edit_form');
      add_action('(taxonomy)_add_form_fields','category_edit_form_fields');
      add_action('(taxonomy)_add_form','category_edit_form');
      
      function category_edit_form() {
      ?>
      <script type="text/javascript">
      jQuery(document).ready(function(){
      jQuery('#edittag').attr( "enctype", "multipart/form-data" ).attr( "encoding", "multipart/form-data" );
      		});
      </script>
      <?php 
      }
      
      function category_edit_form_fields () {
      	?>
      	<tr class="form-field">
      	   <th valign="top" scope="row">
      		   <label for="catpic"><?php _e('Picture of the category', ''); ?></label>
      	   </th>
      	   <td>
      		   <input type="file" id="catpic" name="catpic"/>
      	   </td>
      	</tr>
      	<?php 
      }

      Сохранение полей

      add_action( 'edited_(taxonomy)', 'save_extra_fields_callback', 10, 2);

      Во всех хуках поменяйте (taxonomy) на название вашей таксономии. У меток она называется 'post_tag'.

      Ответить4.5 года назад #
  • adward6 cайт: cimetrica.ru

    Если просто скопипастить самый верхний кусок кода в function.php
    ТО выводится ошибка при добавлении поста

    http://f5.s.qip.ru/FaNZtpQf.png

    Ответить4.5 года назад #
    • Kama7482

      Спасибо за коммент, в коде была ошибка myplugin_meta_box_callback() назвалась иначе, поправил.

      Ответить4.5 года назад #
  • Темур cайт: maejor-system.ru

    Вставил! Все буквы превратились в вопросики. Что делать?

    1
    Ответить4.5 года назад #
    • Темур cайт: maejor-system.ru

      AddDefaultCharset utf-8 в htaccess))

      Ответить4.5 года назад #
      • Темур cайт: maejor-system.ru

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

        Ответить4.5 года назад #
    • Виталий

      кодировать файл в UTF-8 без BOM

      Ответить3.4 года назад #
  • m4gz

    Было бы замечательно если бы вы объединили эти примеры в один плагин, с которым можно было бы играться, а так очень полезная информация, спасибо что вы есть thank_you

    Ответить4.2 года назад #
    • Kama7482

      Это выходит далеко за рамки этой заметки. И собственно для этого уже есть плагины (ACF), но они разумеется комбайны, а по другому там никак.

      Ответить4.2 года назад #
  • Привет. Всё никак не могу взять в толк
    public function add_meta_box( $post_type )
    Вот откуда тут берётся $post_type? как вообще узнавать, какие параметры теоретически могут находиться в функциях и методах классов?

    Ответить2.8 года назад #
    • Kama7482

      Эта функция цепляется на хук add_meta_boxes, который передает параметр $post_type - от туда и берется, его хук передает в функцию (в данном случае в метод).

      add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
      Ответить2.8 года назад #
  • Артем

    Привет, Kama!
    Можешь, пожалуйста, подсказать как из созданного метабокса в админке выводить прописанный текст в нужном мне месте?
    В functions.php прописал:

    function wph_add_metabox($id, $callback){
    	add_meta_box('before_publish', 'Дата мероприятия', 
    	'wph_metabox_content', 'post', 'side', 'high');
    }
    function wph_metabox_content() { ?>
    			<div>
    				<input type = "text" autocomplete="off" placeholder="<?php esc_attr_e( 'Укажите дату' , THEME_NAME );?>" />
    			</div>
    
    <?php }
    add_action('add_meta_boxes', 'wph_add_metabox');

    Как теперь вывести текст (из дива) в нужное мне место на сайте?

    Ответить2.6 года назад #
    • stepan1188 cайт: www.weblancer.net/users/stepanko/?affili...

      А Вы сначала сохраните текст из дива в таблицу wp_postmeta
      То есть, нужно добавить свой код, который при срабатывании хука save_post будет сохранять данные из дива в post_meta

      update_post_meta( $post-ID, 'field_name', 1 );
      Ответить2.6 года назад #
  • Виктор

    Такой вот код:

    function my_template_box() {
    	add_meta_box( 'my_box_id', 'Заголовок', 'my_template_box_callback', 'page', 'side', 'high' );
    }
    add_action('add_meta_boxes', 'my_template_box_callback');

    По началу было все отлично, метабокс выводился вверху справа в сайдбаре, но после он стал выводится внизу под контентом редактора, не смотря на то что прописан параметр 'side', в чём может быть причина данного явления?

    Ответить2.6 года назад #
    • Kama7482

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

      2
      Ответить2.6 года назад #
Здравствуйте, !     Войти . Зарегистрироваться