Присвоить категорию из пользовательского поля при создании и обновлении поста

Вопрос или проблема

Я пытаюсь подключить save_post, чтобы автоматически назначать категорию (из пользовательского поля) при обновлении и создании поста. В основном, если дата события 10/10/2020 – я хочу назначить событие в категорию ‘2020’.

Пока что это частично работает, потому что мне действительно нужно нажимать кнопку ‘обновить’ дважды, чтобы это сработало. Я застрял здесь пока что. Поскольку я не очень proficient в PHP или волшебстве WP, я пытался документировать все, как только мог.

Если это поможет, у меня также есть журналы отладки здесь: https://pastebin.com/HQ9B6JqZ?fbclid=IwAR1Ag9_yekNMByN4Dim3BZPJ6ALdIPwQ77hP36W5Ht13QekpkuaofuoLlzY

<?php
/**
 * Создать или обновить категорию для каждого создания или обновления события
 *
 * @param int $post_id ID поста.
 * @param post $post Объект поста.
 * @param bool $update Является ли это существующим постом, который обновляется или нет.
 */
function save_event( $post_id, $post, $update ) {
    $id = $post_id;

    // Если это не пост 'событие', не делайте ничего.
    $post_type = get_post_type($post_id);
    if ( "event" != $post_type ) return;

    // Проверьте, была ли определена дата
    $date = get_field('event_date', $post_id, false);
    if (empty($date)) {
        write_log( "Дата события еще не определена" );
        return;
    }

    // Извлеките год события 
    $date = new DateTime($date);
    $year = $date->format('Y');

    // Получите существующую категорию
    $current_cats = get_the_category($post_id);
    if ( ! empty( $current_cats ) ) {
        $current_cat_name = esc_html( $current_cats[0]->name ); 
        write_log( "Текущая категория в использовании : {$current_cat_name}");

        if ( ! empty($current_cat_name) && $year === $current_cat_name) {
        write_log( "Совпадение существующей категории с датой события");
        return;
        }
    } 

    // Существует ли категория? Должны ли мы создать ее?
    $category_id = get_cat_ID($year);
    if ( $category_id === 0) {
        $category_id = wp_create_category( $year );
        write_log( "Создание категории : ({$year}) с ID {$category_id}");
    } else {
        write_log( "Найдена категория ({$year}) с ID {$category_id}");
    }

    // Назначьте категорию
    $event_categories = array($category_id);
    $post_categories = wp_set_post_categories( $id, $event_categories);
    write_log( "Новая категория ({$year} - {$category_id} ) была назначена посту {$id}");
    write_log( json_encode($post_categories) );

}
add_action( 'save_post', 'save_event', 10, 3 );

После получения года вы можете проверить, существует ли категория, используя

category_exists($cat_name);

если не найдено, тогда создайте категорию, используя

 wp_create_category( $cat_name, $parent );

после этого вы можете создать пост, используя

$my_post = array(
  'post_title'    => wp_strip_all_tags( $_POST['post_title'] ),
  'post_content'  => $_POST['post_content'],
  'post_status'   => 'publish',
  'post_author'   => 1,
  'post_category' => array( 8,39 )
);

// Вставьте пост в базу данных
wp_insert_post( $my_post );

Вы также можете добавить категорию к существующему посту, используя

wp_set_post_categories($post_id,$post_categories)

больше информации:
https://developer.wordpress.org/reference/functions/wp_insert_post/
https://codex.wordpress.org/Function_Reference/wp_create_category
https://developer.wordpress.org/reference/functions/category_exists/

Итак, я попробовал использовать set_object_terms() вместо wp_set_post_categories(), но это почти одно и то же.

Я попытался вывести почти все, что смог:
– $post_id и объект $post всегда доступны
– данные поста не всегда доступны через $_POST (см. ниже)

Я понял, что не всегда мог получить свое значение, используя get_field(‘event_date’) или $_POST[‘acf’][‘field_5c766105f364e’], но обнаружил, что get_field(‘event_date’, $post_id) постоянно возвращает правильное значение.

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

Так что это действительно работает, если бы не несколько вещей:
– крючок срабатывает трижды
– страница редактирования в админке не отражает обновленную категорию (при первом нажатии)

журналы
https://pastebin.com/dF2Q15Y0

Ответ или решение

Чтобы автоматизировать процесс присвоения категории посту на основе пользовательского поля при его создании или обновлении, вы можете использовать хук save_post в WordPress. Давайте разберем ваш код подробно, чтобы понять, как его улучшить и устранить проблемы, с которыми вы столкнулись.

Шаги для решения проблемы

  1. Оптимизация хука save_post: Убедитесь, что ваш код срабатывает в нужный момент и не вызывает ненужных действий.

  2. Проверка существующих категорий: Вместо использования одной категории, мы можем рассмотреть возможность назначения нескольких, если это необходимо.

  3. Использование set_object_terms: Вместо wp_set_post_categories, использование set_object_terms может предоставить более точное управление терминами.

  4. Логирование и отладка: Использовать логи для отслеживания выполнения и отладки. Это помогает понять, почему функция вызывается несколько раз.

Оптимизированный код

Ниже представлен переработанный код с комментариями:

<?php
/**
 * Присвоение категории на основе пользовательского поля при создании или обновлении поста
 *
 * @param int $post_id Идентификатор поста.
 * @param WP_Post $post Объект поста.
 * @param bool $update Является ли пост существующим постом, который обновляется.
 */
function save_event( $post_id, $post, $update ) {
    // Избегаем рекурсивных вызовов
    if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;
    if ( wp_is_post_revision($post_id) ) return;

    // Проверяем тип поста
    if ( 'event' !== get_post_type($post_id) ) return;

    // Получаем дату события
    $date = get_field('event_date', $post_id);
    if ( empty($date) ) {
        write_log( "Дата события не указана." );
        return;
    }

    // Извлекаем год события
    $date = new DateTime($date);
    $year = $date->format('Y');

    // Проверяем существующую категорию
    $category_id = get_cat_ID($year);
    if ( $category_id === 0 ) {
        $category_id = wp_create_category($year);
        write_log( "Создана категория: {$year} с ID {$category_id}." );
    } else {
        write_log( "Найдена категория: {$year} с ID {$category_id}." );
    }

    // Присваиваем категорию посту
    set_object_terms($post_id, array($category_id), 'category', false);
    write_log( "Категория {$year} (ID {$category_id}) присвоена посту ID {$post_id}." );
}
add_action('save_post', 'save_event', 10, 3);

Объяснение изменений

  1. Защита от рекурсивных вызовов: Мы добавили проверки на выполнение автосохранения и на ревизии постов. Это предотвращает повторные вызовы функции, что может быть причиной необходимости обновления поста несколько раз.

  2. Использование set_object_terms: Этот метод является более гибким в назначении терминов. Параметр false в конце позволяет не удалять существующие категории, если категория уже присутствует.

  3. Логирование: Логирование остается, чтобы облегчить отладку и понимание, как работает ваша логика.

Забележка по логированию

Ваши логи могут указывать на то, что функция save_post вызывается несколько раз. Это может происходить из-за того, что изменения в посте (например, назначение новой категории) также вызывают повторное сохранение. Чтобы этого избежать, вы можете использовать флаг (DOING_AUTOSAVE) для проверки, происходит ли автосохранение.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...