Как разместить произвольный метабокс между заголовком и редактором на странице редактирования записи?
У меня есть произвольный метабокс для пользовательского типа записи, который клиент хочет разместить между секцией заголовка/постоянной ссылки и редактором записи в панели администратора. Возможно ли это, и если да, какой хук/фильтр/и т.д. мне нужно использовать?

- Просто добавьте метабокс, используя контекст advanced и приоритет high
- Затем подключитесь к хуку
edit_form_after_title
Выведите ваши метабоксы в этом месте, а затем удалите их, чтобы они не отображались дважды.
// Перемещаем все "advanced" метабоксы выше стандартного редактора add_action('edit_form_after_title', function() { global $post, $wp_meta_boxes; do_meta_boxes(get_current_screen(), 'advanced', $post); unset($wp_meta_boxes[get_post_type($post)]['advanced']); });

Над сайтом, над которым я работаю, регистрируются несколько метабоксов с использованием параметра register_meta_box_cb
функции register_post_type
. Я попробовал ваш код, но метабоксы не перемещаются выше редактора. Можно ли использовать этот подход в моем случае? Спасибо.

Я бы рекомендовал использовать пользовательский $context
вместо advanced
, например my_before_editor
, чтобы вы не перемещали все метабоксы в контексте advanced
, а конкретно нацеливались на нужные вам метабоксы... см. https://developer.wordpress.org/reference/functions/add_meta_box/

edit_form_after_title
не поддерживается блок-редактором https://github.com/WordPress/gutenberg/issues/5821

Вот как можно переместить определенные метабоксы над редактором, но прежде чем опубликовать код, я хотел бы поблагодарить Эндрю и mhulse. Ребята, вы крутые!
function foo_deck( $post_type ) {
// Проверяем, относится ли тип записи к постам или страницам
if ( in_array( $post_type, array( 'post', 'page' ) ) ) {
add_meta_box(
'contact_details_meta', // ID метабокса
'Контактные данные', // Заголовок метабокса
'contact_details_meta', // Функция обратного вызова
$post_type, // Тип записи
'test', // Контекст (изменяем на что-то отличное от normal, advanced или side)
'high' // Приоритет
);
}
}
// Добавляем метабокс при загрузке страницы редактирования
add_action('add_meta_boxes', 'foo_deck');
function foo_move_deck() {
// Получаем глобальные переменные
global $post, $wp_meta_boxes;
// Выводим метабоксы с контекстом 'test'
do_meta_boxes( get_current_screen(), 'test', $post );
// Удаляем исходные метабоксы с контекстом 'test'
unset($wp_meta_boxes['post']['test']);
}
// Перемещаем метабоксы после заголовка записи
add_action('edit_form_after_title', 'foo_move_deck');

