Вопрос или проблема
Я использую save_post
для функции, которая отправляет электронное письмо, когда пользователь обновляет запись. Это происходит дважды, и я понимаю, что это связано с ревизиями записей и автоматическим сохранением.
Я пытался предотвратить это, обернув wp_mail
в условный оператор, но письмо все равно отправляется дважды. Какие корректировки мне нужно сделать, чтобы это происходило только один раз, когда пользователь обновляет запись?
function updated_search_notification($post_id)
{
$post_type = get_post_type($post_id);
if ($post_type === 'utility-search') {
if ((wp_is_post_revision($post_id)) || (wp_is_post_autosave($post_id))) {
// запись является автосохранением
} else {
// Переменные сообщения
$siteurl = get_option('siteurl');
$post_url="" . $siteurl . '/wp-admin/post.php?post=" . $post_id . "&action=edit';
$new_search_name="";
//$new_search_email = get_option( 'new_search_email' );
$new_search_email="[email]";
$utility_search_customer="";
$subject="Ваш поиск был обновлен";
// Содержание сообщения
$message = "[Содержание сообщения]";
// Отправка письма
wp_mail($new_search_email, $subject, $message);
}
}
}
add_action('save_post', 'updated_search_notification', 10, 3);
Во-первых, вы можете использовать этот хук для нацеливания только на один пользовательский тип:
https://developer.wordpress.org/reference/hooks/save_post_post-post_type/
Этот хук (и save_post
) вызывается первый раз, когда вы нажимаете «новое …», и затем хук вызывается с $update = FALSE
.
Чтобы отправлять письма только при обновлении объекта, вы можете проверить $update
так:
const UTILITY_SEARCH_POST_TYPE = "utility-search";
add_action("save_post_" . UTILITY_SEARCH_POST_TYPE, function ($post_ID, $post, $update) {
if (wp_is_post_autosave($post_ID)) {
return;
}
if (!$update) { // если новый объект
return;
}
// подготовка письма
...
// отправка письма
wp_mail(...);
}, 10, 3);
Одобренный ответ не сработал для меня. В итоге я попробовал несколько условных операторов, и письмо все равно отправлялось дважды:
function xxx_send_mail($id, $post, $update){
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) {
return;
}
if (wp_is_post_revision($id)) {
return;
}
if (wp_is_post_autosave($id)) {
return;
}
// если новая запись
if (!$update) {
return;
}
wp_mail('[email protected]', 'Тема', 'Сообщение');
}
add_action( 'save_post_{the_post_type}', 'xxx_send_mail', 10, 3 );
Я исправил это, добавив удобную функцию, предоставляемую WP, под названием did_action():
function xxx_send_mail($id, $post, $update){
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) {
return;
}
if (wp_is_post_revision($id)) {
return;
}
if (wp_is_post_autosave($id)) {
return;
}
// если новая запись
if (!$update) {
return;
}
$times = did_action('save_post_{the_post_type}');
if( $times === 1){
wp_mail('[email protected]', 'Тема', 'Сообщение');
}
}
add_action( 'save_post_{the_post_type}', 'xxx_send_mail', 10, 3 );
Надеюсь, это поможет кому-то
Уже одобренные ответы не сработали для меня, и комментарий от @Nico Pernice помог.
Если условия в моем коде выглядят так:
function reset_cpt_expire( $post_id, $post, $update ){
// Проверка, является ли запрос REST
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
return;
}
// Проверка, является ли автосохранением или ревизией.
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
return;
}
// Проверка, является ли новой записью
if ( ! $update ) {
return;
}
// мой код сброса...
}
add_action( 'save_post_cpt', 'reset_cpt_expire', 10, 3 );
Попробуйте этот код внутри вашей функции:
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
В качестве альтернативы, вы можете использовать хук publish_post. Если вы просто хотите сработать эту функцию, когда статус записи — опубликовано.
Если у вас возникла проблема, когда хук publish_post срабатывает дважды, вы можете попробовать использовать глобальную переменную, чтобы отслеживать, был ли хук уже сработан.
// Объявление глобальной переменной
global $publish_post_hook_triggered;
$publish_post_hook_triggered = false;
add_action('publish_post', 'my_publish_post_function');
function my_publish_post_function($post_id) {
// Проверка, был ли хук уже сработан
global $publish_post_hook_triggered;
if ($publish_post_hook_triggered) {
return;
}
// Установка глобальной переменной, чтобы указать, что хук был сработан
$publish_post_hook_triggered = true;
// Ваш код, выполняемый при срабатывании хука
}
Мы можем проверить переменную $_POST[‘_wpnonce’]. Это должно работать
add_action( 'save_post', 'clearCDNCache', 10, 3);
public function clearCDNCache($post_id, $post, $update){
$needed_post_types = ['page', 'post', 'boutique', 'brand', 'video', 'product'];
if( ! in_array($post->post_type,$needed_post_types) || empty($_POST['_wpnonce']) ) {
return false;
}
$sample_post_url = get_front_end_post_url($post, 'sg');
$base_url = get_front_end_base_url('sg');
$cdn_path = str_replace($base_url, '*', $sample_post_url);
purge_cdn_paths( [
$cdn_path,
] );
}
.
Ответ или решение
Для решения проблемы с функцией WordPress save_post
, которая срабатывает дважды, возникает необходимость в понимании теоретической основы, примеров применения и практической реализации решения данного вопроса. Давайте подробно разберем эту проблему и предложим подходы к её решению.
Теория
Функция save_post
в WordPress выступает как хук, который вызывается всякий раз, когда пост сохраняется в базе данных. Этот хук срабатывает при ряде событий, таких как:
- Сохранение новой записи.
- Обновление существующей записи.
- Автосохранение (autosave).
- Создание ревизий (revisions).
Причиной дополнительного срабатывания save_post
могут быть именно автосохранения и ревизии, которые являются встроенными функциональностями WordPress. Для избежания этих нежелательных вызовов необходимо учитывать условия, чтобы выполнять действие только для фактического обновления поста пользователем.
Пример
Ваш код, использующий save_post
, может выглядеть следующим образом:
function updated_search_notification($post_id, $post, $update) {
$post_type = get_post_type($post_id);
// Проверка типа поста
if ($post_type !== 'utility-search') {
return;
}
// Проверка на автосохранение и ревизию
if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) {
return;
}
// Проверка, если это не обновление, а создание нового поста
if (!$update) {
return;
}
// Формирование переменных сообщения
$siteurl = get_option('siteurl');
$post_url = $siteurl . '/wp-admin/post.php?post=' . $post_id . '&action=edit';
$new_search_email = "[email]";
$subject = "Your search has been updated";
$message = "[Message Contents]";
// Отправка email
wp_mail($new_search_email, $subject, $message);
}
add_action('save_post', 'updated_search_notification', 10, 3);
Чтобы соответствовать действующему функционалу и устранить нежелательное поведение, рассмотрим практическое применение нескольких методов.
Приложение
Для успешной реализации рассмотрим следующие шаги:
-
Проверка на автосохранение и ревизии:
wp_is_post_autosave($post_id)
иwp_is_post_revision($post_id)
анализируют, является ли сохранение поста автосохранением или ревизией, и если это так, функция завершает выполнение. Эта проверка позволяет предотвратить повторные вызовы, вызванные такими операциями. -
Проверка обновления поста: Используйте параметр
$update
, передаваемый в функцию, чтобы убедиться, что действие выполняется только при обновлении поста, а не при его создании. -
Фильтрация по типу поста: Использование специализированного хука
save_post_{post_type}
для конкретного типа постов, напримерsave_post_utility-search
, позволяет изолировать операции только для указанных типов записей. Это значительно снижает вероятность неправомерной обработки данных для других типов постов. -
Использование глобальных флагов или
did_action
: Для дополнительной гарантии, что функция вызывается единожды, можно применятьdid_action
для проверки количества вызовов. Это добавляет еще одну степень контроля над исполнением функции. -
Обработка REST-запросов: Поскольку REST-запросы могут запускать сохранение постов, стоит исключать их обрабатывая
defined('REST_REQUEST') && REST_REQUEST
.
Таким образом, внедрение всех этих проверок обеспечит, что ваше уведомление об обновлении поста будет отправляться только тогда, когда пост действительно обновляется пользователем, и будет эффективно предотвращать срабатывание функции более одного раза в ходе одного и того же сохранения.
Этот подход надежно минимизирует вероятность ненужного выполнения вашего кода и отправки редандантных email-уведомлений. Надеемся, что данное решение будет полезным и облегчит вашу работу с функцией save_post
в WordPress.