I recently had a tricky WordPress problem to solve: I needed trashed items in a specific CPT visible from a custom URL on the front-end.
Unfortunately for me, the "trash" post status is explicitly coded in such a way as to prevent front-end queries. To add to my frustration, WordPress doesn't allow filtering of this behavior.
I built a custom rewrite rule that passed the post ID directly into the query based on the URL. WordPress had no trouble finding the post[ref]I inspected the query it built. Though the post existed, and was found, the result of the single template's [cci]get_posts()[/cci] would always result in a 404.[/ref], I just couldn't get the thing to display.
That was when I started stepping through [cci]get_posts()[/cci] and found this little nugget:
- If a post is found, and we're on a single post/page, WordPress will check the publication status with [cci]get_post_status()[/cci] - this function exposes no filters to allow developer overrides
- Once the post status is found, it's converted into a status object (with several useful properties, like [cci]->public[/cci]), using [cci]get_post_status_object()[/cci] - again, not filtered at all for developer use
- If the post status isn't public (i.e. [cci]->public === false[/cci]), then WordPress checks to see if we've got a protected or a private post
- If the post isn't in one of the above states - public, protected, or private - WordPress clears the found posts array, resulting in a 404
I had a trashed post I needed to view from the front end - but WordPress was blocking me!
Let's fast forward the 2 hours I spent trying to work around the issue ...
If filters are not suppressed (they aren't in my case), there's a filter that runs a few dozen lines before the status check, and another filter that runs a few dozen lines after. Since these are the only places I can hook in before WordPress throws an error, I elected to abuse these filters for my purposes.
I hook in on the [cci]posts_results[/cci] filter to modify the global [cci]$wp_post_statuses[/cci] array, making the "trash" post status public if we're querying for my specific post type.
Then, I hook in again on the [cci]the_posts[/cci] filter to undo my messy hack so further queries will be unaffected.
It's sinister, ugly, and I won't recommend it for anyone. However, it does solve my particular problem and, until WordPress creates additional hooks for controlling post statuses and visibility, it will be shipping in this plugin.
If you want to see the full code of my hack (abstracted slightly away from my CPT), check out the gist below:
I do a lot of fancy work with WordPress that, at times, has me pulling my hair out in frustration with the lack of (or uselessness of) certain hooks in WordPress core. At the same time, I never hack core.
I might, from time to time, devise a useful hook and attempt to push it upstream to the project. In this case, I did propose a couple of quick filters that will allow for more hookability inside the WordPress query.
My point isn't that we can change WordPress to be more flexible - it's that WordPress is hugely flexible as it is today.
Even though the hooks I wanted to work with didn't exist, there are hooks available that let me do what I need. Is it hacky? Yes. But until we can prove my use case isn't an edge case[ref]I highly doubt many other people will need this functionality. Would I like these features in core? Absolutely! Will they make it in? Probably not.[/ref], I can subsist on the abused hooks I referenced above.
How have you hacked WordPress - without hacking core - today?