Проверка обновления или создания нового поста в хуке save_post

11 апр. 2012 г., 22:43:16
Просмотры: 42K
Голосов: 25

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

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

Я не думаю, что это возможно. Смотри мой комментарий под ответом @moraleida. Зачем вам нужно знать, новый это пост или обновление? Возможно, есть обходной путь или альтернативный подход.

Stephen Harris Stephen Harris
12 апр. 2012 г. 21:28:38
Все ответы на вопрос 13
7
20

Начиная с версии WordPress 3.7 (если я правильно помню), хук save_post — подробнее о хуке и его использовании можно узнать в Code Reference: save_post и Codex: save_post — имеет третий параметр $update, который можно использовать для определения, происходит ли обновление.

@param int $post_ID ID записи.
@param WP_Post $post Объект записи.
@param bool $update Указывает, обновляется ли существующая запись или создаётся новая.


Примечание:

$update не всегда равен true — вы можете проверить это самостоятельно с помощью приведённого ниже кода. Этот параметр недостаточно документирован, возможно, его название не самое удачное, что может вводить в заблуждение. Нижеприведённый код можно использовать для отладки — поэкспериментируйте с точками останова, иначе вы не увидите информацию/сообщения. Я думаю, причина обманчивого поведения кроется в обработке ревизий и автосохранений — их можно отключить, но я не рекомендую этого делать и сам не тестировал. Не уверен, что это требует создания Trac Ticket, поэтому не создавал его; если вы считаете иначе, перейдите по ссылке и сделайте это сами. Кроме того, как указано в комментариях, если у вас есть конкретная проблема, задайте новый вопрос.

add_action( 'save_post', 'debug_save_post_update', 10, 3 );  
function debug_save_post_update( $ID, $post, $update ) {  

  echo '<pre>';  
  print_r( $post ); echo '<br>';  
  echo '$update == ';  
  echo $update ? 'true' : 'false';  

  // Условия  
  if( ! $update && $post->post_status == "auto-draft" ) {  
    // Применяется к новой записи  
    echo ' && $post->post_status == "auto-draft"';  
    //die();  
  } else if ( ! $update ) {  
    // Применяется к автосохранённой ревизии  
    //die();  
  } else {  
    // Применяется к обновлению опубликованной записи  
    // Если есть ревизия (что является стандартным поведением WordPress),  
    // это считается обновлением, что и вызывает путаницу  
    // Существуют другие методы, например проверка времени или статуса записи  
    // В зависимости от вашего случая может быть целесообразнее  
    // использовать один из этих альтернативных подходов  
    //die();  
  }  

  echo '</pre>';  
  //die();  
}  
1 мая 2015 г. 00:13:02
Комментарии

Параметр $update ВСЕГДА имеет значение true, даже при создании новой записи. Таким образом, этот параметр бесполезен. Не уверен, работал ли он вообще, но в последней версии WordPress 4.8 он точно не работает так, как описано в документации.

Solomon Closson Solomon Closson
20 июл. 2017 г. 23:32:34

@SolomonClosson Если вы посмотрите на wp_publish_post, то да. Но это не относится к его использованию в wp_insert_post. Я написал функцию для отладки, добавил её в ответ.

Nicolai Grossherr Nicolai Grossherr
21 июл. 2017 г. 03:11:55

@SolomonClosson Если у вас есть конкретная проблема, пожалуйста, задайте новый вопрос. Посмотрите историю изменений для функции отладки и объяснение.

Nicolai Grossherr Nicolai Grossherr
21 июл. 2017 г. 03:34:11

Хук save_post имеет третий параметр, который всегда установлен в TRUE, поэтому не совсем понятно, какое это имеет отношение к другим хукам, не говоря уже о них. Я говорю о хуке в вашем ответе. Это неверно.

Solomon Closson Solomon Closson
24 июл. 2017 г. 02:42:42

@SolomonClosson Как я уже сказал, хук срабатывает дважды: wp_insert_post(), wp_publish_post(). Последний только для запланированных записей, там $update всегда установлен в true. В случае с wp_insert_post(), $update не всегда true.

Nicolai Grossherr Nicolai Grossherr
24 июл. 2017 г. 16:08:09

Я опоздал на вечеринку, но эй, почему бы и нет, @Nicolai, то, что вы говорите, — это то, что можно было бы ожидать, но я не могу получить $update равным false, даже когда подключаюсь к 'wp_insert_post'. Где бы я ни подключал хук, он всегда true. Я не понимаю, почему это не исправлено.

Caio Mar Caio Mar
2 февр. 2019 г. 16:33:08

