Работа с метабоксами (или custom fields) в WordPress — ключевая часть разработки кастомных решений, будь то темы или плагины. Метабоксы позволяют добавлять произвольные поля к записям, страницам и произвольным типам записей (Custom Post Types), сохраняя дополнительные данные, например цену, период аренды, тип объекта или связанного агента недвижимости.
В этом уроке разберём, как:
1. Регистрация метабокса
Для начала создаётся метод, который будет регистрировать метабокс через хук add_meta_boxes. Например, для кастомного типа записи property (недвижимость) можно зарегистрировать секцию с дополнительными полями:
add_action('add_meta_boxes', [$this, 'metabox_property']);
public function metabox_property() {
add_meta_box(
'property_settings', // ID метабокса
'Property Settings', // Заголовок блока
[$this, 'render_metabox_content'], // Callback-функция вывода
'property', // Тип записи
'normal', // Расположение
'default' // Приоритет
);
}
Такой код добавит блок «Property Settings» в интерфейсе редактирования записи типа property.
2. Вывод пользовательских полей
Внутри метода render_metabox_content создаются HTML-поля, через которые администратор сможет ввести данные. Например, поля для цены, периода и типа недвижимости:
public function render_metabox_content($post) {
// Получаем сохранённые данные
$price = get_post_meta($post->ID, 'property_price', true);
$period = get_post_meta($post->ID, 'property_period', true);
$type = get_post_meta($post->ID, 'property_type', true);
// Защита nonce
wp_nonce_field('property_fields_action', 'property_fields_nonce');
?>
<p>
<label for="property_price">Цена:</label>
<input type="text" name="property_price" id="property_price" value="<?= esc_attr($price) ?>">
</p>
<p>
<label for="property_period">Период:</label>
<input type="text" name="property_period" id="property_period" value="<?= esc_attr($period) ?>">
</p>
<p>
<label for="property_type">Тип объекта:</label>
<select name="property_type" id="property_type">
<option value="">— Выберите —</option>
<option value="sale" <?= selected($type, 'sale', false) ?>>На продажу</option>
<option value="rent" <?= selected($type, 'rent', false) ?>>В аренду</option>
<option value="sold" <?= selected($type, 'sold', false) ?>>Продано</option>
</select>
</p>
<?php
}
Здесь:
get_post_meta()— получает значение метаполя из базы;esc_attr()защищает вывод от XSS;selected()автоматически устанавливает выбранный пункт в<select>;wp_nonce_field()создаёт скрытое поле с nonce для защиты от подделки запросов.
3. Связка с другими сущностями (например, агентами)
Если ваш плагин также регистрирует кастомный тип записей agent, можно добавить селектор для привязки агента к объекту:
$agents = get_posts([
'post_type' => 'agent',
'posts_per_page' => -1,
]);
$selected_agent = get_post_meta($post->ID, 'property_agent', true);
?>
<p>
<label for="property_agent">Агент:</label>
<select name="property_agent" id="property_agent">
<option value="">— Не выбрано —</option>
<?php foreach ($agents as $agent): ?>
<option value="<?= esc_attr($agent->ID) ?>" <?= selected($selected_agent, $agent->ID, false) ?>>
<?= esc_html($agent->post_title) ?>
</option>
<?php endforeach; ?>
</select>
</p>
<?php
Таким образом, каждое объявление недвижимости можно связать с агентом, который за него отвечает.
4. Сохранение данных метабоксов
Чтобы данные сохранялись при обновлении записи, используем хук save_post:
add_action('save_post', [$this, 'save_metabox_data'], 10, 2);
public function save_metabox_data($post_id, $post) {
// Проверки безопасности
if (!isset($_POST['property_fields_nonce']) ||
!wp_verify_nonce($_POST['property_fields_nonce'], 'property_fields_action')) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if ($post->post_type !== 'property') return;
if (!current_user_can('edit_post', $post_id)) return;
// Сохраняем данные
$fields = [
'property_price' => sanitize_text_field($_POST['property_price'] ?? ''),
'property_period' => sanitize_text_field($_POST['property_period'] ?? ''),
'property_type' => sanitize_text_field($_POST['property_type'] ?? ''),
'property_agent' => sanitize_text_field($_POST['property_agent'] ?? ''),
];
foreach ($fields as $key => $value) {
if (empty($value)) {
delete_post_meta($post_id, $key);
} else {
update_post_meta($post_id, $key, $value);
}
}
}
Что делает этот код:
- Проверяет
nonceдля защиты от CSRF; - Исключает автосохранения (
DOING_AUTOSAVE); - Проверяет, имеет ли пользователь право редактировать запись;
- Санитизирует (очищает) данные перед записью в базу;
- Использует
update_post_meta()для сохранения иdelete_post_meta()для удаления пустых значений.
5. Улучшения и безопасность
Несколько рекомендаций для надёжной работы:
- Всегда используйте
esc_html(),esc_attr()иsanitize_text_field()при работе с пользовательскими данными. - Для числовых значений применяйте
intval()илиfloatval(). - Если нужно хранить массив данных — сериализуйте через
maybe_serialize()или используйтеupdate_post_meta()напрямую с массивом. - Не забывайте про
wp_nonce_field()иwp_verify_nonce()— это обязательная защита от CSRF.
Заключение
Теперь у вас есть полноценная структура для работы с метабоксами:
- регистрируется метабокс;
- отображаются дополнительные поля в админке;
- данные сохраняются с проверками и защитой;
- всё работает надёжно и безопасно даже в условиях автосохранений и массовых операций.
Это основа для создания профессиональных плагинов, CRM-систем, сайтов недвижимости, каталогов товаров и любых решений, где требуется расширенное управление контентом.