Make WordPress Core

Opened 2 years ago

Closed 11 months ago

Last modified 5 weeks ago

#56127 closed defect (bug) (invalid)

WP_Widget constructor throws fatal ArgumentCountError

Reported by: firefly2000's profile firefly2000 Owned by:
Milestone: Priority: normal
Severity: normal Version: 6.0
Component: Widgets Keywords: needs-patch reporter-feedback
Focuses: coding-standards Cc:

Description (last modified by SergeyBiryukov)

In WordPress core 6.0, plugins and themes that register widgets cause a fatal error for sites running on PHP 8.0. Here is an example:

Uncaught ArgumentCountError: Too few arguments to function WP_Widget::__construct(), 0 passed

A solution that is working for me is to edit line 61 of wp-includes/class-wp-widget-factory.php so that

new $widget()

gets 2 empty strings passed to it, e.g.

new $widget('', '')

Change History (16)

#1 @TimothyBlynJacobs
2 years ago

  • Keywords reporter-feedback php8 added
  • Severity changed from blocker to normal

Hi @firefly2000,

Welcome to Trac!

Can you share the widgets you are having trouble with? Widgets are supposed to define their own constructor without any parameters, or pass an instance of their widget to register_widget instead of a class name.

https://developer.wordpress.org/themes/functionality/widgets/

So while this is now a fatal error in PHP 8, it sounds to me like the widget was already behaving incorrectly.

#2 follow-up: @trevordearham
21 months ago

I just updated to WordPress 6.0.2 successfully and then to PHP 8.0. When switching to PHP 8.0, I got the same error mentioned:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function WP_Widget::__construct(), 0 passed in /wp-includes/class-wp-widget-factory.php on line 61 and at least 2 expected in /wp-includes/class-wp-widget.php:162

The code can be seen in the release code for WordPress 6.0.2 https://github.com/WordPress/WordPress/blob/6.0.2/wp-includes/class-wp-widget-factory.php#L61.

Applying the suggested patch to that line causes the code to work, but probably not the ideal solution.

For me the call stack has the Video widget of the FullScene theme https://themeforest.net/item/fullscene-portfolio-photography-wp-theme/1617432, which is probably not compatible with WordPress 6. It appears to be passing a string instead of an instance of WP_Widget, but I assume the code path should allow this.

Stack trace:
#0 /wp-includes/class-wp-widget-factory.php(61): WP_Widget->__construct()
#1 /wp-includes/widgets.php(115): WP_Widget_Factory->register('Video_Widget') 
#2 /wp-content/themes/fullscene/functions/widget-video.php(6): register_widget('Video_Widget')
#3 /wp-includes/class-wp-hook.php(307): pt_video_widget('')
#4 /wp-includes/class-wp-hook.php(331): WP_Hook->apply_filters(NULL, Array)
#5 /wp-includes/plugin.php(476): WP_Hook->do_action(Array)
#6 /wp-includes/widgets.php(1854): do_action('widgets_init')
#7 /wp-includes/class-wp-hook.php(307): wp_widgets_init('')
#8 /wp-includes/class-wp-hook.php(331): WP_Hook->apply_filters(NULL, Array)
#9 /wp-includes/plugin.php(476): WP_Hook->do_action(Array)
#10 /wp-settings.php(598): do_action('init')
#11 /wp-config.php(90): require_once('/customers/9/c/...')
#12 /wp-load.php(50): require_once('/customers/9/c/...')
#13 /wp-admin/admin.php(34): require_once('/customers/9/c/...')
#14 /wp-admin/options-general.php(10): require_once('/customers/9/c/...')
#15 {main} thrown in /wp-includes/class-wp-widget.php on line 162
Last edited 21 months ago by SergeyBiryukov (previous) (diff)

#3 @SergeyBiryukov
15 months ago

#57739 was marked as a duplicate.

#4 @SergeyBiryukov
15 months ago

  • Description modified (diff)

#5 @SergeyBiryukov
15 months ago

#58176 was marked as a duplicate.

#6 @hellofromTonya
11 months ago

  • Keywords php8 removed
  • Summary changed from WP_Widget contructor throws fatal ArgumentCountError in WordPress 6.0 running on PHP 8 to WP_Widget constructor throws fatal ArgumentCountError