Ребята, просто информация. Хук срабатывает при восстановлении и удалении записи.

melvin melvin
9 мая 2019 г. 14:39:48
Показать остальные 2 комментариев
6
13

Мой способ проверки (внутри hooked-функции) — сравнение даты публикации и даты изменения (в GMT для стандартизации)

function check_new_vs_update( $post_id ){
    $myPost     = get_post($post_id);
    $created    = new DateTime( $myPost->post_date_gmt );
    $modified   = new DateTime( $myPost->post_modified_gmt );
    $diff       = $created->diff( $modified );
    $seconds_difference = ((($diff->y * 365.25 + $diff->m * 30 + $diff->d) * 24 + $diff->h) * 60 + $diff->i)*60 + $diff->s;

    if( $seconds_difference <= 1 ){
        // Новая запись
    }else{
        // Обновлённая запись
    }
}
add_action('save_post', 'check_new_vs_update' );

Это работает, потому что даже при создании записи к ней прикрепляется дата изменения, которая точно такая же, как и дата создания, но мы допускаем отклонение в 1 секунду на случай, если секунда изменится во время создания записи.

10 февр. 2015 г. 15:51:45
Комментарии

Иногда post_date_gmt имеет значение 2019-03-12 01:31:30, а post_modified_gmt2019-03-12 01:31:31. :(

He Yifei 何一非 He Yifei 何一非
12 мар. 2019 г. 06:06:47

@HeYifei何一非 хорошее замечание, если обработка начинается в конце заданной секунды, такое может произойти. Я обновил свой ответ, спасибо

Cush Cush
12 мар. 2019 г. 15:04:13

Ребята, просто информация. Хук срабатывает при восстановлении и удалении записи.

melvin melvin
9 мая 2019 г. 14:39:53

Полезно знать, @melvin, спасибо

Cush Cush
17 авг. 2020 г. 20:43:30

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

amarinediary amarinediary
4 янв. 2021 г. 15:29:19

Если быть справедливым, у них буквально миллионы пользователей, и это проект с открытым исходным кодом. К сожалению, они не могут включить каждую функцию, и это, вероятно, не самая востребованная. В последние годы приоритетами были улучшение редактора и безопасности, и это хорошо! Даже jQuery только сейчас обновляется! До текущей версии использовалась 1.x!

Cush Cush
21 янв. 2021 г. 15:26:35
Показать остальные 1 комментариев
4

В итоге я просто проверил наличие пользовательского значения перед его установкой. Таким образом, если это только что созданная запись, пользовательского значения ещё не будет существовать.

function attributes_save_postdata($post_id) {
  // Если это автосохранение, ничего не делаем
  if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
  // Проверяем nonce на безопасность
  if (!wp_verify_nonce($_POST['_attributes_noncename'], plugin_basename(__FILE__))) return;
  // Проверяем права пользователя для страниц и записей
  if ('page' == $_POST['post_type']) {
    if (!current_user_can('edit_page', $post_id)) return;
  } else {
    if (!current_user_can('edit_post', $post_id)) return;
  }
  // Получаем текущее значение метаполя
  $termid = get_post_meta($post_id, '_termid', true);
  if ($termid != '') {
    // Если значение существует - помечаем как 'update'
    $termid = 'update';
  } else {
    // Если значения нет - оставляем как есть
  }
  // Обновляем метаполе
  update_post_meta($post_id, '_termid', $termid);
}
// Добавляем обработчик сохранения записи
add_action('save_post', 'attributes_save_postdata');
18 апр. 2012 г. 00:50:50
Комментарии

Для этого нужно сначала создать произвольное поле с помощью add_post_meta?

MF1 MF1
9 апр. 2013 г. 05:03:17

Согласно Codex: [update_post_meta] может использоваться вместо функции add_post_meta(). http://codex.wordpress.org/Function_Reference/update_post_meta

hereswhatidid hereswhatidid
20 янв. 2014 г. 23:46:08

Это может не сработать, если записи были созданы до того, как код активировался через плагин. Старые записи не имеют установленных мета-полей, поэтому первое обновление для них будет считаться новым.

Vasu Chawla Vasu Chawla
5 мая 2018 г. 22:13:01

@VasuChawla в таком случае, возможно, будет надежнее проверять существование isset() (например) этого конкретного мета-термина, а не его значение true или false. В качестве третьего условия. (if, elseif, ...else)

Viktor Borítás Viktor Borítás
1 авг. 2020 г. 20:03:44
1

Пример ответа на ialocin с параметром "update":

function save_func($ID, $post,$update) {

   if($update == false) {
     // выполнить что-то при первой публикации
   } else {
     // Выполнить что-то при обновлении
   }
}

add_action( 'save_post', 'save_func', 10, 3 );
1 дек. 2015 г. 19:53:53
Комментарии

Лучшим способом структурирования будет либо поместить блок обновления первым, позволяя просто использовать if($update), либо оставить новый блок первым, но с использованием if( ! $update ). Последний вариант привьёт OP лучшие практики и предпочтителен по стандартам кодирования WordPress в случаях, подобных использованию тернарного оператора

Cush Cush
17 нояб. 2016 г. 13:38:30
0

Я только что столкнулся с хуком save_post при создании и обновлении записи. После изучения исходного кода, чтобы понять поток выполнения, я обнаружил, что следующий метод может быть полезен. Поскольку ранее он не упоминался, решил поделиться — вдруг кому-то пригодится. (Тестировалось на версии ядра 5.3.3)

Процесс создания записи примерно следующий:

  1. После нажатия "Добавить новую" (запись)
  2. Вызывается $post = get_default_post_to_edit( $post_type, true );, где
  3. get_default_post_to_edit() получает аргумент $create_in_db = true
  4. Сразу же вызывается wp_insert_post(), создается запись со статусом auto-draft, даже если она не сохранена. Каждый раз при нажатии "Добавить новую" создается auto-draft
  5. При публикации новой записи $update всегда равен true. То есть при публикации новой записи значение будет true.

При сравнении объекта $_POST для новой записи и обновления или повторной публикации записи, заметное отличие — это значение _wp_http_referer. Для новой записи это /wp-admin/post-new.php.

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

add_action( 'save_post', 'test_save_post_check', 0, 3 );
function test_save_post_check( $post_ID, $post, $update ) {
    // другие проверки + эта
    // проверяем наличие 'post-new' в '_wp_http_referer'
    if( strpos( wp_get_raw_referer(), 'post-new' ) > 0 ) {
        // новая запись
    } else {
        // обновление
    }
}
3 мая 2020 г. 18:14:40
0

Вот рабочий код, который я протестировал и использовал на своем сайте. Он решает две следующие проблемы, связанные с действием save_post:

  1. Проблема проверки между обновлением и вставкой

  2. Проблема двойной вставки из-за действия save_post

    function save_annonces_callback($post_ID, $post, $update){
    
            $post_type = get_post_type($post_ID);
    
            if ( $post_type === 'annonces' ){
    
                //это предотвращает двойную вставку из-за действия save_post :)
                if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) {
                    return;
                } else {
    
                    //проверяем, является ли пост новым, чтобы выполнить вставку
                    if( strpos( wp_get_raw_referer(), 'post-new' ) > 0 ){
    
                        //выполняем вставку
    
                    }else{
    
                        //выполняем обновление
                    }
    
                }
    
            }
        }add_action('save_post','save_annonces_callback', 10, 3);
    
