One of the quirks with working with WordPress queries is that the default arguments may not be suitable for your application. WordPress was originally a blogging platform. Now its use has expanded to many other types of websites, including news sites and e-commerce sites.
Furthermore, with the advent of the Gutenberg block editor and Full Site Editing project, the architecture of themes is changing.
As a backend PHP developer working on large scale WordPress websites, I have a lot of familiarity with creating WordPress database queries. I’ve encountered my share of bugs, and have learned that a best practice is to always specify post_status.
What is the default post status?
The default post status depends on context. On the front end, for logged out users, the default is
publish. If the user is logged in, private is added.
For queries that run in the admin context, future, draft and pending protected post statuses are added by default.
The fact that the default depends on the request context (admin or frontend) and user authentication (logged out versus logged in) can cause hard to troubleshoot bugs.
Why is it important to specify post_status?
With the move to the block editor, you are likely to have code that runs both in the admin and on the front end of the site. One specific example is if you use the server-side-render component.
Queries that were only previously running on the front end may begin to run in the admin context, due to the evolving architecture of the WordPress editor.
Having varying results will produce inaccuracies — and, if you also cache the results, you may run into even bigger issues.
Beware of Cache Pollution
I tackled a particularly challenging bug which was caused by a combination of not specifying the post_status and subsequent cache pollution. The bug presented itself as an empty module on the front end. The query appeared to not be returning any results. A closer look showed that the query results (post IDs) were being cached in Memcache. If the cached data was generated from a query that ran admin side, it included posts that were drafts. The frontend code loaded the post IDs from the cache and then did a posts__in query to get the post objects. This second step required that the posts be published. No results were returned.