Make WordPress Core

Opened 6 years ago

Closed 5 years ago

#47824 closed defect (bug) (fixed)

get_the_content() still causes a PHP warning outside of the loop

Reported by: sergeybiryukov's profile SergeyBiryukov Owned by: sergeybiryukov's profile SergeyBiryukov
Milestone: 5.5 Priority: normal
Severity: normal Version: 5.2
Component: Posts, Post Types Keywords: has-patch has-unit-tests early
Focuses: Cc:

Description

Background: #42814 / [44941]

Current state of things on PHP 7.2+:

  • Calling the_excerpt() before the loop works as expected, displaying the excerpt of a post in the $post global.
  • Calling the_content() before the loop results in a PHP warning: count(): Parameter must be an array or an object that implements Countable in wp-includes/post-template.php on line 310

get_the_excerpt(), when called without an explicit post object, falls back to the $post global, then passes the post object to wp_trim_excerpt(), which passes it to get_the_content(), and the latter calls generate_postdata().

get_the_content(), when called without an explicit post object, falls back to the $post global too, but makes an incorrect assumption that other globals (specifically $pages) are always set up in that case.

If calling the_content() outside of the loop should be disallowed, then an appropriate _doing_it_wrong() message should be added instead of the cryptic PHP warning.

If calling the_content() outside of the loop should still be supported and properly fall back to the $post global, then in_the_loop() check should be added to the condition that determines when to rely on the globals.

I'm leaning towards the latter, for consistency with get_the_excerpt().

Attachments (4)

47824.diff (461 bytes) - added by SergeyBiryukov 6 years ago.
47824.2.diff (1.0 KB) - added by SergeyBiryukov 6 years ago.
47824-tw.patch (1003 bytes) - added by tessawatkinsllc 5 years ago.
Patches this defect by adding an optional $post parameter to function "the_content" that passes it to the function "get_the_content" since it was added since 5.2.0., and falls back to the global $post variable so it does not break when used outside "the loop".
47824.3.diff (1.7 KB) - added by dontdream 5 years ago.
In this version, get_the_content() avoids using globals altogether.

Download all attachments as: .zip

Change History (31)

@SergeyBiryukov
6 years ago

#1 @SergeyBiryukov
6 years ago

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

#2 follow-up: @spacedmonkey
6 years ago

Why not just put an is_countable check in here at line 310?

#3 in reply to: ↑ 2 @SergeyBiryukov
6 years ago

Replying to spacedmonkey:

Why not just put an is_countable check in here at line 310?

That would solve the warning, but would also just hide the fact that other globals are not properly set up either.

#4 follow-up: @spacedmonkey
6 years ago

I am not sure why the globals are not setup here. Why not add a isset check for the globals then around the 281 line and run generate_postdata to make sure they do exist?

elseif ( !isset($page) or !isset($pages)){
  $elements = generate_postdata( $_post );

#5 in reply to: ↑ 4 @SergeyBiryukov
6 years ago

Replying to spacedmonkey:

Why not add a isset check for the globals then around the 281 line and run generate_postdata to make sure they do exist?

That's an option too. They should always be set up in the loop, though, so just checking for in_the_loop() seems simpler.

#6 @SergeyBiryukov
6 years ago

#46322 was marked as a duplicate.

#7 @SergeyBiryukov
6 years ago

  • Owner set to SergeyBiryukov
  • Resolution set to fixed
  • Status changed from new to closed

In 46079:

Posts, Post Types: Avoid a PHP warning when the_content() is called outside of the loop.

Fixes #47824.

#8 @SergeyBiryukov
6 years ago

  • Resolution fixed deleted
  • Status changed from closed to reopened
There was 1 failure:

1) Tests_Query_SetupPostdata::test_setup_postdata_loop
Failed asserting that '<p>global post</p>' is not equal to '<p>global post</p>'.

/var/www/tests/phpunit/tests/query/setupPostdata.php:416

Related: #24330

#9 @SergeyBiryukov
6 years ago

In 46080:

Posts, Post Types: Revert [46079] pending test failure investigation.

See #47824.

#10 @SergeyBiryukov
5 years ago

#48168 was marked as a duplicate.

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


5 years ago

#12 @peterwilsoncc
5 years ago

  • Keywords needs-refresh added; commit removed
  • Milestone changed from 5.3 to 5.4

Moving to the 5.4 milestone due to 5.3 RC1 coming soon.

#13 @SergeyBiryukov
5 years ago

#48434 was marked as a duplicate.

#14 @SergeyBiryukov
5 years ago

#48433 was marked as a duplicate.

#15 @squarecandy
5 years ago

+1 for this.

For now I'm using: get_the_content( null, false, get_the_ID() );

Is that a reasonable way to deal with it, or should I just leave my plain get_the_content() as it is and ignore the warning until this is fixed in the core?

@tessawatkinsllc
5 years ago

Patches this defect by adding an optional $post parameter to function "the_content" that passes it to the function "get_the_content" since it was added since 5.2.0., and falls back to the global $post variable so it does not break when used outside "the loop".

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


5 years ago

#17 @SergeyBiryukov
5 years ago

  • Keywords early added
  • Milestone changed from 5.4 to 5.5

#18 @dontdream
5 years ago

#49609 was marked as a duplicate.

@dontdream
5 years ago

In this version, get_the_content() avoids using globals altogether.

#19 @SergeyBiryukov
5 years ago

#49895 was marked as a duplicate.

#20 @Otto42
5 years ago

#49895 was marked as a duplicate.

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


5 years ago

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


5 years ago

#23 @davidbaumwald
5 years ago

  • Keywords needs-refresh removed

Latest patch applies cleanly and seems to be a suitable fix. Removing needs-refresh

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


5 years ago

#25 @SergeyBiryukov
5 years ago

Just noting that the latest patch has the same test failure (comment:8) as the one that was committed in [46079].

See #24330 for some history on that test. The test description says:

setup_postdata( $a_post ) followed by the_content() in a loop that does not update global $post should use the content of $a_post rather then the global post.

Going to try a bit different approach here, commit incoming.

#26 @SergeyBiryukov
5 years ago

In 48113:

Posts, Post Types: Simplify test_setup_postdata_loop().

The important part here is calling the_content() after setting up post data for another post without updating global $post.

The foreach() loop is not necessary.

Follow-up to [UT1289].

See #47824, #24330.

#27 @SergeyBiryukov
5 years ago

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

In 48114:

Posts, Post Types: Avoid a PHP warning when get_the_content() is called outside of the loop.

This ensures that $pages and other globals are only used after they have been set up in setup_postdata().

Follow-up to [44941].

Props tessawatkinsllc, dontdream, spacedmonkey, squarecandy, davidbaumwald, SergeyBiryukov.
Fixes #47824. See #42814.

Note: See TracTickets for help on using tickets.