Support » Developing with WordPress » $wp-query->queried_object not set for draft posts

  • Alessandro Fazzi

    (@pioneerskies)


    I noticed something that I consider a discrepancy: having

    * a page in draft (with public visibility for what it worth)
    * a post in draft (with public visibility for what it worth)

    and

    * reaching both with the browser as anonymous user

    the first one will generate a $wp_query with a queried_object set up, while the second one will have a null queried_object.

    Could it be an environment related problem? I tried to stop with a debugger in the highest point possible in a theme and I could say I have no filters/hooks/anything acting on the query.

    The question is: is it intended? Is it a problem of mine?

    I’m working on intercepting requests done to private/draft posts/pages and this “problem” is annoying me a lot 🙂

    Thanks in advance for your thoughts and advices

Viewing 6 replies - 1 through 6 (of 6 total)
  • Joy

    (@joyously)

    Drafts are not shown to anonymous users (the public), so if you are doing your own query, that would be the problem. The query should contain a status clause looking for “Published”.

    Moderator bcworkz

    (@bcworkz)

    Probably saying the same as Joy in a different way:
    A quick test verifies the queried object for draft posts is indeed defined when previewed by a logged in user, so the issue would be in how you are allowing the public to view drafts.

    Alessandro Fazzi

    (@pioneerskies)

    Hello everybody and thanks for your replies.

    I dived a bit in the problem, read your comments and I have to add some news and new bits to the scenario. Let’s try:

    * I’ve wordpress 5.2.2, no plugins, a theme with only an index.php file where i put an xdebug breakpoint in order to debug the **default unaltered global $wp_query** generated by WP
    * I’ve permalinks with nice urls on (postname)
    * I create a new page with a title
    * I publish the page, obtaining a nice url like http://localhost:8080/my-page
    * I navigate in an anonymouse browser window
    * the debugger stops and my control expression on $wp_query->queried_object_id shows me the correct post ID
    * back to the page edit, I switch back to draft
    * I open in another tab the preview link like http://localhost:8080/?page_id=2&preview=true
    * my control expression shows me null as expected
    * now I switch back to the previows anonym tab on the url http://localhost:8080/my-page and reload the page
    * control expression shows me the post ID!

    Note: this does not happen when url rewriting (nice urls) are turned off.

    I know this is a sort of an edge case, but this scenario is making my relying on get_queried_object_id() unreliable when an editor has bookmarked a public url and than switched back to draft.

    I think this is happening because when url rewriting is on the query to the draft page will anyway populate $wp_query->query_vars['pagename'], thus entering in this case when parsing the query: https://github.com/WordPress/WordPress/blob/master/wp-includes/class-wp-query.php#L985

    The result is that queried_object is populated if an unauthenticated user is querying a “somehow existent” URL even if corresponding to a draft object.

    Keep in mind I do not need to solve problems about my business logic but to understand the reliability of queried_object property.

    Thanks again

    Moderator bcworkz

    (@bcworkz)

    All I can tell you is the $wp_query global is consistently assigned a post object when viewing draft posts when logged in. Since the public cannot normally view draft posts, I cannot test any further to confirm or deny your allegation. It stands to reason something about allowing the public to see drafts is interfering with the post object being assigned to $wp_query.

    If you don’t wish to solve what that is, then I guess you cannot rely upon $wp_query. You’d need to get the requested object by other means. For example, get the request from “request” filter or $_SERVER and make your own query.

    But something is not adding up. If $wp_query is unassigned, how can the template be outputting post content? The standard loop relies upon $wp_query methods and properties to operate. If post content is output, where is it coming from if not $wp_query?

    @bcworkz your comments are always precious and spotted. Thank you very much.

    I’ll reveal a bit more around what I’m actually doing.

    I’m not trying to highjack the CMS’s approach about drafts, but I’ve implemented a 401 reply (header and template) aside of the default 404. In my scenario I need to differentiate between unpublished/nonexistent contents and existent but privately accessible contents, while WordPress by default (afaik) goes on 404 all the way down.

    So I set a header and will show static content: I’m not interested in accessing contents. **But** my logic never expected to have a situation where an anonymous user visiting a draft’s URL would make the queried_object populated.

    My expectation would be to **not** have the queried_object.

    Moreover when you say

    Since the public cannot normally view draft posts

    you’re right, but my test want to demonstrate that, even if the post won’t be viewed, the queried_object will get populated, thus I think everyone would be able to test that scenario with a simple var_dump(get_queried_object_id()) in theme’s main index.php file.

    Probably I should use other data/property to build my logic up (post count? a switch on get_post_status()?); but the fact per se let me think it was enough strange to be shared. 🙂

    Moderator bcworkz

    (@bcworkz)

    I did check get_queried_object() on a theme template to be sure I was not making bad assumptions. But I could only test draft posts while logged in, where $wp_query->queried_object is reliably assigned a post object. I don’t doubt that it could be unreliable if one does something unusual to cause public visibility of drafts, but I could not verify this myself one way or the other. Thanks for sharing.

Viewing 6 replies - 1 through 6 (of 6 total)
  • You must be logged in to reply to this topic.