How does WordPress know if a pending post hasn’t been published yet?

If WordPress has a newly created pending post, when you publish it the timestamp on the post is set at the time of publishing. If you publish a post, then set the post status to pending, the timestamp does not update when you re-publish it. How does it know? And why does it matter?

If you have a plugin, eg bbPress, and want the time the post is first created to be the time of the post, even if the post status is initially set to pending to be held for moderation, can you change this behaviour? Oh that’s not clear… hang on.

This is how it works now:

7:01am – Blaise posts which gets caught and whose post status is set to pending
8:23am – Imogen looks at Blaise’s post and publishes it

The timestamp on the post is 8:23am, the time Imogen published it.

But what if you want the timestamp to be 7:01am, the original time Blaise tries to post? Can you do that?

Sure! All you have to do is explicitly set post_date_gmt in the args you pass to wp_insert_post and it will use that value. It would be silly not to set it to the current time as that’s the time published posts get. So $args[‘post_date_gmt’] = current_time(‘mysql’);

There’s also a filter for inserting or updating post data: wp_insert_post_data. The filter will be applied whenever a post is inserted or updated, so keep that in mind if you use it.

A bit more detail

When a post is inserted in WordPress and the post status is set to pending for whatever reason, post_date_gmt is set to ‘0000-00-00 00:00’ in wp-includes/post.php#L3204 or thereabouts. The code changes so line numbers will change too. Comments below are mine.

// if post_date_gmt is empty or already set to 0000-00-00 00:00:00,
// you will need to see if it needs to updated or set
if ( empty( $postarr['post_date_gmt'] ) || '0000-00-00 00:00:00' == $postarr['post_date_gmt'] ) {

// check to see if the post status is pending or if it's a draft
if ( ! in_array( $post_status, array( 'draft', 'pending', 'auto-draft' ) ) ) {

// if it's not pending or a draft, then post_date_gmt is the same as the post_date in GMT
$post_date_gmt = get_gmt_from_date( $post_date );

}else{ // if it is pending or a draft, then post_date_gmt is 0000-00-00 00:00:00

$post_date_gmt = '0000-00-00 00:00:00';

} // the end of the interior if/else statement
} // the end of checking to see if post_date_gmt is empty or set to 0s

else { // if you have $postarr['post_date_gmt'], then use that
$post_date_gmt = $postarr['post_date_gmt'];
}

$postarr is the array of arguments passed to the wp_insert_post function which you can see here. $post_status and $post_date have already been set by this point and it should be obvious what they are.

So that’s how post_date_gmt is set. Now what happens when a post is updated? Here is a link to the codex entry on wp_update_post.

WordPress looks at post_date_gmt to see if a post has a published time. It doesn’t use this as the published time (it uses post_date), it just checks it and if the post status is pending or a draft, sets the post_date to the current time (ie the time you’re updating it) and clears post_date_gmt. This happens around here in /wp-includes/post.php#L3570. Again, comments are mainly mine.

// Drafts and pending posts which haven't been published (ie post_date_gmt =='0000-00-00 00:00:00')

// shouldn't be assigned a date unless explicitly done so by the user by setting 'edit_date' as a key with a value
// in the array passed to wp_update_post. $clear_date is the variable which will be used to change the date or not.

if ( isset( $post['post_status'] ) && in_array($post['post_status'], array('draft', 'pending', 'auto-draft')) && empty($postarr['edit_date']) &&
('0000-00-00 00:00:00' == $post['post_date_gmt']) )
$clear_date = true;
else
$clear_date = false;

...

if ( $clear_date ) {
$postarr['post_date'] = current_time('mysql'); // If the date is to be cleared, set the post date to the currnet time
$postarr['post_date_gmt'] = ''; // If the date is to be cleared, set post_date_gmt
}

...

// see note below
return wp_insert_post( $postarr, $wp_error );
}

Note: wp_update_post uses wp_insert_post to do the actual updating of the database. How does wp_insert_post know whether to update or insert? It looks for a key of ‘ID’ in the array you pass to it.

If you want to not update the post_date to the current time when saving a draft or pending post that hasn’t been published, then simply set a key of ‘edit_date’ with a value in the array you pass to wp_update_post. I can’t think of a situation in which you’d do this instead of changing the array passed to wp_insert_post, but you might think of one!

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s