#29660 closed defect (bug) (fixed)
Functions in wp_includes/query.php assume non-null return value from get_queried_object
Reported by: | yellyc | Owned by: | SergeyBiryukov |
---|---|---|---|
Milestone: | 6.1 | Priority: | normal |
Severity: | normal | Version: | 4.0 |
Component: | Query | Keywords: | 2nd-opinion has-patch has-unit-tests php8 |
Focuses: | Cc: |
Description
There are several functions in wp_includes/query.php that use get_quried_object and assume non-null return values, namely:
- is_attachment
- is_author
- is_category
- is_tag
- is_tax
- is_page
- is_single
- is_singular
This oversight can result in frequent "Trying to get property of non-object" errors.
Attachments (2)
Change History (64)
#1
@
10 years ago
- Keywords reporter-feedback added
This was previously suggested in 21394.diff (see comment:6:ticket:21394), but the consensus in IRC was that these notices can sometimes reveal a developer error, so we probably should not just patch symptoms.
Is there a valid case for any of these template tags to be true while the corresponding queried object is empty? Could you provide a piece of code to reproduce the issue on a clean install?
#3
@
10 years ago
First of all, I am very surprised my search for open tickets did not yield the ticket in question, I apologise for the duplicate.
As for a valid case in for use of these tags in cases in which the queried object is empty, I for one make a call to is_category in a function called at wp_enqueue_scripts, which is called on many occasions, some of which don't have a queried object.
#4
follow-up:
↓ 5
@
10 years ago
As for a valid case in for use of these tags in cases in which the queried object is empty, I for one make a call to is_category in a function called at wp_enqueue_scripts, which is called on many occasions, some of which don't have a queried object.
Do you have any more details about these occasions? To draw out the logic of SergeyBiryukov's comment a bit more: https://core.trac.wordpress.org/browser/tags/4.0/src/wp-includes/query.php#L4326 The logic in WP_Query::is_page()
would only get to the get_queried_object()
check if $this->is_page
is set (line 4327). It's unclear how this would happen without get_queried_object()
having been set - it probably means that some plugin has been messing with the $wp_query
global in an unsavory way. If you can share some more info about the situations where you're seeing the error - such as the other plugins you're running - we might be able to see more clearly whether we want to suppress these warnings in core.
#5
in reply to:
↑ 4
@
10 years ago
Replying to boonebgorges:
As for a valid case in for use of these tags in cases in which the queried object is empty, I for one make a call to is_category in a function called at wp_enqueue_scripts, which is called on many occasions, some of which don't have a queried object.
Do you have any more details about these occasions? To draw out the logic of SergeyBiryukov's comment a bit more: https://core.trac.wordpress.org/browser/tags/4.0/src/wp-includes/query.php#L4326 The logic in
WP_Query::is_page()
would only get to theget_queried_object()
check if$this->is_page
is set (line 4327). It's unclear how this would happen withoutget_queried_object()
having been set - it probably means that some plugin has been messing with the$wp_query
global in an unsavory way. If you can share some more info about the situations where you're seeing the error - such as the other plugins you're running - we might be able to see more clearly whether we want to suppress these warnings in core.
Like I mentioned, I use is_category()
in a function that is called when wp_enqueue_scripts
is triggered since I have a script that I only want enqueued for a certain category.
wp_enqueue_scripts
is triggered on any request, some of which don't have a queried object at all (such as date archives, home page and search).
#6
@
10 years ago
Yes, I saw that you're calling it at wp_enqueue_scripts
. But on a vanilla WP installation, in each of the cases that you mentioned (home page, search, date archive), the 'is_page' flag at line 4327 that I mentioned above is false
. So the get_queried_object()
check at 4333 is never reached in these cases. The question is: what on your installation is making 'is_page' true at 4327? Please have a look at the plugins and other customizations that are running when this happens.
#7
@
9 years ago
Hello,
I've seen this on my site too.
Steps to reproduce:
- Install WordPress 4.1.1.
- All plug-ins are deactivated.
- Default theme "TwentyFifteen" in use.
- Set permalinks to custom structure "/%post_id%/".
- In the reading settings, set front page to display the "sample page" static page. Leave "posts page" unset.
- Log out.
- Make sure PHP error logging is enabled.
- In the browser, enter a URL for the comments feed of a non-existent post, e.g. "http://my.site.net/non/existent/place/feed/".
- Examine the PHP error log.
- Expected: no extra log messages.
- Actual: log messages, such as "Notice: Trying to get property of non-object: {path}/wp-includes/query.php(4349)". I got six similar messages in my case.
- Impact: Such URLs can be requested by web crawlers and other "bots". This will result in the accumulation of log messages. These messages are the result of core WP code behaviour and not theme nor plug-in code.
I do not believe that these messages reflect a developer error on my part, therefore I hope this adds fuel to the argument for adding a patch to check the return value of WP_Query::get_queried_object()
at line 4345 in query.php
.
Regards, Kevin Machin.
#8
follow-up:
↓ 22
@
9 years ago
darkskipper - Thanks very much for the detailed steps to reproduce. I've managed to verify. In your specific case, the problem arises from a combination of a non-existing feed request + the use of the "front page" setting in Dashboard > Settings > Reading. This leads to a number of places in redirect_canonical()
where is_front_page()
is invoked, which in turn calls is_page( get_option( 'page_on_front' ) )
. It's this last bit that's causing the PHP notice. The correct fix here is not a band-aid over the notice, but to ensure that we never get this far in the is_front_page()
chain when we're looking at a feed. I recommend something like 29660.diff - is_front_page()
ought never to return true
for feeds.
So, two questions. (1) Does anyone see a problem with this? Are there cases where is_front_page()
might be true when is_feed
? (2) yellyc - is your case similar to this one?
#9
@
9 years ago
In the mean time, here's a little "band-aid" I'm using...
remove_action ('template_redirect', 'redirect_canonical', 10);
add_action ('template_redirect', 'actRedirectCanonical', 10);
function actRedirectCanonical ()
{
@redirect_canonical (); // Quietly
}
To make the above code theme-agnostic, it can be placed in a must-use plug-in. Otherwise it can just go in a theme's functions.php
file.
#11
@
9 years ago
It's really unfortunate that this doesn't get as much attention since it's a persistent problem. The biggest issue I think is that the errors being generated don't reflect the exact issue, where it's originating from, or the cause. Right now it's all the same generic message.
I can replicate errors like this in pre_get_posts
just as I can in any other form but it doesn't tell me why it's happening. The duplicate ticket above #33729 errors out whenever passing strings to is_category()
and the category isn't found. That's not very intuitive and to get around it I have to use some pretty funky logic. If it is decided that the core errors aren't worth fixing then I think we should also dump additional information to the developers as to why the errors occur. Though, personally I think that since the functions are being used correctly then the solution should be patching the core functions to reflect these cases.
#14
@
9 years ago
Yeah, interestingly, that patch would butt up against #20899. Glad you remembered that one, @swissspidy.
This ticket was mentioned in Slack in #core by chriscct7. View the logs.
9 years ago
#16
@
9 years ago
I'm possibly repeating what is already known but since $wp_query->get_queried_object()
sets the $query_object
to null
there's a possibly in current and future edge cases that it will return a non-object.
For example - I hook into pre_get_posts
and conditionally pass a non-existing term slug to $wp_query->is_category( 'term-slug' )
. It goes and looks for the term using get_term()
and get_term_by()
which both return false and then the $wp_query->is_category()
function attempts to get properties from a null object.
This is not the case with $wp_query->is_tax( 'taxonomy', 'term-slug' )
because of this little conditional in the function:
if ( ! ( isset( $queried_object->taxonomy ) && count( $tax_array ) && in_array( $queried_object->taxonomy, $tax_array ) ) )
Now it seems like we either need to _always_ return an object from $wp_query->get_query_object()
whose properties vary depending or start adding checks into the is_*
functions for null values. Which one is more favorable because I could start patching the latter.
This ticket was mentioned in Slack in #core by jrf. View the logs.
9 years ago
This ticket was mentioned in Slack in #core by howdy_mcgee. View the logs.
9 years ago
#19
@
9 years ago
- Keywords 4.6-early has-patch needs-testing added
- Milestone changed from 4.5 to Future Release
It seems like there is significant testing required to make sure we don't cause backcompat issues, and we're already mid-beta.
Since #20899 was moved to 4.6-early, doing so here as well.
This ticket was mentioned in Slack in #core by howdy_mcgee. View the logs.
8 years ago
#21
follow-up:
↓ 53
@
8 years ago
- Keywords 2nd-opinion added; 4.6-early has-patch needs-testing removed
I remain concerned that adding empty()
checks will paper over legitimate bugs.
The code path described by @Howdy_McGee in #33729 is a legitimate way to trigger the PHP notice, but IMHO this is due to an underlying problem with the semantics of our is_*
functions.
What does it mean to say $this->is_category()
? Does it mean that a category was *requested*? Or does it mean that you're viewing an actual category? The way WP_Query
currently works, the answer depends on when you ask the question:
- At or before 'pre_get_posts',
is_category
is based solely on the results of the rewrite rule, *not* on a database query. So onexample.com/category/foo
, when 'foo' does not exist,$this->is_category
is *true* and$this->is_404
is *false*. - If you ask the question after
WP::handle_404()
, then$this->is_category
is *false* and$this->is_404
is *true*.
Which is "correct"? It depends on whether you think the is_*
flags should reflect the intent of the request, or the results of the request. It seems to me that is_404
always refers to the query results - why would you _intend_ to query a 404? - so I think the latter is the case. But if I'm right about this, then is_*
queries are pretty much unreliable anytime before 'wp'
. See also #14729.
Alternatively, it would be possible to modify the way that parse_query()
works, so that flags like is_category
are set back to false if the requested object does not exist. But this will mean doing an additional database query during every page request. There are a bunch of existing tickets related to this: #31355, #27015, #21790. It is a pretty major change to the way WP_Query
works, but it may be required if we're going to promise developers that they can use the conditional is_*
methods at 'pre_get_posts'.
In any case, given the above, I'm against papering over the error. Developers should be aware that is_category()
is not accurate at 'pre_get_posts'. If anything, we should make the error message more descriptive.
#22
in reply to:
↑ 8
@
8 years ago
In the same light here's some other ways to trigger the is_page()
query errors. The deeper issue has already been pointed out by boonebgorges in #comment8 that WP is looking for non-existent feeds and is_front_page() returns errors:
1) Assign a Front page
2) Create and Publish a new page
3) Change / Update the page slug and visit /old-slug/feed/
Alternatively, if you trash the page and visit the trashed slug /page-slug/feed/
you will also trigger the errors:
Notice: Trying to get property of non-object in /wp-includes/query.php on line 4520 Notice: Trying to get property of non-object in /wp-includes/query.php on line 4522 Notice: Trying to get property of non-object in /wp-includes/query.php on line 4524
#23
@
8 years ago
Hey, I was pointed to this ticket from https://github.com/woothemes/woocommerce/issues/11778
Seeing as the codex states that conditional functions should work after posts_selection, I shouldn't need to worry about notices being thrown when using is_singular during template_redirect hook.
At the very least, the code should check it's dealing with objects to avoid notices.
disclaimer; not looked too deep at the code yet, just adding that this is indeed a bug.
#24
@
8 years ago
Confirming this is a thing.
Notice: Trying to get property of non-object in /var/www/html/wp-includes/class-wp-query.php on line 3516 Notice: Trying to get property of non-object in /var/www/html/wp-includes/class-wp-query.php on line 3518 Notice: Trying to get property of non-object in /var/www/html/wp-includes/class-wp-query.php on line 3520
How I'm getting it to generate:
<?php add_filter( 'pre_get_posts', function( \WP_Query $query ) { if ($query->is_tax() || ( $query->is_category() && ! $query->is_category('blog') )) { $query->set( 'orderby', [ 'title' => 'ASC' ] ); } return $query; });
That's rather simple, shouldn't be running into trouble with something like this.
- Is it a taxonomy? Yes.
- Is it a category? Yes.
- Is it THIS (blog) Category? *project explodes*.
Would be nice to fix this.
#32
@
4 years ago
[08-Apr-2020 14:48:45 UTC] PHP Notice: Trying to get property of non-object in {path}/wp-includes/class-wp-query.php on line 3998 [08-Apr-2020 14:48:45 UTC] PHP Notice: Trying to get property of non-object in {path}/wp-includes/class-wp-query.php on line 4000 [08-Apr-2020 14:48:45 UTC] PHP Notice: Trying to get property of non-object in {path}/wp-includes/class-wp-query.php on line 4002
6 years... and counting.
It would be nice if you guys could at least squelch these error log entries yourself until you decide how you're going to deal with it. Returning a null get_queried_object()
to a function that demands an object is_page()
just cost me the entire day only to discover that the solution is to stuff a sock in WP's mouth.
#33
follow-up:
↓ 34
@
4 years ago
Maybe until it is totally fixed we can use function calls like this to stop logging those particular notices -
@is_woocommerce();
#34
in reply to:
↑ 33
;
follow-up:
↓ 35
@
4 years ago
Replying to utsavmadaan823:
Maybe until it is totally fixed we can use function calls like this to stop logging those particular notices -
@is_woocommerce();
Error suppression operators are more of a hindrance than a helper. I don't think ( and hope ) any patches with suppression operators are being accepted as it's against general coding standards.
#35
in reply to:
↑ 34
@
4 years ago
Replying to Howdy_McGee:
Replying to utsavmadaan823:
Maybe until it is totally fixed we can use function calls like this to stop logging those particular notices -
@is_woocommerce();
Error suppression operators are more of a hindrance than a helper. I don't think ( and hope ) any patches with suppression operators are being accepted as it's against general coding standards.
Please suggest me alternative solution i am open to any solution. I was redirected to this ticket when i was getting these notice using woocommerce (calling is_woocommerce()). Reading this i think the ticket hasn't been resolved so suggested that suppression thing that someone may use if they know what they are doing.
NOTE - I am not suggesting this to Developers rather users facing this issue and are irritated by this notice.
This ticket was mentioned in PR #556 on WordPress/wordpress-develop by dd32.
4 years ago
#37
- Keywords has-patch has-unit-tests added
Avoid PHP Notices in WP_Query when get_queried_object() returns false.
Trac ticket: https://core.trac.wordpress.org/ticket/29660
#38
@
4 years ago
Ran into this on WordPress.org, started a PR, found this ticket and merged query-patch.diff into PR 556.
The unit test shows the absurdity of this, but it kind of makes sense.
There's two different kinds of checks being asked for here:
is_page()
- Is this request for a page? Might be a 404, and that's okay.is_page( 'page-name' )
- Is this a request for THIS page name? (Can never be true for a 404)
So as a result, having a page query for page-name
that 404's is still a page request, but it's not a page-name
page request as the request 404'd.
I think based on the above logic this is probably safe and ideal to be fixed in this manner, however, I would not be against having all of these fields set to false
when is_404()
- but that only happens for the main query, not for new queries like in this unit test (A stand-alone query is never a 404, only a zero-results query).
#40
@
4 years ago
- Milestone changed from Future Release to 5.7
- Owner set to SergeyBiryukov
- Status changed from new to reviewing
As seen in #52510, this is now more prominent with PHP 8 (warnings instead of notices).
Moving to attempt to figure out the way forward from comment:21 one way or another for 5.7.
#41
@
4 years ago
- Milestone changed from 5.7 to 5.8
I don't think we'll make it in time for 5.7 at this point.
#43
@
3 years ago
- Milestone changed from 5.8 to 5.9
With 5.8 beta 1 in less than an hour, I'm afraid I personally don't have the time to review this in enough detail. I'm going to punt to 5.9 as it seems really close.
#44
@
3 years ago
I have same issue with PHP 8 and latest WP version:
PHP Warning: Attempt to read property "post_type" on null in /xxxx/xxxx/xxxxx/xxxx/wp-includes/class-wp-query.php on line 4196 PHP Warning: Attempt to read property "post_type" on null in /xxxx/xxxx/xxxxx/xxxx/wp-includes/class-wp-query.php on line 4196 PHP Warning: Attempt to read property "post_type" on null in /xxxx/xxxx/xxxxx/xxxx/wp-includes/class-wp-query.php on line 4196 PHP Warning: Attempt to read property "post_type" on null in /xxxx/xxxx/xxxxx/xxxx/wp-includes/class-wp-query.php on line 4196 PHP Warning: Attempt to read property "post_type" on null in /xxxx/xxxx/xxxxx/xxxx/wp-includes/class-wp-query.php on line 4196 PHP Warning: Attempt to read property "post_type" on null in /xxxx/xxxx/xxxxx/xxxx/wp-includes/class-wp-query.php on line 4196 PHP Warning: Attempt to read property "post_type" on null in /xxxx/xxxx/xxxxx/xxxx/wp-includes/class-wp-query.php on line 4196 PHP Warning: Attempt to read property "post_type" on null in /xxxx/xxxx/xxxxx/xxxx/wp-includes/class-wp-query.php on line 4196 PHP Warning: Attempt to read property "post_type" on null in /xxxx/xxxx/xxxxx/xxxx/wp-includes/class-wp-query.php on line 4196 PHP Warning: Attempt to read property "post_type" on null in /xxxx/xxxx/xxxxx/xxxx/wp-includes/class-wp-query.php on line 4196
#45
@
3 years ago
Hi everyone, so for now best solution is to replace original code with agengineering code from this ticket: https://core.trac.wordpress.org/ticket/49024 ? It stops PHP warnings in my website, but is it safe to use? Thank you :)
<?php /** * Is the query for an existing single page? * * If the $page parameter is specified, this function will additionally * check if the query is for one of the pages specified. * * @see WP_Query::is_single() * @see WP_Query::is_singular() * * @since 3.1.0 * * @param int|string|array $page Optional. Page ID, title, slug, path, or array of such. Default empty. * @return bool Whether the query is for an existing single page. */ public function is_page( $page = '' ) { if ( ! $this->is_page ) { return false; } if ( empty( $page ) ) { return true; } $page_obj = $this->get_queried_object(); $page = array_map( 'strval', (array) $page ); if ( ! empty( $page_obj ) && in_array( (string) $page_obj->ID, $page ) ) { return true; } elseif ( ! empty( $page_obj ) && in_array( $page_obj->post_title, $page ) ) { return true; } elseif ( ! empty( $page_obj ) && in_array( $page_obj->post_name, $page ) ) { return true; } else { foreach ( $page as $pagepath ) { if ( ! strpos( $pagepath, '/' ) ) { continue; } $pagepath_obj = get_page_by_path( $pagepath ); if ( $pagepath_obj && ( $pagepath_obj->ID == $page_obj->ID ) ) { return true; } } } return false; } ?>
#46
follow-up:
↓ 56
@
3 years ago
- Milestone changed from 5.9 to Future Release
Query changes by design need careful consideration and plenty of soak time to ensure nothing breaks. With 5.9 feature freeze ~2 days away and Beta 1 ~9 days, it's too late in the release cycle for a change to query. Punting this out of 5.9. As the next milestone is not yet available, moving to Future Release
. Once available, feel free to move into the next release.
#49
@
2 years ago
I'm getting similar warnings while trying to call this function on PHP version 8:
Warning: Attempt to read property "ID" on null in /Users/wedevs/Sites/Theme_Rat/wp-includes/class-wp-query.php on line 4123 Warning: Attempt to read property "post_title" on null in /Users/wedevs/Sites/Theme_Rat/wp-includes/class-wp-query.php on line 4125 Warning: Attempt to read property "post_name" on null in /Users/wedevs/Sites/Theme_Rat/wp-includes/class-wp-query.php on line 4127
How to reproduce this warning:
add_action( 'posts_results', 'my_prefix_func_name', 10, 2 ); function my_prefix_func_name( $posts, $query ) { if ( is_page() ) { // here those warnings are triggred // extra logic } return $posts; }
#52
@
2 years ago
- Keywords php8 added
Adding the php8
keyword. As noted in comment:40, the notices were promoted to warnings in PHP 8, and the issue is more prominent now.
I think comment:21 should still be addressed for this to move forward, maybe with a _doing_it_wrong()
message similar to the ones we have when calling conditional tags too early:
if ( ! isset( $wp_query ) ) { _doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.' ), '3.1.0' ); return false; }
#53
in reply to:
↑ 21
@
2 years ago
Replying to boonebgorges:
What does it mean to say
$this->is_category()
? Does it mean that a category was *requested*? Or does it mean that you're viewing an actual category? The wayWP_Query
currently works, the answer depends on when you ask the question:
And to make it even more complicated, is_category()
and is_author()
do not necessarily mean they're archives of that type, it can mean that it's a singular view but with an additional author/taxonomy check/request (ie. https://example.org/post-name/?cat=unknown-cat-slug is both $this->is_singular
and $this->is_category
, and even though it might only resolve to the post, get_queried_object()
will be null
as it tries to return a category first).
There's far more problems with the conditionals than just when you call them..
#55
@
2 years ago
I'm getting similar warnings under PHP 8, with any urls of my website, ending with /feed/;
Attempt to read property “post_type” on null in /wp-includes/class-wp-query.php on line 4338
(the feed link gets displayed, however the warning is at the top of the page - each /feed page)
I've searched for that warning message on Google and I can say came up with almost hundreds of websites indexed with that warning message in the results.
So, it seems that’s a very common problem.
The warning appears only in /feed/ pages, the mentioned line in php file contains:
return in_array( $post_obj->post_type, (array) $post_types, true );
And I must say that our webserver's error_log file is growing extremely fast with this message, and unfortunately we cannot disable the error_log for several legal and maintenance reasons.
Wordpress version: 6.0.1
PHP version: 8.0.20
#56
in reply to:
↑ 46
@
2 years ago
Replying to hellofromTonya:
Query changes by design need careful consideration and plenty of soak time to ensure nothing breaks. With 5.9 feature freeze ~2 days away and Beta 1 ~9 days, it's too late in the release cycle for a change to query. Punting this out of 5.9. As the next milestone is not yet available, moving to
Future Release
. Once available, feel free to move into the next release.
Then honestly, freeze features until things like this can be addressed. Eight years is insane, and there was plenty of time for things to soak since this was first reported. Now with 8.2 in Beta, the window for actually addressing this is becoming smaller and smaller before someone needs to rush in and actually spend time on it.
#57
@
2 years ago
I agree with @bwbama that this issue has been open a tad too long.
What I've done for now to keep the error log from growing unnecessarily, is to return null early when accessing the properties that cause the error message. This doesn't change any functionality, as null
is returned anyway, it's just a matter of not outputting the error message.
/wp-includes/class-wp-query.php
around lines 4188 onward:
Changing $page_obj->ID
to $page_obj?->ID
Also for other properties $page_obj?->post_title
, $page_obj?->post_name
.
Note that I'm changing the file in core here, so it's needed once with every new WP release.
This ticket was mentioned in Slack in #core by audrasjb. View the logs.
2 years ago
#59
@
2 years ago
same issue after updating to php 8, any fix for this??
Attempt to read property "post_type" on null in wp-includes/class-wp-query.php on line 4338
This ticket was mentioned in Slack in #core by desrosj. View the logs.
2 years ago
SergeyBiryukov commented on PR #556:
2 years ago
#62
Thanks for the PR! Merged in r54496.
A patch to add null return checks for get_queried_object