Чтобы предоставить полный пример кода на основе ответа Эндрю... Мне нужен был способ добавить "Декабрь" (подзаголовок) к моим записям; я хотел, чтобы поле декабря появлялось после основной строки заголовка.
/**
* Добавляет метабокс "Декабрь" (подзаголовок) на страницу(ы) записи и позиционирует его
* под заголовком.
*
* @todo Перенести в класс.
* @see http://codex.wordpress.org/Function_Reference/add_meta_box
* @see http://wordpress.org/extend/ideas/topic/add-meta-box-to-multiple-post-types
* @see https://github.com/Horttcore/WordPress-Subtitle
* @see http://codex.wordpress.org/Function_Reference/wp_nonce_field
*/
# Добавляет блок в основную колонку на экранах редактирования Записи и Страницы:
function foo_deck($post_type) {
# Разрешенные типы записей для отображения метабокса:
$post_types = array('post', 'page');
if (in_array($post_type, $post_types)) {
# Добавляем метабокс в административный интерфейс:
add_meta_box(
'foo-deck-meta-box', // HTML атрибут 'id' секции редактирования.
'Декабрь', // Заголовок секции редактирования, видимый пользователю.
'foo_deck_meta_box', // Функция, выводящая HTML для секции редактирования.
$post_type, // Тип экрана редактирования, на котором показывать секцию.
'advanced', // Часть страницы, где должна отображаться секция.
'high' // Приоритет в контексте отображения блоков.
);
}
}
# Функция обратного вызова, выводящая содержимое блока:
function foo_deck_meta_box($post) {
# Используем `get_post_meta()` для получения существующего значения из базы данных и используем его для формы:
$deck = get_post_meta($post->ID, '_deck', true);
# Поле формы для отображения:
?>
<label class="screen-reader-text" for="foo_deck">Декабрь</label>
<input id="foo_deck" type="text" autocomplete="off" value="<?=esc_attr($deck)?>" name="foo_deck" placeholder="Декабрь">
<?php
# Отображаем скрытое поле nonce:
wp_nonce_field(
plugin_basename(__FILE__), // Название действия.
'foo_deck_meta_box' // Название nonce.
);
}
/**
* @see https://wordpress.stackexchange.com/a/16267/32387
*/
# Сохраняем пользовательские данные при сохранении записи:
function foo_deck_save_postdata($post_id) {
# Имеет ли текущий пользователь право выполнять это действие?
if ((($_POST['post_type'] === 'page') && current_user_can('edit_page', $post_id) || current_user_can('edit_post', $post_id))) { // Если это страница, ИЛИ, если это запись, может ли пользователь ее редактировать?
# Препятствуем WP очищать пользовательские поля при автосохранении:
if ((( ! defined('DOING_AUTOSAVE')) || ( ! DOING_AUTOSAVE)) && (( ! defined('DOING_AJAX')) || ( ! DOING_AJAX))) {
# Проверка nonce:
if (wp_verify_nonce($_POST['foo_deck_meta_box'], plugin_basename(__FILE__))) {
# Получаем отправленный декабрь:
$deck = sanitize_text_field($_POST['foo_deck']);
# Добавить, обновить или удалить?
if ($deck !== '') {
# Декабрь существует, поэтому добавляем ИЛИ обновляем его:
add_post_meta($post_id, '_deck', $deck, true) OR update_post_meta($post_id, '_deck', $deck);
} else {
# Декабрь пуст или удален:
delete_post_meta($post_id, '_deck');
}
}
}
}
}
# Получаем декабрь:
function foo_get_deck($post_id = FALSE) {
$post_id = ($post_id) ? $post_id : get_the_ID();
return apply_filters('foo_the_deck', get_post_meta($post_id, '_deck', TRUE));
}
# Отображаем декабрь (это будет выглядеть лучше при ООП):
function foo_the_deck() {
echo foo_get_deck(get_the_ID());
}
# Проверка условия:
function foo_has_subtitle($post_id = FALSE) {
if (foo_get_deck($post_id)) return TRUE;
}
# Определяем пользовательский блок:
add_action('add_meta_boxes', 'foo_deck');
# Делаем что-то с введенными данными:
add_action('save_post', 'foo_deck_save_postdata');
/**
* @see https://wordpress.stackexchange.com/questions/36600
* @see https://wordpress.stackexchange.com/questions/94530/
*/
# Теперь перемещаем расширенные метабоксы после заголовка:
function foo_move_deck() {
# Получаем глобальные переменные:
global $post, $wp_meta_boxes;
# Выводим "расширенные" метабоксы:
do_meta_boxes(get_current_screen(), 'advanced', $post);
# Удаляем изначальные "расширенные" метабоксы:
unset($wp_meta_boxes['post']['advanced']);
}
add_action('edit_form_after_title', 'foo_move_deck');
Очевидно, что приведенный выше код можно доработать, но он должен помочь другим, пытающимся сделать то же самое (ответ Эндрю пролил свет, но я подумал, что будет полезно предоставить рабочий пример).
Улучшения, которые можно сделать:
- Сделать ООП/класс(ы).
- Добавить стили/js, чтобы это выглядело/чувствовалось/работало как поле заголовка.
Я планирую сделать вышеуказанные улучшения в будущем, но, по крайней мере, приведенный выше код должен помочь другим, пытающимся разобраться в этом.
Смотрите исходный код здесь для большего вдохновения (они выбрали использование jQuery для перемещения "подзаголовка").

Если кому-то будет полезно, кто идет по тому же пути: я задал вопрос здесь, где есть некоторый связанный/похожий код (я решил использовать поле "title" для хранения и фильтрации подзаголовка).

Вместо того чтобы перемещать всё из расширенного раздела наверх, почему бы не создать новый раздел и поместить его в начало:
// Создаем раздел 'top' и перемещаем его в начало
add_action('edit_form_after_title', function() {
global $post, $wp_meta_boxes;
do_meta_boxes(get_current_screen(), 'top', $post);
unset($wp_meta_boxes[get_post_type($post)]['top']);
});
Теперь вам остаётся только зарегистрировать метабокс, используя top
для раздела и high
для приоритета.
Это работает в WordPress 4.4.2. Я не тестировал это в других версиях WP.

Есть и другой способ, с помощью которого мы можем разместить редактор в любом месте:
Удалить редактор из параметра support при регистрации типа записи post_type
Добавить фейковый метабокс
add_meta_box( 'does-not-matter', __( 'Описание'), function($post){ wp_editor($post->post_content,'post_content',array('name'=>'post_content')); }, 'post_type_type', 'advanced', 'high' );
