Make WordPress Core

Opened 2 years ago

Closed 2 years ago

#56948 closed defect (bug) (fixed)

WP_Query::the_post causes a type warning when querying for ids, not full post objects

Reported by: konyoldeath's profile konyoldeath Owned by: peterwilsoncc's profile peterwilsoncc
Milestone: 6.1.1 Priority: normal
Severity: normal Version: 6.1
Component: Query Keywords: has-patch has-unit-tests commit fixed-major dev-reviewed
Focuses: performance Cc:

Description

Hello,

there is error on newest version of wordpress (6.1).

Temporary, I was able to supress the error message by adding:
if(!empty($value->$field)) and if(!empty($value[ $field ]))

Reference: https://developer.wordpress.org/reference/classes/wp_list_util/pluck/

Change History (22)

#1 follow-up: @dd32
2 years ago

  • Keywords reporter-feedback added

Hi @konyoldeath,

It sounds like some code is passing the incorrect value to the function. Would you be able to do some more debugging to determine what's calling wp_list_pluck()?

The simplest way would be inspecting the return value of wp_debug_backtrace_summary() on the line preceding it:

			foreach ( $this->output as $key => $value ) {
				if ( is_object( $value ) ) {
					$newlist[ $key ] = $value->$field;
				} else {
					// Debugging:
					if ( ! is_array( $value ) ) {
						error_log( wp_debug_backtrace_summary() );
						// or, show it:
						// var_dump( wp_debug_backtrace_summary() );
					}
					$newlist[ $key ] = $value[ $field ];
				}
			}

#2 in reply to: ↑ 1 @konyoldeath
2 years ago

Hello @dd32

Thank you for your response.

I've tried the debugging methods you mentioned, this is the debugging messages using var_dump:

string(755) "require('wp-blog-header.php'), require_once('wp-includes/template-loader.php'), include('/themes/astra/single.php'), astra_content_loop, do_action('astra_content_loop'), WP_Hook->do_action, WP_Hook->apply_filters, Astra_Loop->loop_markup, do_action('astra_template_parts_content'), WP_Hook->do_action, WP_Hook->apply_filters, Astra_Loop->template_parts_post, get_template_part, locate_template, load_template, require('/themes/astra/template-parts/content-single.php'), astra_entry_after, do_action('astra_entry_after'), WP_Hook->do_action, WP_Hook->apply_filters, Astra_Related_Posts_Markup->astra_related_posts_markup, Astra_Related_Posts_Markup->astra_get_related_posts, WP_Query->the_post, update_post_author_caches, wp_list_pluck, WP_List_Util->pluck"

I'm using wp astra themes, the warning message showed up after I update my webiste to the most recent version of wordpress. The warning message does not showed on previous wordpress version.

#3 @dd32
2 years ago

  • Component changed from General to Query
  • Keywords reporter-feedback removed

Thank you @konyoldeath that helps a great deal!

Looks like Astra calls WP_Query( [ 'fields' => 'ids', ... ] ) and then loops over that, so $this->posts is an array of ints, not an array of posts.

Astra Loop and the Query.

I'm not familiar enough with the core code to go further here, but documenting the above for others to follow up with.

Introduced in [53482] / #55716 cc @spacedmonkey, @timothyblynjacobs, @peterwilsoncc

#4 @dd32
2 years ago

  • Milestone changed from Awaiting Review to 6.1.1

Marking for 6.1.1 for tracking purposes.

#5 @peterwilsoncc
2 years ago

At a guess, prior to priming the user cache in WP_Query::the_post() there will need to be a check for WP_Post objects, similar to that used in WP_Query::setup_postdata().

I think that will be safer than checking the type of fields requested as the check can remain consistent even if the fields argument of WP_Query is extended.

Thanks for the report @konyoldeath!

#6 @lozula
2 years ago

I have the same issue, running a custom WP_Query with fields => ids specified as an argument results in the php warning above. Commenting out that line in my query solves the error but as all I need are the ids it seems like it would be less efficient.

#7 @TimothyBlynJacobs
2 years ago

At a guess, prior to priming the user cache in WP_Query::the_post() there will need to be a check for WP_Post objects, similar to that used in WP_Query::setup_postdata().

