Как сохранять метаданные только для определенного типа записей в WordPress?
Я пытаюсь настроить пользовательский тип записи, следуя этому руководству. Однако я немного запутался в том, как и где реализовать update_post_meta()
. В руководстве предлагается такой шаблон:
add_action('save_post', 'save_my_metadata');
function save_my_metadata()
{
global $post;
update_post_meta($post->ID, 'my_metadata', $_POST['my_metadata']);
}
Это действительно работает, но имеет неприятный побочный эффект - добавляет эти метаданные к каждой записи, независимо от того, принадлежит ли она к этому пользовательскому типу или нет.
Я разместил этот код в functions.php
и подозреваю, что это может быть частью проблемы. Полагаю, мне нужно ограничить действие 'save_post', чтобы оно срабатывало только для записей моего пользовательского типа.

function save_my_metadata($ID = false, $post = false)
{
if($post->post_type != 'your_post_type')
return;
update_post_meta($ID, 'my_metadata', $_POST['my_metadata']);
}
Это должно сработать. Просто замените 'your_post_type' на название вашего типа записи. Также малоизвестный факт: хук 'save_post' передает ID записи в качестве аргумента.
РЕДАКТИРОВАНО
Я обновил функцию, учитывая комментарий Яна. Спасибо, Ян!

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

Это решение действительно работает... Я использовал его в клиентских проектах с большим успехом.

Блестяще - работает как часы. И я полагаю, что имеет смысл сделать "if ($post->post_type == 'animal') { update_post_meta($ID, "number_of_legs", $_POST['number_of_legs']); } else if ($post->post_type == 'vehicle') { update_post_meta($ID, "number_of_wheels", $_POST['number_of_wheels']); } // ... и так далее ... для обработки нескольких различных типов записей? (Извините за плохие возможности форматирования в комментариях!)

На самом деле, при работе с несколькими типами записей я бы рекомендовал использовать оператор switch. Меньше разметки, выше производительность, проще добавлять новые условия в будущем.

@EAMann - да, в процессе написания я понял, что switch подошёл бы лучше, но комментарии - не самое подходящее место для редактирования кода, так что я поленился ;)

Хм, я получаю это предупреждение: Notice: Trying to get property of non-object в /ustorage/www/users/qom/vhosts/xxx/xxx/wp-content/themes/ep/functions.php на строке 239 в этой строке: if ($post->post_type == 'mycpt') { при создании совершенно новой записи. Стоит ли беспокоиться?

Если вам нужно обрабатывать несколько типов записей, я рекомендую использовать простую конструкцию switch:
add_action('save_post', 'save_my_metadata');
function save_my_metadata($ID = false, $post = false)
{
switch($post->post_type)
{
case 'post_type_1':
// Действия для типа записи 1
update_post_meta($ID, 'my_metadata', $_POST['my_metadata']); // Пример...
break;
case 'post_type_2':
// Действия для типа записи 2
break;
default:
return;
}
}
Варианты case работают аналогично конструкции if($post->post_type) == 'post_type_1') {}
, но не требуют множественных блоков if-else. Блок default
в switch обрабатывает случаи, когда тип записи не входит в ваш набор.

@John P Bloch и @EAMann уже дали отличные ответы, поэтому мой является дополнением:
- Подумайте о добавлении подчеркивания в начале ваших meta_keys. Это скроет их из списка пользовательских полей, отображаемых на экране редактирования записи, например:
Очевидно, это означает, что вам также понадобится пользовательский метабокс для редактирования этих полей. Вот экран редактирования для контекста:function save_my_metadata($post_id,$post=false) { if($post->post_type=='your_post_type') update_post_meta($post_id, '_my_metadata', $_POST['my_metadata']); }
-
Еще одна вещь, которую вы можете сделать — добавить собственный хук, чтобы упростить сохранение записей определенного типа. Например, ваш хук может быть "
save_{$post_type}_post
"; для типа записиmovie
это будетsave_movie_post
. Вот что вам нужно добавить в файлfunctions.php
вашей темы или в плагин:
С этим вы можете переписать ваш исходный код следующим образом (включая трюк с подчеркиванием из пункта №1 выше):add_action('save_post', 'save_custom_post_type_posts',10,2); function save_custom_post_type_posts($post_id,$post=false) { do_action("save_{$post->post_type}_post"); }
add_action('save_my_postype_post','save_my_postype_metadata',10,2); function save_my_postype_metadata($post_id,$post) { update_post_meta($post_id, '_my_metadata', $_POST['my_metadata']); }

Лично я предпочитаю использовать следующий шаблон для добавления обработчиков произвольных метаполей к типам записей. С приведенным ниже кодом вы можете добавить поддержку метаполя к типу записи, просто добавив ключ поддержки ('subtitle' в примере ниже) в массив supports для типа записи, вызвав add_post_type_support('my_post_type', 'subtitle');
class Subtitle_Meta_Handler {
public function initialize() {
add_action('add_meta_boxes', array($this, 'add_metabox'), 10, 2);
add_action('save_post', array($this, 'update'));
}
public function add_metabox($post_type, $post)
{
if(post_type_supports($post_type, 'subtitle'))
{
add_meta_box('subtitle', 'Подзаголовок', array($this, 'metabox'), $post_type);
}
}
public function metabox($post)
{
$subtitle = get_post_meta($post->ID, 'subtitle', true);
if(!$subtitle)
{
$subtitle = '';
}
?>
<input type="text" style="width: 70%;" value="<?php echo esc_attr($subtitle);?>" name="subtitle" id="subtitle">
<?php
wp_nonce_field('update_subtitle', 'subtitle_nonce');
}
public function update($post_id)
{
if(wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
return $post_id;
}
if(isset($_REQUEST['subtitle_nonce']) && wp_verify_nonce($_REQUEST['subtitle_nonce'], 'update_subtitle')) {
$subtitle = trim(strip_tags($_REQUEST['subtitle'], '<b><strong><span><a>'));
if(empty($subtitle)) {
delete_post_meta($post_id, 'subtitle');
} else {
update_post_meta($post_id, 'subtitle', $subtitle);
}
}
}
}
add_action('init', array(new Subtitle_Meta_Handler(), 'initialize'));
Надеюсь, что подобный функционал скоро будет добавлен в ядро WordPress.

Перед обновлением проверьте, относится ли текущая запись к вашему типу записи. Это гарантирует, что изменения не будут сохранены для всех записей.
Также следует проверить ввод (это отсутствует в вашем примере), и помимо этого, учитывайте, что действие может быть добавлено только когда этот тип записи активен. В таком случае, вам не нужно проверять тип записи позже.
Получение типа записи: get_post_type()
или $post->post_type;

У меня не получается заставить это работать - не уверен, что делаю не так - но я пытаюсь использовать хук post_updated вместо save_post, потому что хочу, чтобы эти значения вставлялись после обновления записи, чтобы я мог получить значения из других произвольных полей.
function update_meta ($ID = false, $post = false) {
update_post_meta($ID, 'rest_long', 'Тест 1');
update_post_meta($ID, 'rest_lat', 'Тест 2');
}
add_action('post_updated', 'update_meta');
