WordPress.org

Make WordPress Core

Opened 7 months ago

Last modified 2 weeks ago

#42814 reopened defect (bug)

PHP 7.2 Warning: ...wp-includes/post-template.php on line 284

Reported by: internetwerk Owned by:
Milestone: 4.9.8 Priority: normal
Severity: normal Version: 4.5
Component: Posts, Post Types Keywords: has-patch
Focuses: Cc:

Description

Warning with PHP 7.2:

Warning: count(): Parameter must be an array or an object that implements Countable in /wp-includes/post-template.php on line 284

---> https://www.blogseye.com/convert-a-web-page-to-a-wordpress-theme-in-5-minutes/ ---> https://neu.internetwerk.de/business-webhosting/bestellformular/

Attachments (3)

42814.patch (1.5 KB) - added by Shital Patel 7 months ago.
if it is array then use count function, otherwise set default variable value zero
warning_count.png (135.8 KB) - added by Shital Patel 6 months ago.
42814.diff (1.6 KB) - added by kraftbj 5 months ago.
Updating wp_trim_excerpt to accept a post object

Download all attachments as: .zip

Change History (61)

@Shital Patel
7 months ago

if it is array then use count function, otherwise set default variable value zero

#1 follow-up: @Shital Patel
7 months ago

  • Keywords has-patch added

#2 @dd32
6 months ago

Hey @internetwerk and welcome to Trac!

Do you know what circumstances can be used to trigger these warnings? Are they duplicatable on a clean WordPress install?

Looking at 42814.patch these seem to be things which should always be arrays, knowing when it's not an array would be beneficial to fixing this.

#3 in reply to: ↑ 1 @internetwerk
6 months ago

  • Resolution set to worksforme
  • Status changed from new to closed

Thank You @Shital Patel and @dd32, it works fine!

---> https://www.internetwerk.de/webspace-domain-bestellformular/ ---> No errors, no warnings with PHP 7.2. after patch post-template.php

(Sorry for my bad English!)

#4 @dd32
6 months ago

  • Keywords needs-testing reporter-feedback added; has-patch removed
  • Resolution worksforme deleted
  • Status changed from closed to reopened

We only close tickets when the patch is committed to core.

I'm not happy with committing 42814.patch blindly, unless someone can show how to duplicate it. It seems to be patching over a larger underlying problem.

If someone can post a scenario where $pages / $content / $custom[$key] is not an array, that'd be appreciated.

#5 follow-up: @Shital Patel
6 months ago

Hello @dd32 ,

The problem is that $pages,$content,$custom[$key] could be null in some cases, and PHP 7.2 doesn't allow count(null);

So, We can set zero value.

#6 in reply to: ↑ 5 ; follow-up: @dd32
6 months ago

Replying to Shital Patel:

Hello @dd32 ,

The problem is that $pages,$content,$custom[$key] could be null in some cases, and PHP 7.2 doesn't allow count(null);

So, We can set zero value.

Yes, But I want to know *why* they're a null value, as they should always be an array unless I've missed something. That's why I want to know the steps to reproduce it.

#7 in reply to: ↑ 6 @rodrigogomes
6 months ago

Replying to dd32:

Replying to Shital Patel:

Hello @dd32 ,

The problem is that $pages,$content,$custom[$key] could be null in some cases, and PHP 7.2 doesn't allow count(null);

So, We can set zero value.

Yes, But I want to know *why* they're a null value, as they should always be an array unless I've missed something. That's why I want to know the steps to reproduce it.

@dd32 I'm getting the same error, in different WordPress installs.

I could not identify what caused it. But apparently it began to appear after I imported the demo of a premium theme.

Last edited 6 months ago by rodrigogomes (previous) (diff)

#8 @azrobbo
6 months ago

I ran into this issue while performing upgrade/failover tests against multiple WP sites at the same time - but encountered this error on only one site.

The "problem site" is very simple and is using a 3-year old premium theme by StudioPress called Executive Pro which uses Genesis (also by StudioPress) as its parent theme.

  • Because the same actions were performed against multiple sites, and only one exhibited this error, it appears to be caused by something site specific (not mere actions alone).

While, I cannot explain how to reproduce the error, I can provide this list of actions I performed that caused the error (on one site, but not others).

Note: I'm using a containerized WP implementation - each site has it's own WP container with "/var/www/html" mapped to site specific persistent storage, and share a common MySQL with seperate DB's for each site & persistent storage.

