Проверьте наличие обновлений и новых сообщений о действии save_post

21

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

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

Ответы:

16

Начиная с версии WordPress 3.7. - IIRC - 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';

  //conditions
  if( ! $update && $post->post_status == "auto-draft" ) {
    // applies to new post
    echo ' && $post->post_status == "auto-draft"';
    //die();
  } else if ( ! $update ) {
    // applies basically to the (auto saved) revision 
    //die();
  } else {
    // applies to updating a published post
    // when there is a revision, which is normally the case, 
    // standard behavior of WordPress, then it is considered 
    // an update, which is where the confusion sets in
    // there are other methods, like checking time or post status
    // depending on your use case it might be more appropriate 
    // to use one of those alternatives 
    //die();
  }

  echo '</pre>';
  //die();
}
Nicolai
источник
3
$updateПараметр всегда верно , даже если это новый пост. Так что этот параметр бесполезен. Не уверен, работал ли он вообще когда-либо, но он точно работает не так, как задокументировано в последней версии WordPress 4.8.
Соломон Клоссон
@SolomonClosson Если вы посмотрите wp_publish_post, то да. Но это не так для его использования в wp_insert_post. Я написал функцию отладки, я добавляю ее в ответ.
Николай
@SolomonClosson Если у вас есть конкретная проблема, пожалуйста, задайте новый вопрос. Посмотрите на ревизии для функции отладки объяснение.
Николай
save_postКрюк имеет 3 - й параметр , который всегда должен быть установлен в значение TRUE, поэтому не уверен , что это связано с другими крюками, не говоря уже о других крючков. Я говорю о крючке в вашем ответе. Это неверно
Соломон Клоссон
@SolomonClosson Как я сказал крючок происходит два раза: wp_insert_post(), wp_publish_post(). Последние есть только будущие посты, там $updateи так будет всегда true. Иначе, в отношении wp_insert_post(), $updateне всегда true.
Николай
11

Способ, которым я выполняю эту проверку (в рамках подключенной функции), заключается в сравнении даты публикации и даты изменения (в GMT для стандартизации)

function check_new_vs_update( $post_id ){
    $myPost        = get_post($post_id);
    $post_created  = new DateTime( $myPost->post_date_gmt );
    $post_modified = new DateTime( $myPost->post_modified_gmt );

    if( abs( $post_created->diff( $post_modified )->s ) <= 1 ){
        // New post
    }else{
        // Updated post
    }
}
add_action('save_post', 'check_new_vs_update' );

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

Джеймс Кушинг
источник
1
Иногда post_date_gmtесть 2019-03-12 01:31:30и post_modified_gmtесть 2019-03-12 01:31:31. :(
Он Ифэй 何 一 非
1
@HeYifei 非 一 非 хороший момент, если обработка начинается в конце данной секунды, это может произойти. Я обновил свой ответ, спасибо
Джеймс Кушинг
Ребята, просто информация. Хук срабатывает при восстановлении и удалении поста.
Мелвин
6

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

function attributes_save_postdata($post_id) {
  if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
  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 != '') {
    // it's a new record
    $termid = 'update';
  } else {
    // it's an existing record
  }
  update_post_meta($post_id, '_termid', $termid);
}
add_action('save_post', 'attributes_save_postdata');
hereswhatidid
источник
Чтобы это работало, нужно ли вам сначала создавать настраиваемое поле, используя add_post_meta?
MF1
Согласно Кодексу: [update_post_meta] может использоваться вместо функции add_post_meta (). codex.wordpress.org/Function_Reference/update_post_meta
hereswhatidid
Это может не сработать, если сообщения были созданы до того, как ловушка кода будет активирована через активацию плагина. В старых сообщениях мета-набор отсутствует, поэтому первое обновление для них будет считаться новым.
Васу Чавла,
4

Пример ответа на вопрос «Ялоцин» с параметром «обновление»:

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

   if($update == false) {
     // do something if its first time publish
   } else {
     // Do something if its update
   }
}

add_action( 'save_post', 'save_func', 10, 3 );
Горан Яковлевич
источник
2
Лучшим способом структурировать это было бы либо поместить блок обновления первым, позволяя просто сделать, if($update)либо сохранить новый блок первым, но использовать if( ! $update ). Последний получит ОП в лучшую практику и предпочтительнее вашего метода стандартами кодирования WordPress в таких случаях, как троичный оператор
Джеймс Кушинг
1

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

Даршан Благодар
источник
4
save_postХук срабатывает как при создании и обновлении поста (после того, как WordPress сохранил его в базе данных). pre_post_updateсрабатывает при обновлении сообщения, но до его обновления - это может быть важно.
Стивен Харрис
1

Как намекнул Даршан Спасибо (и Стивен Харрис), вы можете использовать это 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события (которого обычно достаточно, по крайней мере, для того, что мы делаем с ним).

Qix
источник
0

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

function f4553265_check_post() {

    if (!get_posts($post_id)) {
    // if this is a new post get_posts($post_id) should return null
    } else {
    // $post_id already exists on the database
    }
}
add_action('save_post','f4553265_check_post');

это не проверено, хотя. знак равно

moraleida
источник
3
К тому времени, когда вы дойдете до save_postсамого сообщения, оно уже будет сохранено в базе данных - поэтому get_postsвернет текущее сообщение.
Стивен Харрис
Правда, только что проверил это в Кодексе. Спасибо за хедз-ап.
Моралейда
0

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

$post_status = get_post_status();
if ( $post_status != 'draft' ) {
    //draft
} else { 
    //not a draft: can be published, pending, etc. 
}

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

См. Кодекс для get_post_status () и статуса сообщения

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

  • «Опубликовать» - опубликованный пост или страница
  • 'pending' - сообщение ожидает рассмотрения
  • 'draft' - пост в состоянии черновика
  • 'auto-draft' - недавно созданная запись без содержания
  • «будущее» - публикация в будущем
  • 'private' - не виден пользователям, которые не вошли в систему
  • «Наследовать» - ревизия. смотри get_children.
  • 'мусор' - сообщение находится в мусорном ведре. добавлено в версии 2.9.
John112
источник
Я не думаю, что это делает то, о чем просили. Если я создаю новую публикацию, а затем нажимаю «Опубликовать», save_post()она выполняется впервые, но во время этого выполнения get_post_status()уже возвращается «публикация», а не «черновик», даже если она находится только в процессе публикации.
cgogolin