Metabox в WordPress — это мощный инструмент для добавления дополнительных полей к записям, страницам и пользовательским типам записей. Однако часто бывает необходимо не просто добавить несколько простых полей, а создать сложные формы с вложенной структурой, повторяющимися блоками и логикой. В этой статье мы подробно разберём, как создать такие комплексные метабоксы с помощью стандартных возможностей WordPress и минимального кода.
Что такое Metabox и зачем нужны комплексные формы
Metabox — это интерфейсный элемент в редакторе записи, который позволяет вводить дополнительные данные, сохраняемые в базе. Простые метабоксы содержат отдельные поля, например, текстовое поле или чекбокс. Но в реальных проектах часто требуется:
- Группировать поля по разделам.
- Создавать повторяющиеся блоки полей (например, список контактов, услуг, галерей).
- Использовать вложенные поля с разной логикой валидации и отображения.
Для таких задач нужно создавать более сложную структуру данных и интерфейс для удобного редактирования.
Создание метабокса с вложенными и повторяющимися полями
Начнём с регистрации метабокса. Для этого используем хук add_meta_boxes и функцию add_meta_box. Ниже показан пример, как добавить метабокс с повторяющимися группами полей:
add_action('add_meta_boxes', 'wpcoder_add_complex_metabox');
function wpcoder_add_complex_metabox() {
add_meta_box(
'wpcoder_complex_metabox',
'Комплексные данные',
'wpcoder_complex_metabox_callback',
'post',
'normal',
'high'
);
}
function wpcoder_complex_metabox_callback($post) {
wp_nonce_field('wpcoder_save_complex_metabox', 'wpcoder_complex_metabox_nonce');
$data = get_post_meta($post->ID, '_wpcoder_complex_data', true);
if (!is_array($data)) $data = [];
echo '<div id="wpcoder-repeatable-fields">';
if (empty($data)) {
$data[] = ['title' => '', 'description' => ''];
}
foreach ($data as $index => $item) {
echo '<div class="repeatable-block">';
echo '<p><label>Заголовок:</label><input type="text" name="wpcoder_data['.$index.'][title]" value="'.esc_attr($item['title']).'" style="width: 100%;"/></p>';
echo '<p><label>Описание:</label><textarea name="wpcoder_data['.$index.'][description]" rows="4" style="width: 100%;">'.esc_textarea($item['description']).'</textarea></p>';
echo '<p><button class="wpcoder-remove-block button" type="button">Удалить</button></p>';
echo '</div>';
}
echo '</div>';
echo '<p><button id="wpcoder-add-block" class="button" type="button">Добавить блок</button></p>';
// Подключим небольшой JS для динамического добавления/удаления
?>
<script>
jQuery(document).ready(function($){
$('#wpcoder-add-block').click(function(e){
e.preventDefault();
var container = $('#wpcoder-repeatable-fields');
var index = container.children('.repeatable-block').length;
var block = `
<div class="repeatable-block">
<p><label>Заголовок:</label><input type="text" name="wpcoder_data[${index}][title]" style="width: 100%;" /></p>
<p><label>Описание:</label><textarea name="wpcoder_data[${index}][description]" rows="4" style="width: 100%;"></textarea></p>
<p><button class="wpcoder-remove-block button" type="button">Удалить</button></p>
</div>
`;
container.append(block);
});
$(document).on('click', '.wpcoder-remove-block', function(){
$(this).closest('.repeatable-block').remove();
});
});
</script>
<?php
}
Сохранение данных сложного метабокса
Для сохранения данных нужно обработать POST-запрос, проверить nonce и права пользователя. Данные придут в виде массива, который нужно сохранить в метаполе в сериализованном виде.
add_action('save_post', 'wpcoder_save_complex_metabox_data');
function wpcoder_save_complex_metabox_data($post_id) {
if (!isset($_POST['wpcoder_complex_metabox_nonce']) || !wp_verify_nonce($_POST['wpcoder_complex_metabox_nonce'], 'wpcoder_save_complex_metabox')) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (!current_user_can('edit_post', $post_id)) return;
if (isset($_POST['wpcoder_data']) && is_array($_POST['wpcoder_data'])) {
$cleaned = [];
foreach ($_POST['wpcoder_data'] as $item) {
$title = sanitize_text_field($item['title']);
$desc = sanitize_textarea_field($item['description']);
if ($title || $desc) {
$cleaned[] = ['title' => $title, 'description' => $desc];
}
}
update_post_meta($post_id, '_wpcoder_complex_data', $cleaned);
} else {
delete_post_meta($post_id, '_wpcoder_complex_data');
}
}
Вывод данных метабокса на фронтенде
Чтобы вывести сложные данные на сайте, например, в шаблоне single.php, достаточно получить метаполе и пройтись циклом:
$data = get_post_meta(get_the_ID(), '_wpcoder_complex_data', true);
if ($data && is_array($data)) {
echo '<div class="wpcoder-complex-output">';
foreach ($data as $block) {
echo '<h3>' . esc_html($block['title']) . '</h3>';
echo '<p>' . nl2br(esc_html($block['description'])) . '</p>';
}
echo '</div>';
}
Дополнительные советы и плагины для работы с метабоксами
Если хочется сэкономить время и получить удобный интерфейс, рекомендую обратить внимание на плагины:
- Clearfy Pro — помогает оптимизировать и расширять WP, включая дополнительные настройки метабоксов.
- ABC Pagination — может пригодиться, если комплексные данные надо выводить с пагинацией.
Также для сложных форм можно использовать библиотеку Meta Box, которая предоставляет гибкий API для создания любых метаполей и групп.
Итоги
Создание комплексных метабоксов в WordPress требует понимания как PHP, так и JS для удобного интерфейса. В статье приведён пример с повторяющимися блоками и вложенными полями, который можно расширять и адаптировать под конкретные задачи. Такой подход помогает создавать удобные админки, улучшая работу с контентом и расширяя возможности сайта.