I just finished a feature for a project that uses a combination of custom post types, data imports, and updating existing posts when deleting a user (or set of users).
There’s one problem, though:
Say have you have a post that’s currently published (that is, it’s ‘post_status’ is set to ‘publish’) but, when you update the post via wp_update_post, its post_status attribute is set to ‘future.’
In order words, whenever you programmatically update a post, the status of the post is set to ‘Scheduled’ (according to the UI) and ‘future’ (according to the database column).
So what gives?
Post Status When Updating
Generally speaking, I’m not a fan of getting something to work, finding out that it does, and moving on to the next task unless I understand exactly why it didn’t work in the first place.
This isn’t to say that there aren’t times where constraints have caused this to happen (at least during working hours). But if it’s midnight, I fix a bug, and then I’m not totally sure I understand why it was apparently broken in the first place, I might as well stay up and figure it out right?
It’s like the programmer’s version of sunk cost bias.
Anyway, as outlined above, here’s the gist of the problem:
- A given post exists in WordPress.
- When a user is deleted, the system looks to see if certain content exists within a given post and, if so, removes it.
- The post is then updated using a WordPress API function.
Everything works great except there’s a problem: Whenever the post is programmatically updated, it marks the post’s status as ‘future’ in the database ultimately setting the post’s line item in the All Posts view as “Scheduled.”
There are two ways to fix this problem:
- Run a quick query directly against the database to fix the problem.
- Update the post’s arguments to use the proper time in GMT (I’ll cover this more in a moment).
If you opt for the first solution, then make sure you use the prepare function and make sure you execute the query after the update function is returned.
If you opt for the second solution, then explicitly update the properties of the post object before passing it to the update function.
I’m not one to say there isn’t a place for either of these solutions when working on a project, but the question remains:
Why is WordPress marking a post scheduled for the future when the post, before going through the update procedure, was set to publish?
And if you’re not familiar with the rest of the arguments that are passed to WordPress when updating a post, it will take some time to track it down.
Understanding The Problem
For the sake of avoiding writing a direct database query, I opt to go with the second solution because it’s cleaner (though it doesn’t make it any less confusing).
To figure out why this behavior happens, you can ask another developer or debug the code. Given that I was working on this late at night, I opted for the latter.
I’m not going to talk through all of the breakpoints and watches that I set, so I’ll try to make this as concise as possible.
Notice that within the conditional, we’re not working with an attachment and we’re working with a post status of ‘publish.’ So we’re going to hit the first conditional within the outer conditional (a bit confusing isn’t it?).
Now there’s a variable, $post_status, maintaining a value of publish but it’s not assigned to any particular property of the current post. If you continue tracing the code, you’ll come across the next line:
Here, you’ll see that it’s working with a set of array keys that are contained in the $postarr variable. This variable is used earlier in the code (see it here on Trac). And if you look closely, you’ll see that it first checks to see if the post_date_gmt property is empty or if its all zeroed out.
And since it’s not, it will use the value that we specified on the property when we initially called the function:
Why go back up into the function when the code has already run past this? That’s the nature of debugging. Sometimes you see variables and don’t think anything of them only to see they are used, set, manipulated, combined, or whatever else later in the code.
That’s the reality of it.
But anyway, because of that, the property will maintain the value that we supplied before calling the update function. Usually, this will be the same value as when the function started, but there may be times where you want to, say, trash a post.
And that’s grounds for using wp_delete_post. But it has its caveats, too especially around custom post types.
That gets into another post, though.