The reported issue happens is a fatal error on PHP 7.1+ and PHP8+ and a warning on PHP 5 to 7.0 (see it in action https://3v4l.org/uPrIn). Thus, I'm removing the php8 keyword as it is not specifically PHP 8.0 only.

#7 @hellofromTonya
11 months ago

As @TimothyBlynJacobs noted, widgets should extend WP_Widget and declare a constructor with no parameters that invokes the WP_Widget::__construct with the required arguments as shown in the documentation https://developer.wordpress.org/themes/functionality/widgets/. For example:

<?php
class My_Widget extends WP_Widget {
        public function __construct() {
                parent::__construct(
                        'my-text',  // Base ID
                        'My Text'   // Name
                );

The code in WP_Widget_Factory::register( $widget ) that instantiates new $widget() expects and requires no parameters being defined in the widget. This means themes and plugins are required to follow the above code.

This code has been in Core since WP 2.8.0.

  • [10782] added WP_Widget which also had a similar constructor as now.
  • [10808] introduced the WP_Widget_Factory whose register method accepted a string of the widget class name and instantiated as new $widget_class().

Notice that the code flagged in the ticket's description was introduced in WP 2.8.0. The design then and now is as @TimothyBlynJacobs noted above, i.e. widgets should extend WP_Widget with no parameters in the constructor.

I'm not sure why this issue is flagged as occurring in WP 6.0.0 release. But to double check, next I'll scanning Core's source code for all widget classes to ensure each is properly doing their constructor.

#8 @hellofromTonya
11 months ago

Audit of WordPress Core 6.0 widgets

Here are all of the widget files shipped in WP 6.0:

(Note: ✅ means its constructor is correct)

All of Core's widgets are correctly declaring their constructors.

#9 in reply to: ↑ 2 @hellofromTonya
11 months ago

Replying to trevordearham:

I just updated to WordPress 6.0.2 successfully and then to PHP 8.0. When switching to PHP 8.0, I got the same error mentioned:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function WP_Widget::__construct(), 0 passed in /wp-includes/class-wp-widget-factory.php on line 61 and at least 2 expected in /wp-includes/class-wp-widget.php:162

The code can be seen in the release code for WordPress 6.0.2 https://github.com/WordPress/WordPress/blob/6.0.2/wp-includes/class-wp-widget-factory.php#L61.

Applying the suggested patch to that line causes the code to work, but probably not the ideal solution.

For me the call stack has the Video widget of the FullScene theme https://themeforest.net/item/fullscene-portfolio-photography-wp-theme/1617432, which is probably not compatible with WordPress 6.

Hello @trevordearham, I suspect the Video widget in that theme is incorrectly doing its constructor. It should have a __construct() with no parameters defined and then pass the correct information to the base WP_Widget constructor, per the the documentation. I suggest reaching out to the theme's author to report the issue.

It appears to be passing a string instead of an instance of WP_Widget, but I assume the code path should allow this.

Passing its widget classname as a string is correct and the way WordPress Core does it too.

#10 @hellofromTonya
11 months ago

Test Report

Env:

  • WP: 6.0
  • PHP: 8.0.22
  • Theme: Twenty Twenty
  • Plugins: none

Test Steps

  1. Go to the Appearance > Widgets page.
  2. Add multiple types of widgets to each Footer section.
  3. Save.
  4. Did an error happen? Check the error logs.

Test Results

No errors occurred when adding the following widgets:

  • Footer 1: heading, quote, image, paragraph
  • Footer 2: comments, tag cloud, login/logout

Widgets worked as expected ✅

Summary

I could not reproduce the reported error. Widgets worked as expected without errors.

#11 @hellofromTonya
11 months ago

#58176 noted the error occurred with the MiniMeta Widget plugin. Looking at its widget code, the code has not been updated and appears to use PHP 4 code. It will fatal error because it is using the WP_Widget constructor rather than its own, per the documentation.

I share this plugin as an example for anyone experiencing this problem.

#12 follow-up: @hellofromTonya
11 months ago

  • Milestone Awaiting Review deleted
  • Resolution set to invalid
  • Status changed from new to closed

I'm closing this ticket. Why?

  • I suspect the root cause is in a plugin, theme, or must-use script.
  • I can't reproduce the reported issue.
  • The audit of Core's widgets shows they are correct and not contributing to the reported issue.
  • Core's WP_Widget and WP_Widget_Factory::register( $widget ) code is from WP 2.8.0.
  • Widgets are required to have a constructor without parameters and call the parent (WP_Widget) constructor passing the correct args to its parameters (see the docs).

Why is this happening with WP 6.0 and beyond?
Hmm I'm not sure. There was only 1 Trac ticket in 6.0: #54561 / [53158]. But the call to parent's constructor is correct.

If however the problem does appear to be a Core issue, please reopen and share your findings (after the following the steps below) and additional information (see Step 5 below).

To discover where the root cause, please follow these steps in order:

Step 1: Clear all site and hosting caches.
Is the problem gone?

  • If yes, woohoo!
  • If no, go to the next step.

Step 2: Please deactivate all plugins.
Is the problem gone?

  • If yes, then the issue is in one or more of the plugins. How to find which ones? Reactivate each plugin one-by-one, refreshing and rechecking. When the problem reoccurs, the last plugin activated is causing the issue. Reach out to its author to report the issue.
  • If no, go to the next step.

Step 3: Switch to a default theme such as Twenty Twenty-Two (TT2).
Is the problem gone?

  • If yes, then the theme (before the Twenty Twenty-Two theme) is causing the issue. Reach out to its author to report the issue.
  • If no, go to the next step.

Step 4: Check the must-use scripts for any widgets.
Note: This step may require reaching out to the web host. Some hosts add must-use scripts for things like migration, debug, and admin tasks. One or more of these scripts may be adding a widget.

Is the problem gone?

  • If yes, then please reach out to the must-use script's author to report the issue.
  • If no, go to the next step.

Step 5: Share findings and how to reproduce here.
If the problem persists after following all the above steps, then please reopen this ticket and share your findings and how to reproduce, such as what widgets, WordPress version, theme, and plugins the site is using. A backtrace of the error is helpful too.

#13 in reply to: ↑ 12 @SergeyBiryukov
11 months ago

Replying to hellofromTonya:

Why is this happening with WP 6.0 and beyond?
Hmm I'm not sure. There was only 1 Trac ticket in 6.0: #54561 / [53158]. But the call to parent's constructor is correct.

Thanks for the investigation! Looks like it was most likely a consequence of switching to a recent PHP version and updating WordPress at the same time. The fatal error on PHP 7.1+ made the issue in the affected plugins or themes more visible, but it does not appear to be specific to WP 6.0.

#14 @SergeyBiryukov
7 months ago

#60039 was marked as a duplicate.

#15 @sabernhardt
4 months ago

#60725 was marked as a duplicate.

#16 @sabernhardt
5 weeks ago

#61415 was marked as a duplicate.

Note: See TracTickets for help on using tickets.