Как сохранять метаданные только для определенного типа записей в WordPress?

17 авг. 2010 г., 13:41:32
Просмотры: 21.3K
Голосов: 16

Я пытаюсь настроить пользовательский тип записи, следуя этому руководству. Однако я немного запутался в том, как и где реализовать 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', чтобы оно срабатывало только для записей моего пользовательского типа.

2
Комментарии

Хороший вопрос, Bobby Jack, но могу ли я попросить вас переименовать вопрос во что-то вроде "Как сохранять метаданные только для определенных пользовательских типов записей"; текущий заголовок слишком общий, и люди могут не понять, что здесь есть решение их проблемы.

MikeSchinkel MikeSchinkel
17 авг. 2010 г. 20:14:17

@Mike: сделано (полностью согласен с вашим предложением, спасибо!)

Bobby Jack Bobby Jack
18 авг. 2010 г. 11:38:29
Все ответы на вопрос 6
7
21
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 записи в качестве аргумента.

РЕДАКТИРОВАНО

Я обновил функцию, учитывая комментарий Яна. Спасибо, Ян!

17 авг. 2010 г. 14:02:31
Комментарии

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

Jan Fabry Jan Fabry
17 авг. 2010 г. 14:20:26

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

EAMann EAMann
17 авг. 2010 г. 14:36:17

Блестяще - работает как часы. И я полагаю, что имеет смысл сделать "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']); } // ... и так далее ... для обработки нескольких различных типов записей? (Извините за плохие возможности форматирования в комментариях!)

Bobby Jack Bobby Jack
17 авг. 2010 г. 14:38:39

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

EAMann EAMann
17 авг. 2010 г. 14:43:19

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

Bobby Jack Bobby Jack
17 авг. 2010 г. 14:50:12

Добавил пример с switch в ответе ниже для справки :)

EAMann EAMann
17 авг. 2010 г. 14:59:21

Хм, я получаю это предупреждение: 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') { при создании совершенно новой записи. Стоит ли беспокоиться?

INT INT
20 июл. 2011 г. 09:22:37
Показать остальные 2 комментариев
0

Если вам нужно обрабатывать несколько типов записей, я рекомендую использовать простую конструкцию 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 обрабатывает случаи, когда тип записи не входит в ваш набор.

17 авг. 2010 г. 14:48:08
0

@John P Bloch и @EAMann уже дали отличные ответы, поэтому мой является дополнением:

  1. Подумайте о добавлении подчеркивания в начале ваших 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']);
    }
    Очевидно, это означает, что вам также понадобится пользовательский метабокс для редактирования этих полей. Вот экран редактирования для контекста:

    Скриншот админки WordPress с отсутствием пользовательских полей, начинающихся с подчеркивания

  2. Еще одна вещь, которую вы можете сделать — добавить собственный хук, чтобы упростить сохранение записей определенного типа. Например, ваш хук может быть "save_{$post_type}_post"; для типа записи movie это будет save_movie_post. Вот что вам нужно добавить в файл functions.php вашей темы или в плагин:

    
    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");
    }
    С этим вы можете переписать ваш исходный код следующим образом (включая трюк с подчеркиванием из пункта №1 выше):

    
    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']);
    }
17 авг. 2010 г. 20:03:05
0

Лично я предпочитаю использовать следующий шаблон для добавления обработчиков произвольных метаполей к типам записей. С приведенным ниже кодом вы можете добавить поддержку метаполя к типу записи, просто добавив ключ поддержки ('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.

18 авг. 2010 г. 19:55:26
0

Перед обновлением проверьте, относится ли текущая запись к вашему типу записи. Это гарантирует, что изменения не будут сохранены для всех записей.

Также следует проверить ввод (это отсутствует в вашем примере), и помимо этого, учитывайте, что действие может быть добавлено только когда этот тип записи активен. В таком случае, вам не нужно проверять тип записи позже.

Получение типа записи: get_post_type() или $post->post_type;

17 авг. 2010 г. 13:49:59
1

У меня не получается заставить это работать - не уверен, что делаю не так - но я пытаюсь использовать хук 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');
10 апр. 2011 г. 12:34:04
Комментарии

Неважно - я разобрался!

jrutter jrutter
10 апр. 2011 г. 15:19:52