I think that action makes sense to me as well. We could probably run an array_map( 'get_post', $posts ) since the post IDs will need to be transformed into full WP_Post objects anyways by ::setup_postdata.

I think we should consider firing a _doing_it_wrong when using a WP_Query with fields set to ids and using the loop methods since those require fetching a post which defeats any performance optimization of making an ids query.

#8 @TimothyBlynJacobs
2 years ago

  • Summary changed from (WordPress 6.1) Trying to access array offset on value of type int in wp-includes/class-wp-list-util.php on line 170 to WP_Query::the_post causes a type warning when querying for ids, not full post objects

This ticket was mentioned in PR #3553 on WordPress/wordpress-develop by @peterwilsoncc.


2 years ago
#9

  • Keywords has-patch has-unit-tests added; needs-patch removed

#10 @peterwilsoncc
2 years ago

In the linked pull request:

  • WP_Query::the_post() only attempts to warm the author cache if the posts array contains WP_Post objects
  • Added a test to ensure the author cache is warmed when returning all fields.
  • Added a test to ensure there isn't an error if a subset of fields is returned. This uses assertTrue( true ) as I couldn't find a way to excpectNoError

I experimented with warming the cache when a subset of fields was requested (either ids or id=>parent) but it was a little complex with the latter as there's no way of knowing whether the developer intends to use the posts or the post parents.

I could be convinced to warm the cache for the post parents as WP_Query::the_post() will set up the loop using the parent IDs. However, that's probably best considered in a ticket for a major release.

#11 @TimothyBlynJacobs
2 years ago

I experimented with warming the cache when a subset of fields was requested (either ids or id=>parent) but it was a little complex with the latter as there's no way of knowing whether the developer intends to use the posts or the post parents.

Doesn't initializing the loop indicate that they are at minimum going to use the posts? Since each loop will call setup_postdata?

#12 @peterwilsoncc
2 years ago

Doesn't initializing the loop indicate that they are at minimum going to use the posts? Since each loop will call setup_postdata?

I guess so, yeah, for id=>parent it's just not going to be the posts they expect as setup_postdata() will use the parent ID.

I've pushed a few additional commits to the linked pull request, in addition to the changes above:

  • account for the post array being either post objects or IDs
  • run _prime_post_caches() with the IDs to ensure the post objects are primed
  • convert post IDs to objects
  • ensure author cache warming is done with post objects

There is a risk it's doing unnecessary work, so feel free to push back if you feel the need.

#13 @spacedmonkey
2 years ago

I left some feedback on the PR. To make the logic easier. Other the change seems solid.

This ticket was mentioned in Slack in #core by jeffpaul. View the logs.


2 years ago

#15 @spacedmonkey
2 years ago

  • Keywords commit added

The PR looks good to me. Adding commit keyword.

#16 @spacedmonkey
2 years ago

  • Focuses performance added

#17 @mxbclang
2 years ago

  • Owner set to peterwilsoncc
  • Status changed from new to assigned

@peterwilsoncc Assigning over to you for a quick review and commit, thanks!

#18 @peterwilsoncc
2 years ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 54771:

Query: Prevent ID only queries erroring when starting the loop.

Ensure only full post objects are passed to update_post_author_caches() when called within WP_Query::the_post(). This prevents an error when starting the Loop for Queries initiated with a subset of fields or IDs only.

Props konyoldeath, dd32, lozula, TimothyBlynJacobs, spacedmonkey, mxbclang, peterwilsoncc.
Fixes #56948.

#19 @peterwilsoncc
2 years ago

  • Keywords fixed-major added
  • Resolution fixed deleted
  • Status changed from closed to reopened

Reopening for merging to the 6.1 branch.

#21 @TimothyBlynJacobs
2 years ago

  • Keywords dev-reviewed added

Looks good to backport.

#22 @peterwilsoncc
2 years ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 54784:

Query: Prevent ID only queries erroring when starting the loop.

Ensure only full post objects are passed to update_post_author_caches() when called within WP_Query::the_post(). This prevents an error when starting the Loop for Queries initiated with a subset of fields or IDs only.

Props konyoldeath, dd32, lozula, TimothyBlynJacobs, spacedmonkey, mxbclang, peterwilsoncc.
Merges [54771] to the 6.1 branch.
Fixes #56948.

Note: See TracTickets for help on using tickets.