在save_post操作上检查更新与新帖子


21

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


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

Answers:


16

从WordPress版本3.7开始。-IIRC- save_post钩子-有关钩子及其用法的更多信息,请参见代码参考:save_postCodex: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();
}

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

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

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

save_post钩有总是被设置为TRUE,所以不知道这是什么需要做的与其他挂钩,而不是谈论其他钩子第三个参数。我说的是你答案中的陷阱。这是不正确的。
所罗门·克洛森

@SolomonClosson正如我所说的那样,挂钩发生了两次:wp_insert_post()wp_publish_post()。后者仅是将来的职位,$update并且总是存在true。否则,在问候wp_insert_post()$update并不总是true
Nicolai

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_gmt2019-03-12 01:31:30post_modified_gmt2019-03-12 01:31:31。:(
何一非何一非

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

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

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

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

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

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

4

用“更新”参数对ialocin答案的示例:

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
一种更好的结构化方法是要么将update块放在第一位,然后才允许这样做,if($update)要么将新块放在第一位,然后使用if( ! $update )。后者将使OP进入更好的实践,并且在三元运算符
James Cushing

1

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


4
save_post钩被激发双方在创建时桩和更新(WordPress的有它保存到数据库后)。pre_post_update在帖子更新时触发,但帖子更新之前触发-这可能很重要。
史蒂芬·哈里斯

1

正如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事件内/ 事件后可靠地使用它(通常就足够了,至少对于我们正在处理的事情而言)。


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

不过,这未经测试。=)


3
到您save_post发布帖子时,该帖子本身已经已经保存到数据库中,因此get_posts将返回当前帖子。
史蒂芬·哈里斯

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

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()以构建更合适的方案。

参见Codex中的get_post_status()发布状态

可能的值为:

  • “发布”-已发布的帖子或页面
  • “待审核”-帖子待审核
  • “草稿”-处于草稿状态的帖子
  • “自动草稿”-新创建的帖子,没有内容
  • “未来”-将来发布的帖子
  • “私人”-对未登录的用户不可见
  • '继承'-版本。参见get_children。
  • “垃圾箱”-帖子在垃圾箱中。在2.9版中添加。

我不认为这能达到要求。如果我创建一个新帖子,然后单击“发布”,save_post()则将首次执行该命令,但是在执行过程中,get_post_status()它仅返回“发布”状态,而不会返回“草稿”状态。
cgogolin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.