是否可以在save_post动作中确定是创建新帖子还是更新现有帖子?

评论

我认为这是不可能的。请参阅下面@moraleida的回答我的评论。为什么您需要知道这是新帖子还是正在更新?可能有解决方法或替代方法。

#1 楼

从WordPress版本3.7开始。 -IIRC-save_post钩子-有关钩子及其用法的更多信息,请参见代码参考:save_post和Codex:save_post-具有第三个参数$update,可用于确定该参数。


@param整型int $ post_ID帖子ID。
@param WP_Post帖子$ post帖子对象。
@param bool不管此帖子是否已更新。



注意:

$update并不总是true –您可以使用以下代码亲自对其进行测试。但是,它没有很好的文档记录,可能远没有最佳命名,因此会产生误导性的期望。下面的代码可用于某些调试,并尝试何时拦截代码执行,因为否则您将看不到信息/消息。我认为,欺骗性行为的罪魁祸首是对修订和自动保存的处理-可以将其禁用,但我不建议这样做,也没有对其进行测试。不知道这是否需要一张Trac票,所以我没有打开那张票,如果您这么想,请按照链接自行完成。除此之外,如评论中所述,如果您有特定问题,请发布新问题。

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();
}


评论


$ update参数即使是新帖子也始终为true。所以这个参数没用。不确定它是否曾经奏效,但可以肯定的是,它并没有按照最新版本的wordpress 4.8所记录的那样工作。

–所罗门·克洛森(Solomon Closson)
17年7月20日在20:32

@SolomonClosson如果您看看wp_publish_post,那么可以。但这在wp_insert_post中的用法并不正确。我编写了一个调试功能,将其添加到答案中。

–尼古拉
17年7月21日在0:11

@SolomonClosson如果您遇到实际的具体问题,请提出一个新问题。查看有关调试功能的修订说明。

–尼古拉
17年7月21日在0:34

save_post挂钩具有第三个参数,该参数始终设置为TRUE,因此不确定与其他挂钩有什么关系,而不是其他挂钩。我说的是你答案中的陷阱。这是不正确的。

–所罗门·克洛森(Solomon Closson)
17年7月23日在23:42

@SolomonClosson正如我所说的,挂钩发生了两次:wp_insert_post(),wp_publish_post()。后者只是将来的帖子,其中$ update设置为true。否则,对于wp_insert_post(),$ update并不总是true。

–尼古拉
17年7月24日在13:08



#2 楼

我执行此检查的方法(在带钩子的函数内)是比较发布日期和修改日期(在格林威治标准时间进行标准化)
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 );
    $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 ){
        // New post
    }else{
        // Updated post
    }
}
add_action('save_post', 'check_new_vs_update' );

之所以可行,是因为即使在创建时,该帖子也具有“修改”日期附加到它,与“创建”日期完全相同,但是我们允许任一种方式都以1秒为单位的差异,以防在创建信息期间出现一秒的滴答声。

评论


有时post_date_gmt是2019-03-12 01:31:30而post_modified_gmt是2019-03-12 01:31:31。 :(

–何一非何一非
19年3月12日在4:06

@HeYifei何一非好点,如果处理在给定的秒数结束时开始,则可能会发生这种情况。我已经更新了答案,谢谢

–詹姆斯·库欣
19年3月12日在13:04

伙计们,只是一个信息。在还原和删除帖子时会触发该挂钩。

–梅尔文
19年5月9日,11:39

很高兴认识@melvin,谢谢

–詹姆斯·库欣
20/08/17在17:43

我不敢相信它是如此复杂。 WordPress永远不会令我惊讶。

–amarinediary
1月4日13:29

#3 楼

我最终只是在设置前检查自定义值的存在。这样,如果它是新创建的帖子,则自定义值将不存在。

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');


评论


为此,您是否必须首先使用add_post_meta创建自定义字段?

–MF1
2013年4月9日在2:03

根据食典:[update_post_meta]可以代替add_post_meta()函数使用。 codex.wordpress.org/Function_Reference/update_post_meta

–这里是什么
2014年1月20日在21:46



如果帖子是在通过插件激活启用代码挂钩之前创建的,则这可能会失败。较旧的帖子没有元集,因此对它们的第一次更新将被视为新的。

– Vasu Chawla
18年5月5日在19:13

@VasuChawla,因此在这种情况下,检查该特定元术语的存在isset()(例如)而不是检查其真假,可能更可靠。作为第三个条件。 (如果,否则,...否则)

– ViktorBorítás
20年8月1日在17:03



#4 楼

带有“更新”参数的elocin答案示例:

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 );