14 июл. 2021 г. 19:34:25
1

Вы можете использовать хук pre_post_update для кода обновления и save_post для кода нового поста. Это срабатывает перед обновлением записи.

6 авг. 2012 г. 15:08:44
Комментарии

Хук save_post срабатывает как при создании записи, так и при её обновлении (после того, как WordPress сохранит её в базе данных). Хук pre_post_update срабатывает при обновлении записи, но до того, как запись будет обновлена — это может быть важно.

Stephen Harris Stephen Harris
12 авг. 2012 г. 21:59:39
0

Как намекнул Darshan Thanki (и более подробно объяснил Stephen Harris), вы можете использовать pre_post_update в своих интересах.

global $___new_post;
$___new_post = true;

add_action(
  'pre_post_update',
  function() {
    global $___new_post;
    $___new_post = false;
  },
  0
);

function is_new_post() {
  global $___new_post;
  return $___new_post;
}

Причина, по которой я использовал глобальные переменные, заключается в том, что function is_new_post() use ( &$new_post ) недопустимо в PHP (удивительно...), поэтому передача этой переменной в область видимости функции не работает — отсюда и глобальная переменная.

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

6 янв. 2015 г. 22:49:27
3

Когда срабатывает save_post, вся информация о записи уже доступна, поэтому теоретически вы можете использовать:

function f4553265_check_post() {

    if (!get_posts($post_id)) {
    // если это новая запись, get_posts($post_id) должен вернуть null
    } else {
    // $post_id уже существует в базе данных
    }
}
add_action('save_post','f4553265_check_post');

однако это не тестировалось. =)

12 апр. 2012 г. 07:27:21
Комментарии

К моменту выполнения save_post пост уже будет сохранен в базе данных - поэтому get_posts вернет текущий пост.

