Вопрос или проблема
Я пытаюсь подключить 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. Давайте разберем ваш код подробно, чтобы понять, как его улучшить и устранить проблемы, с которыми вы столкнулись.
Шаги для решения проблемы
-
Оптимизация хука
save_post
: Убедитесь, что ваш код срабатывает в нужный момент и не вызывает ненужных действий. -
Проверка существующих категорий: Вместо использования одной категории, мы можем рассмотреть возможность назначения нескольких, если это необходимо.
-
Использование
set_object_terms
: Вместоwp_set_post_categories
, использованиеset_object_terms
может предоставить более точное управление терминами. -
Логирование и отладка: Использовать логи для отслеживания выполнения и отладки. Это помогает понять, почему функция вызывается несколько раз.
Оптимизированный код
Ниже представлен переработанный код с комментариями:
<?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);
Объяснение изменений
-
Защита от рекурсивных вызовов: Мы добавили проверки на выполнение автосохранения и на ревизии постов. Это предотвращает повторные вызовы функции, что может быть причиной необходимости обновления поста несколько раз.
-
Использование
set_object_terms
: Этот метод является более гибким в назначении терминов. Параметрfalse
в конце позволяет не удалять существующие категории, если категория уже присутствует. -
Логирование: Логирование остается, чтобы облегчить отладку и понимание, как работает ваша логика.
Забележка по логированию
Ваши логи могут указывать на то, что функция save_post
вызывается несколько раз. Это может происходить из-за того, что изменения в посте (например, назначение новой категории) также вызывают повторное сохранение. Чтобы этого избежать, вы можете использовать флаг (DOING_AUTOSAVE
) для проверки, происходит ли автосохранение.
Заключение
Ваша исходная задача по автоматическому назначению категории на основе значения пользовательского поля может быть успешно реализована с налетом внимательности и удачно выбранными проверками. Применяя предложенные улучшения, вы сможете устранить проблему с несколькими вызовами хука и обеспечите корректное обновление категории поста.