Skip to content

Commit 9a6f484

Browse files
Fix: PHP 8.0 named parameters compatibility — Tasks 1, 2, 3, and 4
Task 1: Fix reserved keyword parameter names in Core - Rename wp_is_valid_utf8() fallback branch parameter from $string to $bytes (utf8.php:51) to match the primary branch and ensure consistency for PHP 8.0+ named argument callers. Task 2: Align child class parameter names with abstract parent signatures - Rename prepare_item_for_response() first parameter to $item in child controllers to match WP_REST_Controller::prepare_item_for_response($item): class-wp-rest-abilities-v1-categories-controller.php ($category → $item), class-wp-rest-abilities-v1-list-controller.php ($ability → $item), class-wp-rest-global-styles-controller.php ($post → $item), class-wp-rest-global-styles-revisions-controller.php ($post → $item), class-wp-rest-menus-controller.php ($term → $item). Task 3: Audit and wrap call_user_func_array() usage in Core - Introduce wp_normalize_call_user_func_args() in load.php to strip string keys from argument arrays before they reach call_user_func_array(), preventing PHP 8.0+ from misinterpreting them as named arguments. - Wrap dynamic callback calls where $args could contain non-integer keys: class-wp-hook.php, class-wp-customize-widgets.php, class-wp-image-editor.php, class-wp-rest-widgets-controller.php, functions.php, widgets.php, and wp-admin dispatch sites (ajax-actions, class-wp-screen, dashboard, media, post, widgets, widgets-form). - Add a safety comment to class-wp-block-bindings-source.php:86 documenting why its call_user_func_array() does not need wrapping. Task 4: Escalate PHPCS rule to error severity - Update phpcs.xml.dist to escalate Universal.NamingConventions.NoReservedKeywordParameterNames from warning to error, preventing future reserved keyword parameter names (string, list, array, etc.) that break PHP 8.0+ named argument syntax. See: https://core.trac.wordpress.org/ticket/59649
1 parent e12ddb3 commit 9a6f484

22 files changed

+101
-65
lines changed

phpcs.xml.dist

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,4 +367,13 @@
367367
<exclude-pattern>/tests/*</exclude-pattern>
368368
</rule>
369369

370+
<!-- Enforce PHP 8.0 named parameter compatibility.
371+
Escalated from warning to error to prevent reserved keyword parameter names
372+
(string, list, array, etc.) which break PHP 8.0+ named argument syntax.
373+
See: Trac #59649
374+
-->
375+
<rule ref="Universal.NamingConventions.NoReservedKeywordParameterNames">
376+
<type>error</type>
377+
</rule>
378+
370379
</ruleset>

src/wp-admin/includes/ajax-actions.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2432,7 +2432,7 @@ function wp_ajax_save_widget() {
24322432
}
24332433

24342434
ob_start();
2435-
call_user_func_array( $control['callback'], $control['params'] );
2435+
call_user_func_array( $control['callback'], wp_normalize_call_user_func_args( $control['params'] ) );
24362436
ob_end_clean();
24372437
break;
24382438
}
@@ -2451,7 +2451,7 @@ function wp_ajax_save_widget() {
24512451

24522452
$form = $wp_registered_widget_controls[ $widget_id ];
24532453
if ( $form ) {
2454-
call_user_func_array( $form['callback'], $form['params'] );
2454+
call_user_func_array( $form['callback'], wp_normalize_call_user_func_args( $form['params'] ) );
24552455
}
24562456

24572457
wp_die();

src/wp-admin/includes/class-wp-screen.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ public function render_screen_meta() {
913913

914914
// If it exists, fire tab callback.
915915
if ( ! empty( $tab['callback'] ) ) {
916-
call_user_func_array( $tab['callback'], array( $this, $tab ) );
916+
call_user_func_array( $tab['callback'], wp_normalize_call_user_func_args( array( $this, $tab ) ) );
917917
}
918918
?>
919919
</div>

src/wp-admin/includes/dashboard.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,7 @@ function wp_dashboard_cached_rss_widget( $widget_id, $callback, $check_urls = ar
12121212
if ( $callback && is_callable( $callback ) ) {
12131213
array_unshift( $args, $widget_id, $check_urls );
12141214
ob_start();
1215-
call_user_func_array( $callback, $args );
1215+
call_user_func_array( $callback, wp_normalize_call_user_func_args( $args ) );
12161216
// Default lifetime in cache of 12 hours (same as the feeds).
12171217
set_transient( $cache_key, ob_get_flush(), 12 * HOUR_IN_SECONDS );
12181218
}

src/wp-admin/includes/media.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -635,7 +635,7 @@ function wp_iframe( $content_func, ...$args ) {
635635
</script>
636636
<?php
637637

638-
call_user_func_array( $content_func, $args );
638+
call_user_func_array( $content_func, wp_normalize_call_user_func_args( $args ) );
639639

640640
/** This action is documented in wp-admin/admin-footer.php */
641641
do_action( 'admin_print_footer_scripts' );