The actions performed:

  • Manually logged into each site's wp-admin and upgraded it to the latest WP version
    • at this point all sites worked great
  • Pulled the latest WP image and relaunched all the sites using the new image. (This was done to test failing-over to a new host, where images would need to be pulled.)
    • I thought this redundant, as the "/var/www/html" dir, and MySQL already contained the files & data for the new WP version from the previous step.
    • However, immediately after relaunching with the new WP image, the error appeared on the "problematic site" - but not any others.

Attempts to fix:

  • i tried restoring the DB & user HTML files from backups: (1) before the upgrade and (2) after the manual-upgrade but before pulling the image - neither stopped the error message
  • I temporarily stopped the error by commenting out lines 284-285 as they don't appear to apply to the "problematic site". (I did not need to change, or comment out, and other lines)

I can share additional information/data from the site in question if necessary (please contact me offline as I can't post it publicly).

Last edited 6 months ago by azrobbo (previous) (diff)

#9 @jlapitan
6 months ago

This error appears when you have jetpack plugin enabled

#10 @Theolobias
6 months ago

Same error on my website using WordPress 4.9.1 and PHP 7.2.0 with Jetpack Plugin activated. Deactivating Jetpack results in the error disappearing. Seems to be no issue with PHP 7.0.26.

#11 follow-up: @kenwood31
6 months ago

Hey,

Yes, it happens when Jetpack plugin is activated. After checking several settings on this plugin, I noticed this is due to the feature "publicize".

In my case, I didn't use it so I just switched it off (in Jetpack > Settings > Sharing) and the error is not displayed anymore. Hope it will help you to fix it before a real fix on this ;)

#12 in reply to: ↑ 11 ; follow-up: @Theolobias
6 months ago

Replying to kenwood31:

Hey,

Yes, it happens when Jetpack plugin is activated. After checking several settings on this plugin, I noticed this is due to the feature "publicize".

In my case, I didn't use it so I just switched it off (in Jetpack > Settings > Sharing) and the error is not displayed anymore. Hope it will help you to fix it before a real fix on this ;)

I can't confirm this - deactivating the Pubilcize-feature doesn't change anything. (Maybe in your case it's due to another PHP-version?)

#13 in reply to: ↑ 12 @rodrigogomes
6 months ago

Replying to Theolobias:

Replying to kenwood31:

Hey,

Yes, it happens when Jetpack plugin is activated. After checking several settings on this plugin, I noticed this is due to the feature "publicize".

In my case, I didn't use it so I just switched it off (in Jetpack > Settings > Sharing) and the error is not displayed anymore. Hope it will help you to fix it before a real fix on this ;)

I can't confirm this - deactivating the Pubilcize-feature doesn't change anything. (Maybe in your case it's due to another PHP-version?)

Disabling Publicize connections and Sharing buttons actually removes the error. The problem is actually in the Jetpack plugin.

#14 @bobbingwide
5 months ago

I've updated the Issue raised against Jetpack with my findings. https://github.com/Automattic/jetpack/issues/8420

For me the problem occurs when viewing an Attachment that doesn't have a caption ( i.e. excerpt ). Theme Twenry Seventeen, Jetpack 5.7

My change to get_the_content() was simpler.

if ( is_array( $pages ) ) {
		if ( $page > count( $pages ) ) // if the requested page doesn't exist
			$page = count( $pages ); // give them the highest numbered page that DOES exist
	} else { 	
		$page = 0;
	}

I didn't try fixing Jetpack.

Don't ask me why the next line works, but it does!

$content = $pages[ $page - 1 ];

$content becomes null.

Last edited 5 months ago by bobbingwide (previous) (diff)

#15 @lofesa
5 months ago

I can confirm the issue but w/o Jetpack. Only php upgraded from 7.0 to 7.2

#16 @Cibulka
5 months ago

In my case, it was a call to get_the_excerpt(), when the page had none. I have fixed it roughly this way:

global $post; $excerpt = !empty($post->post_excerpt) ? get_the_excerpt() : null;

PHP 7.2 as well.

#17 @dd32
5 months ago

  • Keywords needs-patch added; needs-testing reporter-feedback removed

Duplicated it against an attachment when Jetpack is in use (and out of development mode)

Here's a backtrace:

( ! ) Warning: count(): Parameter must be an array or an object that implements Countable in ../wp-includes/post-template.php on line 292
Call Stack
#	Time	Memory	Function	Location
1	0.0002	394584		{main}( )	.../index.php:0
2	0.0004	396520		require( '.../wp-blog-header.php' )	.../index.php:17
3	0.8743	35298240	require_once( '.../wp-includes/template-loader.php' )	.../wp-blog-header.php:19
4	0.8863	35641272	include( '.../wp-content/themes/twentyseventeen/single.php' )	.../template-loader.php:77
5	0.8863	35641272	get_header( )	.../single.php:13
6	0.8863	35641648	locate_template( )	.../general-template.php:41
7	0.8864	35641744	load_template( )	.../template.php:653
8	0.8865	35648296	require_once( '.../wp-content/themes/twentyseventeen/header.php' )	.../template.php:695
9	0.8873	35656288	wp_head( )	.../header.php:22
10	0.8873	35656288	do_action( )	.../general-template.php:2661
11	0.8873	35656664	WP_Hook->do_action( )	.../plugin.php:465
12	0.8873	35656664	WP_Hook->apply_filters( )	.../class-wp-hook.php:310
13	0.9288	35757880	jetpack_og_tags( )	.../class-wp-hook.php:286
14	0.9308	35762904	apply_filters( )	.../functions.opengraph.php:216
15	0.9308	35763304	WP_Hook->apply_filters( )	.../plugin.php:208
16	0.9853	35835632	Jetpack_Twitter_Cards::twitter_cards_tags( )	.../class-wp-hook.php:288
17	0.9918	35822616	Jetpack_Media_Summary::get( )	.../class.jetpack-twitter-cards.php:80
18	0.9920	35823920	Jetpack_Media_Summary::get_excerpt( )	.../class.media-summary.php:57
19	0.9920	35823920	apply_filters( )	.../class.media-summary.php:314
20	0.9920	35824320	WP_Hook->apply_filters( )	.../plugin.php:208
21	0.9920	35825072	wp_trim_excerpt( )	.../class-wp-hook.php:286
22	0.9920	35825072	get_the_content( )	.../formatting.php:3568

The reason this is being run into, is because Jetpacks Jetpack_Media_Summary::get_excerpt calls apply_filters( 'get_the_excerpt', $post_excerpt ); where $post_excerpt is empty, and before WP_Query::setup_postdata()/the_post() is called. get_the_content() currently expects that it'll be used within an actual post content loop (which is a fairly sane assumption to make, except plugins do weird things) Jetpack is doing it wrong here, but in a subtle way that would be expected to work by many.

Now, we can paper over this by checking if it's an array, but that's not the actual problem at play here. The issue is that get_the_content() relies upon WP_Query::setup_postdata() having being run in order to actually return the correct data, and in this case, it can't as the source variables for the content are not yet setup. The more correct fix would be to ensure that get_the_content() can split content into pages for correct return values even when it's not within the loop.

#18 @kraftbj
5 months ago

  • Component changed from General to Formatting
  • Keywords has-patch added; needs-patch removed
  • Version changed from 4.9.1 to 4.5

I see where you're going with this @dd32, but I think there's another problem in play.

First, Jetpack is doing it wrong, yup. We should just ask for the excerpt we want using Core functions (get_the_excerpt( $post );), which works as of WP 4.5 outside of the loop. ( https://github.com/Automattic/jetpack/pull/8510 )

Second, noting get_the_excerpt's relatively new ability to accept a post argument, the default filter adds wp_trim_excerpt, which has not been updated to accept this new usage of get_the_excerpt, so it'll error out on it's own (or use the global $post data instead of the specified $post).

Try running

$post = get_post( [ID of an attachment] );
get_the_excerpt( $post );

and it'll throw a notice still.

Patch incoming. Marking as issue since 4.5 based on when the $post arg was added to get_the_excerpt

Last edited 5 months ago by kraftbj (previous) (diff)

@kraftbj
5 months ago

Updating wp_trim_excerpt to accept a post object

#19 @dd32
5 months ago

Yep 42814.diff will also avoid the warning, as it prevents calling get_the_content( '' ) which is the actual underlying function which requires to be in the loop

However, it still has the same issue - It avoids it by simply using the full post_content directly rather than the processed content which respects <!--nextpage--> and <!--more--> tags. While you're right, that using the passed $post context helps and avoids this code branch in Jetpack, it doesn't fix it overall I don't think

#20 @kraftbj
5 months ago

That's fair.

So yes, one thing that needs to happen is for get_the_content to work outside the loop.

Another is, specific to the excerpt, Core incompletely adding support for get_the_excerpt working outside the loop, which my patch addresses (could say incompletely since get_the_content($post) would be ultimately the best).

Not sure if it is best to conflate both into this ticket or break them out to separate issues. At least with the excerpt issue, it is truly a bug (should have been done in 4.5) while get_the_content never intended to work outside the loop, so is more of an enhancement.

By itself, the excerpt patch not using processed content should be fine in the majority of cases, with the major exception of when the excerpt length is longer than the content before a more/nextpage jump when getting the excerpt outside of the loop, which would have previously returned the wrong excerpt (I think), since wp_trim_excerpt would only be acting on the global.

#21 @kraftbj
5 months ago

  • Milestone changed from Awaiting Review to 4.9.3

I'm bumping this to 4.9.3 so it can get some attention, specifically for resolving what (IMO) was left undone in the work that shipped in 4.5. I'm presuming that 1. I'm accurately following the code and this is functionality that's now a bug because it was missing from 4.5 and 2. having get_the_content working outside of the loop is an enhancement that should go in via another ticket.

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


5 months ago

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


5 months ago

#24 @Greg Raven
5 months ago

I’m seeing the same issue on one of my WordPress sites. When I use any version of PHP up to 7.1, the page is fine. When I switch to 7.2, I get this error message:

Warning: count(): Parameter must be an array or an object that implements Countable in /wp-includes/post-template.php on line 284

So, I compared post-template.php from one of my sites that works fine under PHP 7.2 and the one giving me the error. Each is running version 4.9.2 WordPress. However, there are subtle differences between the two post-template.php files! None of the differences is anywhere near line 284, but I’m still baffled how two supposedly identical files can have different content.

#25 @Kelderic
5 months ago

I just ran into this when I began testing with PHP 7.2. In my <head> section of my theme, I call get_the_excerpt as part of Open Graph meta tags. I have tried passing the post ID using get_the_ID, and passing $post, but I can't get rid of the error.

If we add:

if ( ! is_array($pages) ) {  
        $pages = []; 
}

At line 283 of post-template.php, we correct the issue. Long term, we need to check that all expected arrays are really arrays, and convert NULL values to empty arrays before calling count().

Last edited 5 months ago by Kelderic (previous) (diff)

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


5 months ago

#27 @williampatton
5 months ago

  • Milestone changed from 4.9.3 to 4.9.4

Moving to next release milestone.

#28 @internetwerk
4 months ago

Update to WordPress 4.9.3, same problem: "Warning: count(): Parameter must be an array or an object that implements Countable in /var/www/web8/htdocs/wp-includes/post-template.php on line 284"

#29 @avcascade
4 months ago

Also affected by this issue. Not using Jetpack, but WordPress site I tested PHP 7.2.x with is generating OpenGraph meta tags.

#30 @dd32
4 months ago

  • Milestone changed from 4.9.4 to 4.9.5

Bumping, 4.9.4 has been released.

#31 @swissspidy
4 months ago

Looking at 42814.diff, this is something covered by #36934.

#32 @swissspidy
4 months ago

#43368 was marked as a duplicate.

#33 @jrf
4 months ago

#43374 was marked as a duplicate.

#34 @pkwooster
3 months ago

Same issue on 4.9.4 multi-site with Jetpack and PHP 7.2. Backoff to 7.1 resolved the issue for now.

#35 in reply to: ↑ description @adelsonbn
3 months ago

I was able to solve the problem on my website: Disabling Publicize connections and Sharing buttons in the Jetpack plugin.

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


3 months ago

#37 @audrasjb
3 months ago

  • Milestone changed from 4.9.5 to 4.9.6

Bumping to 4.9.6 due to 4.9.5 beta release.

#38 @SergeyBiryukov
3 months ago

  • Component changed from Formatting to Posts, Post Types

#39 @SergeyBiryukov
3 months ago

#43600 was marked as a duplicate.

#40 @gsarig
3 months ago

On my case, it happens on a different scenario: on a WooCommerce eshop I created a price filter. The filter works fine with no errors or warnings. If I select a price range that has no results, though, I get the warning, even if everything else seems OK and the actual content shows the "No products were found matching your selection." message, as it should. Adding

if ( ! is_array($pages) ) {  
        $pages = []; 
}

doesn't help on my case, because then I get another Notice: Undefined offset: -1 ...on line 289, which is

$content = $pages[$page - 1];

What seems to solve it for me is simply changing the line

if ( $page > count( $pages ) )

to that:

if ( $pages && $page > count( $pages ) )

#41 @tasmer
3 months ago

Hello, I get the same issue on 4.9.1 with PHP 7.2.1.

In my case I call get_the_excerpt () from the hook wp_head and I get this warning when the excerpt is empty.

The same observation as @Kelderic and @gsarig

We should set the global $pages to an empty array if is null, because get_the_excerpt can be call outside the main loop.

$pages = is_array ($pages)? $pages: array ();

at line 262 of post-template. PHP (inside the get_the_content function)

#42 follow-up: @FPCSJames
3 months ago

This also occurs when calling wp_calculate_image_srcset(). Changing line 1206 to:

if ( ! $src_matched || ! is_array( $sources ) || count( $sources ) < 2 ) {

fixes the issue.

#43 in reply to: ↑ 42 @SergeyBiryukov
3 months ago

Replying to FPCSJames:

This also occurs when calling wp_calculate_image_srcset().

That one's already fixed in #43201, the fix will ship with 4.9.5.

#44 follow-up: @qbaf
3 months ago

Upgraded today to 4.9.5 and no changes

#45 in reply to: ↑ 44 @cezariuszmarek
3 months ago

Replying to qbaf:

Upgraded today to 4.9.5 and no changes

Update 4.9.5 fixed #43201, not this one.

#46 in reply to: ↑ description @yashparmar71
2 months ago

Replying to internetwerk:

Warning with PHP 7.2:

Warning: count(): Parameter must be an array or an object that implements Countable in /wp-includes/post-template.php on line 284

if get this error you must be try this it work very nice

while (have_posts()) { the_post();

}

Last edited 2 months ago by yashparmar71 (previous) (diff)

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


2 months ago

#48 @davisshaver
2 months ago

If get_the_content() should not be called outside the loop, could we patch by adding a conditional check to the top? The function would operate as-is but would no longer throw a PHP warning.

<?php
        if ( ! in_the_loop() ) {
                return '';
        }

This is similar to how get_post() behaves.

<?php
        $post = get_post( $post );
        if ( empty( $post ) ) {
                return '';
        }

For now, I have patched in implementation like so:

<?php
        if ( in_the_loop() && ! has_shortcode( get_the_content(), 'custom-shortcode' ) ) ) {
                echo 'do something';
        }
Last edited 2 months ago by davisshaver (previous) (diff)

#49 @f_monts
2 months ago

How to fix this? It's spamming millions of rows in our logs

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


8 weeks ago

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


7 weeks ago

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


7 weeks ago

#53 @desrosj
7 weeks ago

  • Milestone changed from 4.9.6 to 4.9.7

Punting to 4.9.7.

#54 @Abigailm
5 weeks ago

Seeing the same issue on one of my sites after upgrade from PHP 7.1 to PHP 7.2. The error is sporadic on a very busy site, generating about 40 warnings per day in error logs on a site that is getting tens of thousand of hits daily... so only triggered by something infrequent. The site does NOT run jetpack.

I have been able to replicate the error. The error corresponds to certain user search requests on the site. If I find the triggering GET request and repeat the search (entering the same terms in the "search" field from any page on the site) -- then the error recurs. But it only happens in some instances -- not all searches. So I can't simply enter random searches and create the error. The site is running the Relevansii plugin so I will report the problem in the support forum there as well. (I don't know enough about how relevanssi modifies the core wordpress search function to determine the source of the problem).

Last edited 5 weeks ago by Abigailm (previous) (diff)

#55 @ocean90
5 weeks ago

#44140 was marked as a duplicate.

#56 @desrosj
4 weeks ago

  • Milestone changed from 4.9.7 to 4.9.8

Moving all tickets in 4.9.7 to 4.9.8.

#57 @juergen74
3 weeks ago

For me this seem to be a problem of Themes or Plugins calling the Function get_the_content() outside of the Loop.

So if you call it outside the loop the global $pages = null

There are some easy fixes for this error: Don't call the function from outside of the loop! :) And if you see a theme or plugin that is doing that, ask the developers to fix it.

or we could check $pages for null and return an empty string right at the begining of the function.

function get_the_content( $more_link_text = null, $strip_teaser = false ) {
	global $page, $more, $preview, $pages, $multipage;

        if (is_null($pages)) { return ''; }    // new line

	$post = get_post();

....

#58 @Clorith
2 weeks ago

#44297 was marked as a duplicate.

Note: See TracTickets for help on using tickets.