评论


更好的方法是将更新块放在第一位,只允许执行if($ update)或将新块放在第一位,但要使用if(!$ update)。后者将使OP成为更好的实践,并且在三元运算符之类的情况下,WordPress编码标准会优先于您的方法使用OP

–詹姆斯·库欣
16年11月17日在11:38

#5 楼

您可以将pre_post_update操作挂钩用于更新代码,将save_post用于新的邮政编码。它可以在帖子更新之前起作用。

评论


创建和更新帖子时都会触发save_post挂钩(在WordPress将其保存到数据库之后)。更新帖子时但在更新帖子之前会触发pre_post_update-这可能很重要。

–斯蒂芬·哈里斯(Stephen Harris)
2012年8月12日18:59



#6 楼

正如Darshan Thanki所暗示的(斯蒂芬·哈里斯(Stephen Harris)进一步阐述)一样,您可以使用pre_post_update来发挥自己的优势。 PHP(令人震惊...),因此将该变量拉入函数范围不起作用-因此是全局的。

请注意,这实际上只能在function is_new_post() use ( &$new_post )事件中/之后可靠地使用(通常就足够了,至少对于我们正在使用它进行操作。)

#7 楼

触发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');


,但这未经测试。 =)

评论


当您到达save_post时,帖子本身已经保存到数据库中-因此get_posts将返回当前帖子。

–斯蒂芬·哈里斯(Stephen Harris)
2012年4月12日在18:25

是的,只需在食典中检查一下即可。感谢您的单挑。

– moraleida
2012年4月12日在18:59

这不适用于get_posts,但适用于get_post。

–加文
20年8月18日在2:28

#8 楼

使用内置函数且不添加数据库的另一种方法涉及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()可以返回的各种字符串,以构建更合适的字符串场景。

请参见Codex以获得get_post_status()和发布状态


可能的值为: -已发布的帖子或页面
'待定'-待审核的帖子
'草稿'-处于草稿状态的帖子
'自动草稿'-新建的帖子,没有内容
'future'-将来要发布的帖子
'private'-未登录的用户不可见
'inherit'-修订版。请参见get_children。
'trash'-帖子在回收站中。已在2.9版中添加。



评论


我不认为这能达到要求。如果我创建一个新帖子,然后单击“发布”,则将首次执行save_post(),但在执行此过程中,get_post_status()已经返回“发布”而不是“草稿”,即使它只是在正在发布。

– cgogolin
17年11月25日在18:39

#9 楼

我刚刚遇到了关于新的和更新的save_post。阅读完源代码后即可了解流程。我发现以下方法可能有用。由于之前尚未提及。查看它是否对任何人有用。 (测试是Core 5.3.3)

创建帖子的流程大致如下:


按Add New(Post)
$ post = get_default_post_to_edit($ post_type,true);将在
get_default_post_to_edit()接收参数$ create_in_db = true
的地方被调用,因此将立即调用wp_insert_post(),并创建auto-draft帖子,即使它没有保存,每次单击Add New时,都会显示auto-draft创建的
$ update对于发布始终为true。因此,当发布新帖子时,它是正确的。

通过比较$ _POST对象用于新帖子和更新帖子或重新发布帖子,最主要的区别是值_wp_http_referer,新帖子是/wp-admin/post-new.php

假设:假设帖子是通过UI发布/添加的。如果通过其他机制,自定义代码完成,则需要进行检查以进行调整。

add_action( 'save_post', 'test_save_post_check', 0, 3 );
function test_save_post_check( $post_ID, $post, $update ) {
    // other tests + this
    // checking the 'post-new' position from the '_wp_http_referer'
    if( strpos( wp_get_raw_referer(), 'post-new' ) > 0 ) {
        // new
    } else {
        // update
    }
}


#10 楼

由于$update参数没有用,因此这是我测试的最快方法:
 function wpse48678_check_is_post_new($post_id, $post, $update)
{
    if (false !== strpos($_POST['_wp_http_referer'], 'post-new.php')) {
        return true; // Or do something else.
    } else {
        return false; // Or do something else.
    }
}
add_action('save_post_{$post_type}', 'wpse48678_check_is_post_new', 10, 3);