Stephen Harris Stephen Harris
12 апр. 2012 г. 21:25:41

Верно, только что проверил в Кодексе. Спасибо за подсказку.

moraleida moraleida
12 апр. 2012 г. 21:59:38

Это не работает с get_posts, но работает с get_post.

Gavin Gavin
18 авг. 2020 г. 05:28:49
1

Другой подход, который использует встроенную функцию и не требует изменений в базе данных, включает использование get_post_status().

$post_status = get_post_status();
if ( $post_status != 'draft' ) {
    //черновик
} else { 
    //не черновик: может быть опубликован, ожидает проверки и т.д. 
}

Однако обратите внимание, что этот метод может быть не совсем подходящим, если вы планируете позже снова установить статус "черновик" — ваши инструкции будут повторены в следующий раз при обновлении записи.

В зависимости от контекста, вы можете рассмотреть различные значения, возвращаемые функцией get_post_status(), чтобы построить более подходящий сценарий.

См. Codex для get_post_status() и Статусы записей

Возможные значения:

  • 'publish' - Опубликованная запись или страница
  • 'pending' - Запись ожидает проверки
  • 'draft' - Запись в статусе черновика
  • 'auto-draft' - Новая созданная запись без содержимого
  • 'future' - Запись, запланированная для публикации в будущем
  • 'private' - Не видна пользователям, которые не авторизованы
  • 'inherit' - Ревизия. См. get_children.
  • 'trash' - Запись в корзине. Добавлено в версии 2.9.
12 дек. 2014 г. 04:15:22
Комментарии

Я не думаю, что это работает так, как было запрошено. Если я создаю новую запись и нажимаю 'Опубликовать', функция save_post() выполняется в первый раз, но во время этого выполнения get_post_status() уже возвращает 'publish', а не 'draft', несмотря на то, что запись находится только в процессе публикации.

cgogolin cgogolin
25 нояб. 2017 г. 20:39:01
0

Поскольку параметр $update бесполезен, это самый быстрый способ, который я протестировал:

function wpse48678_check_is_post_new($post_id, $post, $update)
{
    if (false !== strpos($_POST['_wp_http_referer'], 'post-new.php')) {
        return true; // Или сделать что-то ещё.
    } else {
        return false; // Или сделать что-то ещё.
    }
}
add_action('save_post_{$post_type}', 'wpse48678_check_is_post_new', 10, 3);
9 сент. 2020 г. 23:26:12
0

Я потратил на это часы

Сейчас я разрабатываю плагин и хотел отправлять уведомления всем авторам, когда на сайте моей Веб-дизайн компании создаётся страница.

Изначально я попробовал использовать следующий код:

add_action('save_post_page', function($post_id, $post, $update) {
    if(!$update){
        echo("Это новый пост!");
    }else{
        echo("Это старый пост!");
    }
}

Но он постоянно выводил "Это старый пост!". Почему? После некоторых исследований выяснилось, что после нажатия кнопки "Добавить новую страницу" WordPress мгновенно создаёт автосохранённый черновик (auto-draft), из-за чего переменная $update устанавливается в true. Очень удобно.

После долгих поисков я наконец нашёл рабочее решение:

// Срабатывает при изменении статуса записи, например: pending → draft, published → scheduled.
add_action('transition_post_status', function($new_status, $old_status, $post) {
    // Проверяем, переходит ли запись из auto-draft в любой другой статус (draft, pending, publish и т. д.)
    if ('auto-draft' === $old_status && $new_status !== 'auto-draft'){
        echo("Это новый пост!");
    }else{
        echo("Это старый пост!");
    }
}

Примечание: В WordPress "draft" и "auto-draft" — это разные статусы. "Draft" — это ручной черновик, который пользователь сохраняет как незавершённую работу. "Auto-draft" же автоматически присваивается записи при создании, если она ещё не опубликована. По сути, это аналог автосохранения.

Надеюсь, это поможет кому-то сэкономить время... Теперь пойду потрачу ещё 4 часа на другую проблему, ха-ха.

12 дек. 2024 г. 22:45:17
0

Это должно сработать, ребята

add_action( 'wp_after_insert_post', 'clearCDNCache', 10, 4);       
 
public function clearCDNCache($post_id, $post, $update, $post_before){
        
        if ( ! empty($_POST['_wpnonce']) ) {
            // Выполнить пользовательскую функцию только один раз
        }
    
        // Добавление нового режима.
        if (!empty($_POST['_wp_http_referer']) && $_POST['_wp_http_referer'] == '/wp-admin/post-new.php') { 

        } else {
            // Режим обновления
        }
       
    }
27 февр. 2025 г. 11:12:21