src/wp-admin/includes/post.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ function edit_post( $post_data = null ) {
437437
$tax_object = get_taxonomy( $taxonomy );
438438

439439
if ( $tax_object && isset( $tax_object->meta_box_sanitize_cb ) ) {
440-
$translated['tax_input'][ $taxonomy ] = call_user_func_array( $tax_object->meta_box_sanitize_cb, array( $taxonomy, $terms ) );
440+
$translated['tax_input'][ $taxonomy ] = call_user_func_array( $tax_object->meta_box_sanitize_cb, wp_normalize_call_user_func_args( array( $taxonomy, $terms ) ) );
441441
}
442442
}
443443
}

src/wp-admin/includes/widgets.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ function wp_widget_control( $sidebar_args ) {
273273
<?php echo $before_widget_content; ?>
274274
<?php
275275
if ( isset( $control['callback'] ) ) {
276-
$has_form = call_user_func_array( $control['callback'], $control['params'] );
276+
$has_form = call_user_func_array( $control['callback'], wp_normalize_call_user_func_args( $control['params'] ) );
277277
} else {
278278
echo "\t\t<p>" . __( 'There are no options for this widget.' ) . "</p>\n";
279279
}

src/wp-admin/widgets-form.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@
177177
}
178178

179179
ob_start();
180-
call_user_func_array( $control['callback'], $control['params'] );
180+
call_user_func_array( $control['callback'], wp_normalize_call_user_func_args( $control['params'] ) );
181181
ob_end_clean();
182182

183183
break;
@@ -290,7 +290,7 @@
290290
<div class="widget-inside">
291291
<?php
292292
if ( is_callable( $control_callback ) ) {
293-
call_user_func_array( $control_callback, $control['params'] );
293+
call_user_func_array( $control_callback, wp_normalize_call_user_func_args( $control['params'] ) );
294294
} else {
295295
echo '<p>' . __( 'There are no options for this widget.' ) . "</p>\n";
296296
}

src/wp-includes/class-wp-block-bindings-source.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public function __construct( string $name, array $source_properties ) {
8383
* @return mixed The value of the source.
8484
*/
8585
public function get_value( array $source_args, $block_instance, string $attribute_name ) {
86+
// Safe: Array is built internally with numeric keys, not from untrusted input.
8687
$value = call_user_func_array( $this->get_value_callback, array( $source_args, $block_instance, $attribute_name ) );
8788
/**
8889
* Filters the output of a block bindings source.

src/wp-includes/class-wp-customize-widgets.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,7 +1631,7 @@ public function call_widget_update( $widget_id ) {
16311631
foreach ( (array) $wp_registered_widget_updates as $name => $control ) {
16321632
if ( $name === $parsed_id['id_base'] && is_callable( $control['callback'] ) ) {
16331633
ob_start();
1634-
call_user_func_array( $control['callback'], $control['params'] );
1634+
call_user_func_array( $control['callback'], wp_normalize_call_user_func_args( $control['params'] ) );
16351635
ob_end_clean();
16361636
break;
16371637
}
@@ -1677,7 +1677,7 @@ public function call_widget_update( $widget_id ) {
16771677
ob_start();
16781678
$form = $wp_registered_widget_controls[ $widget_id ];
16791679
if ( $form ) {
1680-
call_user_func_array( $form['callback'], $form['params'] );
1680+
call_user_func_array( $form['callback'], wp_normalize_call_user_func_args( $form['params'] ) );
16811681
}
16821682
$form = ob_get_clean();
16831683

0 commit comments

Comments
 (0)