From d875967a9393bf687424cc80fdffacae7246eecb Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 13 Aug 2026 22:42:36 -0700 Subject: [PATCH 01/11] Restore string|void on WP_Widget::form() r62178 replaced `@return string|void` with `@return string|null` on WP_Widget::form(), on the premise that void cannot be part of a union type. That holds for PHP's native return types, but not for PHPDoc, where `string|void` is the documented way to say a method may return a string or may return nothing at all. PHPStan reads it exactly that way, and treats `string|null` instead as an obligation to return. The base implementation echoes a notice and returns 'noform', while every subclass echoes its own markup and falls off the end. Tightening the declared type therefore put all 18 subclass form() overrides in breach of it, for 20 reported errors. Four of those overrides live in bundled themes, which r62178 did not touch and so could not have updated alongside the parent. form_callback() is unaffected: it initialises $return to null and always returns it, so its own string|null annotation stays accurate, as does the null|string documented for $return on the in_widget_form action. Only the method that may legitimately not return at all needed void back. Regenerating the baselines drops 18 entries covering 20 errors from tests/phpstan/baselines/return.missing.neon. Co-Authored-By: Claude Opus 5 --- src/wp-includes/class-wp-widget.php | 3 +- tests/phpstan/baselines/return.missing.neon | 90 --------------------- 2 files changed, 2 insertions(+), 91 deletions(-) diff --git a/src/wp-includes/class-wp-widget.php b/src/wp-includes/class-wp-widget.php index dc84f54774162..b131c50db3226 100644 --- a/src/wp-includes/class-wp-widget.php +++ b/src/wp-includes/class-wp-widget.php @@ -138,7 +138,8 @@ public function update( $new_instance, $old_instance ) { * @since 2.8.0 * * @param array $instance The settings for the particular instance of the widget. - * @return string|null Default return is 'noform'. A subclass may opt to return null. + * @return string|void Default return is 'noform'. A subclass which echoes its own + * form returns nothing. */ public function form( $instance ) { echo '

' . __( 'There are no options for this widget.' ) . '

'; diff --git a/tests/phpstan/baselines/return.missing.neon b/tests/phpstan/baselines/return.missing.neon index 11bb654bafb2c..4a09ba261519d 100644 --- a/tests/phpstan/baselines/return.missing.neon +++ b/tests/phpstan/baselines/return.missing.neon @@ -18,16 +18,6 @@ parameters: ignoreErrors: - - - message: '#^Method Twenty_Eleven_Ephemera_Widget\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/inc/widgets.php - - - message: '#^Method Twenty_Fourteen_Ephemera_Widget\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-content/themes/twentyfourteen/inc/widgets.php - message: '#^Function get_category_by_path\(\) should return array\|WP_Error\|WP_Term\|null but return statement is missing\.$#' identifier: return.missing @@ -143,83 +133,3 @@ parameters: identifier: return.missing count: 1 path: ../../../src/wp-includes/user.php - - - message: '#^Method WP_Nav_Menu_Widget\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-nav-menu-widget.php - - - message: '#^Method WP_Widget_Archives\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-archives.php - - - message: '#^Method WP_Widget_Block\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-block.php - - - message: '#^Method WP_Widget_Calendar\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-calendar.php - - - message: '#^Method WP_Widget_Categories\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-categories.php - - - message: '#^Method WP_Widget_Custom_HTML\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-custom-html.php - - - message: '#^Method WP_Widget_Links\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-links.php - - - message: '#^Method WP_Widget_Media\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-media.php - - - message: '#^Method WP_Widget_Meta\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-meta.php - - - message: '#^Method WP_Widget_Pages\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-pages.php - - - message: '#^Method WP_Widget_Recent_Comments\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-recent-comments.php - - - message: '#^Method WP_Widget_Recent_Posts\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-recent-posts.php - - - message: '#^Method WP_Widget_RSS\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-rss.php - - - message: '#^Method WP_Widget_Search\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-search.php - - - message: '#^Method WP_Widget_Tag_Cloud\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 2 - path: ../../../src/wp-includes/widgets/class-wp-widget-tag-cloud.php - - - message: '#^Method WP_Widget_Text\:\:form\(\) should return string\|null but return statement is missing\.$#' - identifier: return.missing - count: 2 - path: ../../../src/wp-includes/widgets/class-wp-widget-text.php From 97f15444cf9d9ce15e215b55bebf142dbfdbae06 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 13 Aug 2026 22:54:30 -0700 Subject: [PATCH 02/11] Call WP_Theme_JSON's private static methods through self Sixteen call sites reached seven private static methods through `static::` rather than `self::`. Late static binding resolves to the runtime class, but a private method is not inherited, so the two are only equivalent for as long as nothing subclasses WP_Theme_JSON. The moment something does, `static::` resolves against a class where the method is not visible. Nothing in core extends WP_Theme_JSON today, so this is latent rather than an active defect. It is worth correcting regardless: `self::` is what a private method actually means, and the class is a plausible extension point, being the one Gutenberg mirrors. The methods involved are sanitize_viewport_settings(), is_valid_viewport_breakpoint_size(), get_viewport_breakpoint_value_in_pixels(), update_paragraph_text_indent_selector(), update_button_width_declarations(), get_block_name_from_metadata_path(), and get_feature_selector(). All were introduced after 7.0. Regenerating the baselines drops 7 entries covering 14 errors from tests/phpstan/baselines/staticClassAccess.privateMethod.neon. The remaining entries in that file are unrelated to this class. Co-Authored-By: Claude Opus 5 --- src/wp-includes/class-wp-theme-json.php | 32 ++++++++--------- .../staticClassAccess.privateMethod.neon | 35 ------------------- 2 files changed, 16 insertions(+), 51 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 7175d7a88747d..c631bca1be971 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -718,7 +718,7 @@ class WP_Theme_JSON { * @return array Responsive media queries. */ public static function get_viewport_media_queries( $viewport_settings = null, $options = array() ) { - $breakpoints = static::sanitize_viewport_settings( $viewport_settings ); + $breakpoints = self::sanitize_viewport_settings( $viewport_settings ); $responsive_media_queries = array(); @@ -788,7 +788,7 @@ private static function is_valid_viewport_breakpoint_size( $value ) { * @return float|null Viewport breakpoint size in pixels, or null when invalid. */ private static function get_viewport_breakpoint_value_in_pixels( $value ) { - if ( ! static::is_valid_viewport_breakpoint_size( $value ) ) { + if ( ! self::is_valid_viewport_breakpoint_size( $value ) ) { return null; } @@ -831,7 +831,7 @@ private static function sanitize_viewport_settings( $viewport_settings ) { $breakpoints = array(); foreach ( array_keys( static::DEFAULT_VIEWPORT_BREAKPOINTS ) as $breakpoint ) { $value = $viewport_settings[ $breakpoint ] ?? null; - $px = static::get_viewport_breakpoint_value_in_pixels( $value ); + $px = self::get_viewport_breakpoint_value_in_pixels( $value ); if ( null !== $px ) { $breakpoints[ $breakpoint ] = array( 'value' => trim( $value ), @@ -989,8 +989,8 @@ private function process_pseudo_selectors( $node, $base_selector, $settings, $bl if ( is_array( $block_metadata ) ) { $feature_declarations = $this->get_feature_declarations_for_node( $block_metadata, $pseudo_node ); - $feature_declarations = static::update_paragraph_text_indent_selector( $feature_declarations, $settings, $block_name ); - $feature_declarations = static::update_button_width_declarations( $feature_declarations, $settings ); + $feature_declarations = self::update_paragraph_text_indent_selector( $feature_declarations, $settings, $block_name ); + $feature_declarations = self::update_button_width_declarations( $feature_declarations, $settings ); foreach ( $feature_declarations as $feature_selector => $declarations ) { $target_selector = is_array( $style_variation ) @@ -1457,7 +1457,7 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n $result = static::remove_keys_not_in_schema( $input[ $subtree ], $schema[ $subtree ] ); if ( 'settings' === $subtree && array_key_exists( 'viewport', $input[ $subtree ] ) ) { - $result['viewport'] = static::sanitize_viewport_settings( $input[ $subtree ]['viewport'] ); + $result['viewport'] = self::sanitize_viewport_settings( $input[ $subtree ]['viewport'] ); } if ( empty( $result ) ) { @@ -2509,7 +2509,7 @@ protected function get_css_variables( $nodes, $origins ) { continue; } - $target = static::get_feature_selector( $feature_selectors, $preset_metadata['path'][0], $selector ); + $target = self::get_feature_selector( $feature_selectors, $preset_metadata['path'][0], $selector ); if ( ! isset( $vars_by_selector[ $target ] ) ) { $vars_by_selector[ $target ] = array(); @@ -3824,11 +3824,11 @@ public function get_styles_for_block( $block_metadata ) { // Update text indent selector for paragraph blocks based on the textIndent setting. $block_name = $block_metadata['name'] ?? null; - $feature_declarations = static::update_paragraph_text_indent_selector( $feature_declarations, $settings, $block_name ); + $feature_declarations = self::update_paragraph_text_indent_selector( $feature_declarations, $settings, $block_name ); $block_elements = $block_metadata['elements'] ?? array(); // Update button width declarations for percentage values to use calc() with block gap. - $feature_declarations = static::update_button_width_declarations( $feature_declarations, $settings ); + $feature_declarations = self::update_button_width_declarations( $feature_declarations, $settings ); // If there are style variations, generate the declarations for them, including any feature selectors the block may have. $style_variation_declarations = array(); @@ -3844,10 +3844,10 @@ public function get_styles_for_block( $block_metadata ) { $variation_declarations = static::get_feature_declarations_for_node( $block_metadata, $style_variation_node ); // Update text indent selector for paragraph blocks based on the textIndent setting. - $variation_declarations = static::update_paragraph_text_indent_selector( $variation_declarations, $settings, $block_name ); + $variation_declarations = self::update_paragraph_text_indent_selector( $variation_declarations, $settings, $block_name ); // Update button width declarations for percentage values to use calc() with block gap. - $variation_declarations = static::update_button_width_declarations( $variation_declarations, $settings ); + $variation_declarations = self::update_button_width_declarations( $variation_declarations, $settings ); // Combine selectors with style variation's selector and add to overall style variation declarations. foreach ( $variation_declarations as $current_selector => $new_declarations ) { @@ -3864,7 +3864,7 @@ public function get_styles_for_block( $block_metadata ) { if ( isset( $block_metadata['name'] ) ) { $block_name = $block_metadata['name']; } elseif ( in_array( 'blocks', $block_metadata['path'], true ) && count( $block_metadata['path'] ) >= 3 ) { - $block_name = static::get_block_name_from_metadata_path( $block_metadata ); + $block_name = self::get_block_name_from_metadata_path( $block_metadata ); } else { $block_name = null; } @@ -3902,8 +3902,8 @@ public function get_styles_for_block( $block_metadata ) { $breakpoint_media = $responsive_media_queries[ $breakpoint ]; // Process feature-level declarations for this breakpoint. $breakpoint_feature_declarations = static::get_feature_declarations_for_node( $block_metadata, $breakpoint_node ); - $breakpoint_feature_declarations = static::update_paragraph_text_indent_selector( $breakpoint_feature_declarations, $settings, $block_name ); - $breakpoint_feature_declarations = static::update_button_width_declarations( $breakpoint_feature_declarations, $settings ); + $breakpoint_feature_declarations = self::update_paragraph_text_indent_selector( $breakpoint_feature_declarations, $settings, $block_name ); + $breakpoint_feature_declarations = self::update_button_width_declarations( $breakpoint_feature_declarations, $settings ); foreach ( $breakpoint_feature_declarations as $feature_selector => $feature_decl ) { $combined_selectors = static::get_block_style_variation_feature_selector( $style_variation, $feature_selector ); @@ -4681,7 +4681,7 @@ public static function remove_insecure_properties( $theme_json, $origin = 'theme } $block_name = in_array( 'blocks', $metadata['path'], true ) - ? static::get_block_name_from_metadata_path( $metadata ) + ? self::get_block_name_from_metadata_path( $metadata ) : null; // The global styles custom CSS is not sanitized, but can only be edited by users with 'edit_css' capability. @@ -5014,7 +5014,7 @@ protected static function remove_insecure_settings( $input, $is_root = false ) { self::preserve_valid_typed_settings( $input, $output, static::VALID_SETTINGS ); if ( $is_root && array_key_exists( 'viewport', $input ) ) { - $output['viewport'] = static::sanitize_viewport_settings( $input['viewport'] ); + $output['viewport'] = self::sanitize_viewport_settings( $input['viewport'] ); } return $output; diff --git a/tests/phpstan/baselines/staticClassAccess.privateMethod.neon b/tests/phpstan/baselines/staticClassAccess.privateMethod.neon index c3a8969643a94..30fd53d2540c1 100644 --- a/tests/phpstan/baselines/staticClassAccess.privateMethod.neon +++ b/tests/phpstan/baselines/staticClassAccess.privateMethod.neon @@ -98,31 +98,11 @@ parameters: identifier: staticClassAccess.privateMethod count: 3 path: ../../../src/wp-includes/class-wp-theme-json.php - - - message: '#^Unsafe call to private method WP_Theme_JSON\:\:get_block_name_from_metadata_path\(\) through static\:\:\.$#' - identifier: staticClassAccess.privateMethod - count: 2 - path: ../../../src/wp-includes/class-wp-theme-json.php - message: '#^Unsafe call to private method WP_Theme_JSON\:\:get_block_nodes\(\) through static\:\:\.$#' identifier: staticClassAccess.privateMethod count: 3 path: ../../../src/wp-includes/class-wp-theme-json.php - - - message: '#^Unsafe call to private method WP_Theme_JSON\:\:get_feature_selector\(\) through static\:\:\.$#' - identifier: staticClassAccess.privateMethod - count: 1 - path: ../../../src/wp-includes/class-wp-theme-json.php - - - message: '#^Unsafe call to private method WP_Theme_JSON\:\:get_viewport_breakpoint_value_in_pixels\(\) through static\:\:\.$#' - identifier: staticClassAccess.privateMethod - count: 1 - path: ../../../src/wp-includes/class-wp-theme-json.php - - - message: '#^Unsafe call to private method WP_Theme_JSON\:\:is_valid_viewport_breakpoint_size\(\) through static\:\:\.$#' - identifier: staticClassAccess.privateMethod - count: 1 - path: ../../../src/wp-includes/class-wp-theme-json.php - message: '#^Unsafe call to private method WP_Theme_JSON\:\:merge_spacing_sizes\(\) through static\:\:\.$#' identifier: staticClassAccess.privateMethod @@ -138,26 +118,11 @@ parameters: identifier: staticClassAccess.privateMethod count: 1 path: ../../../src/wp-includes/class-wp-theme-json.php - - - message: '#^Unsafe call to private method WP_Theme_JSON\:\:sanitize_viewport_settings\(\) through static\:\:\.$#' - identifier: staticClassAccess.privateMethod - count: 3 - path: ../../../src/wp-includes/class-wp-theme-json.php - message: '#^Unsafe call to private method WP_Theme_JSON\:\:unwrap_shared_block_style_variations\(\) through static\:\:\.$#' identifier: staticClassAccess.privateMethod count: 1 path: ../../../src/wp-includes/class-wp-theme-json.php - - - message: '#^Unsafe call to private method WP_Theme_JSON\:\:update_button_width_declarations\(\) through static\:\:\.$#' - identifier: staticClassAccess.privateMethod - count: 4 - path: ../../../src/wp-includes/class-wp-theme-json.php - - - message: '#^Unsafe call to private method WP_Theme_JSON\:\:update_paragraph_text_indent_selector\(\) through static\:\:\.$#' - identifier: staticClassAccess.privateMethod - count: 4 - path: ../../../src/wp-includes/class-wp-theme-json.php - message: '#^Unsafe call to private method WP_Theme_JSON\:\:update_separator_declarations\(\) through static\:\:\.$#' identifier: staticClassAccess.privateMethod From 5c6a81b0b9f0377e99ee9f40b2ba476ab7511917 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 14 Aug 2026 00:04:16 -0700 Subject: [PATCH 03/11] Document get_feature_declarations_for_node()'s params as arrays The method has been annotated `@param object` for both `$metadata` and `$node` since 6.3.0, but it has only ever been passed arrays, and only ever treats them as arrays: it reads `$metadata['selectors']` and `$node[ $feature ]`, builds `$node[ $feature ][ $subfeature ]`, and unsets through the reference. Given a real object, the first subscript would be fatal. The wrong type propagated. Because `$node` is taken by reference, callers had their own variable narrowed to object after the call, so the same node then reported the mirror-image error when handed to process_pseudo_selectors(), which correctly documents `array`. Code added since 7.0 in get_styles_for_block() made that visible in three places. Correcting the two annotations resolves all five errors the file reported, without touching a line of executable code, and documents that features promoted to their own selector are removed from `$node`. Regenerating the baselines drops 3 entries covering 5 errors from tests/phpstan/baselines/argument.type.neon. Co-Authored-By: Claude Opus 5 --- src/wp-includes/class-wp-theme-json.php | 5 +++-- tests/phpstan/baselines/argument.type.neon | 15 --------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index c631bca1be971..170930471f347 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -5672,8 +5672,9 @@ protected static function get_block_element_selectors( $root_selector ) { * * @since 6.3.0 * - * @param object $metadata The related block metadata containing selectors. - * @param object $node A merged theme.json node for block or variation. + * @param array $metadata The related block metadata containing selectors. + * @param array $node A merged theme.json node for block or variation. Features + * promoted to their own selector are removed from it. * @return array The style declarations for the node's features with custom * selectors. */ diff --git a/tests/phpstan/baselines/argument.type.neon b/tests/phpstan/baselines/argument.type.neon index da71134bcaf34..f2f45a7b3d3c1 100644 --- a/tests/phpstan/baselines/argument.type.neon +++ b/tests/phpstan/baselines/argument.type.neon @@ -908,21 +908,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-includes/class-wp-site.php - - - message: '#^Parameter \#1 \$metadata of method WP_Theme_JSON\:\:get_feature_declarations_for_node\(\) expects object, array given\.$#' - identifier: argument.type - count: 4 - path: ../../../src/wp-includes/class-wp-theme-json.php - - - message: '#^Parameter \#1 \$node of method WP_Theme_JSON\:\:process_pseudo_selectors\(\) expects array, object given\.$#' - identifier: argument.type - count: 2 - path: ../../../src/wp-includes/class-wp-theme-json.php - - - message: '#^Parameter \#1 \$styles of static method WP_Theme_JSON\:\:compute_style_properties\(\) expects array, object given\.$#' - identifier: argument.type - count: 3 - path: ../../../src/wp-includes/class-wp-theme-json.php - message: '#^Parameter \#2 \$data of method WP_Theme\:\:cache_add\(\) expects array\|string, int given\.$#' identifier: argument.type From b7a00c1796443b97adf30ad393340a5e9b1f697a Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 14 Aug 2026 00:11:25 -0700 Subject: [PATCH 04/11] Drop a redundant empty check in merge_properties() The shape-mismatch guard tested `array() !== $current` after already requiring `! array_is_list( $current )`. Since array_is_list() returns true for an empty array, the negation cannot hold unless $current is non-empty, so the trailing comparison was always true and never decided anything. Only that clause is removed. The matching test on $incoming stays, because it is live: $incoming is a list at that point and may legitimately be empty, which is the documented exemption letting replace() clear a list. So does the similar check further down, where array_is_list( $current ) is asserted rather than negated and an empty array therefore still reaches it. Behaviour is unchanged. The 78 view config tests pass. Regenerating the baselines drops 1 entry from tests/phpstan/baselines/notIdentical.alwaysTrue.neon. Co-Authored-By: Claude Opus 5 --- src/wp-includes/class-wp-view-config-data.php | 2 +- tests/phpstan/baselines/notIdentical.alwaysTrue.neon | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-view-config-data.php b/src/wp-includes/class-wp-view-config-data.php index be85e9dc10d60..a1f6fd37f99b1 100644 --- a/src/wp-includes/class-wp-view-config-data.php +++ b/src/wp-includes/class-wp-view-config-data.php @@ -523,7 +523,7 @@ private function merge_properties( $current, $incoming, $replace_lists ) { // A non-empty list only lands where a list (or nothing) lives, under // merge() and replace() alike. An empty array is shape-ambiguous and // exempt, so replace() with an empty list can still clear a list. - if ( array() !== $incoming && is_array( $current ) && ! array_is_list( $current ) && array() !== $current ) { + if ( array() !== $incoming && is_array( $current ) && ! array_is_list( $current ) ) { _doing_it_wrong( __METHOD__, esc_html__( 'A view configuration patch value must match the shape of the value it patches: a list merges into a list, and an associative array into an associative array.' ), diff --git a/tests/phpstan/baselines/notIdentical.alwaysTrue.neon b/tests/phpstan/baselines/notIdentical.alwaysTrue.neon index 99fe5295c9d55..ee19bcbbd98b4 100644 --- a/tests/phpstan/baselines/notIdentical.alwaysTrue.neon +++ b/tests/phpstan/baselines/notIdentical.alwaysTrue.neon @@ -28,11 +28,6 @@ parameters: identifier: notIdentical.alwaysTrue count: 2 path: ../../../src/wp-includes/class-wp-rewrite.php - - - message: '#^Strict comparison using \!\=\= between array\{\} and non\-empty\-array\ will always evaluate to true\.$#' - identifier: notIdentical.alwaysTrue - count: 1 - path: ../../../src/wp-includes/class-wp-view-config-data.php - message: '#^Strict comparison using \!\=\= between ''Etc'' and ''Africa''\|''America''\|''Antarctica''\|''Arctic''\|''Asia''\|''Atlantic''\|''Australia''\|''Europe''\|''Indian''\|''Pacific'' will always evaluate to true\.$#' identifier: notIdentical.alwaysTrue From 60664f9e2461c42e59d04f4d5ee47bb7eb6b868a Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 14 Aug 2026 00:19:37 -0700 Subject: [PATCH 05/11] Drop isset() checks on properties that are always set Two guards added since 7.0 tested isset() on a declared property that has a non-null default and is therefore never unset: * WP_Posts_List_Table::get_primary_column_aria_label() paired isset( $item->post_title ) with ! empty( $item->post_title ). WP_Post declares $post_title as a string, and empty() already covers unset, null and '', so the isset() decided nothing. * wp_get_block_state_style_rules() paired isset( $block_type->selectors ) with is_array( $block_type->selectors ). WP_Block_Type declares `public $selectors = array()`. Only the isset() is removed in each case. The is_array() test on $selectors stays: the property carries no native type, so a plugin can assign a non-array to it, and that check is doing real work. Behavior is unchanged. The 46 block supports states tests pass. Regenerating the baselines drops 2 entries from tests/phpstan/baselines/isset.property.neon. Co-Authored-By: Claude Opus 5 --- src/wp-admin/includes/class-wp-posts-list-table.php | 2 +- src/wp-includes/block-supports/states.php | 2 +- tests/phpstan/baselines/isset.property.neon | 10 ---------- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/wp-admin/includes/class-wp-posts-list-table.php b/src/wp-admin/includes/class-wp-posts-list-table.php index 8a319986766b8..bb8382569dbaa 100644 --- a/src/wp-admin/includes/class-wp-posts-list-table.php +++ b/src/wp-admin/includes/class-wp-posts-list-table.php @@ -1135,7 +1135,7 @@ protected function _column_title( $post, $classes, $data, $primary ) { * @return string The post title, or 'no title' if no title. */ protected function get_primary_column_aria_label( $item ) { - return isset( $item->post_title ) && ! empty( $item->post_title ) ? $item->post_title : __( 'no title' ); + return ! empty( $item->post_title ) ? $item->post_title : __( 'no title' ); } /** diff --git a/src/wp-includes/block-supports/states.php b/src/wp-includes/block-supports/states.php index 7b5f0af18e800..bedfc5b9a1d98 100644 --- a/src/wp-includes/block-supports/states.php +++ b/src/wp-includes/block-supports/states.php @@ -399,7 +399,7 @@ function wp_add_block_state_style_rule( &$css_rules, $state, $selector, $style, */ function wp_get_block_state_style_rules( $state_styles, $block_type, $rules_group = null ) { $css_rules = array(); - $block_selectors = isset( $block_type->selectors ) && is_array( $block_type->selectors ) + $block_selectors = is_array( $block_type->selectors ) ? $block_type->selectors : array(); diff --git a/tests/phpstan/baselines/isset.property.neon b/tests/phpstan/baselines/isset.property.neon index 2a0c8971ceb55..ab7d839e22002 100644 --- a/tests/phpstan/baselines/isset.property.neon +++ b/tests/phpstan/baselines/isset.property.neon @@ -28,11 +28,6 @@ parameters: identifier: isset.property count: 1 path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php - - - message: '#^Property WP_Post\:\:\$post_title \(string\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../src/wp-admin/includes/class-wp-posts-list-table.php - message: '#^Property WP_Screen\:\:\$post_type \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property @@ -88,11 +83,6 @@ parameters: identifier: isset.property count: 1 path: ../../../src/wp-includes/block-editor.php - - - message: '#^Property WP_Block_Type\:\:\$selectors \(array\) in isset\(\) is not nullable\.$#' - identifier: isset.property - count: 1 - path: ../../../src/wp-includes/block-supports/states.php - message: '#^Property WP_Customize_Control\:\:\$settings \(array\) in isset\(\) is not nullable\.$#' identifier: isset.property From cf9a4af44138c5944783206067f397473971bc51 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 14 Aug 2026 00:31:14 -0700 Subject: [PATCH 06/11] Declare the $wpdb global on the Users screen The delete-users confirmation block queries $wpdb for a user's posts and links without the file ever importing the global. It works, since a top-level admin page runs at global scope, but nothing said so, and static analysis reported the variable as possibly undefined. Import it with the `@global` docblock core uses elsewhere for the same purpose, matching edit.php and edit-comments.php. The tag alone is not enough: the PHPStan visitor bridging core's `@global` tags acts on `global` statements, so the statement carries the type and the tag documents it. Two of the three reports on the file are on lines added since 7.0; the third predates it and is fixed by the same declaration. Regenerating the baselines drops the users.php entry from tests/phpstan/baselines/variable.undefined.neon. Co-Authored-By: Claude Opus 5 --- src/wp-admin/users.php | 5 +++++ tests/phpstan/baselines/variable.undefined.neon | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/wp-admin/users.php b/src/wp-admin/users.php index a94a9eff4a9cf..1a2177a21dbf7 100644 --- a/src/wp-admin/users.php +++ b/src/wp-admin/users.php @@ -339,6 +339,11 @@
    Date: Fri, 14 Aug 2026 11:04:36 -0700 Subject: [PATCH 07/11] Stop baselining a substr_compare() report PHPStan gets wrong The HTML API passes null for substr_compare()'s $length, which has always meant "compare the full length". PHP 7.4 spelled the parameter `int $length = null`, where the null default makes it implicitly nullable, and PHP 8.0 only made that explicit as `?int $length = null`. The behavior never differed; running the call on PHP 7.4 confirms null compares the whole string rather than coercing to a length of 0, which is the failure that would matter here. PHPStan reads the two spellings from two sources and only one is right. Its PHP 8 stub carries `?int`, but the pre-8.0 resources/functionMap.php records plain `int`, having dropped the implicit nullability when it was transcribed from the old manual. Since phpVersion.min is 70400, the legacy map wins and null is reported as invalid. Move the entry out of the baseline and into ignoreErrors, where the surrounding comment records all of the above. A baseline entry is a promise to fix something, and there is nothing here to fix: the call is correct on every version WordPress supports, and passing an explicit length purely to satisfy the analyzer would change working code to suit a tooling bug. reportUnmatched is false so the entry lapses quietly once PHPStan corrects its map. Co-Authored-By: Claude Opus 5 --- phpstan.neon.dist | 20 ++++++++++++++++++++ tests/phpstan/baselines/argument.type.neon | 5 ----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index e2e72fb367482..27c00a45cfa6e 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -133,3 +133,23 @@ parameters: message: '#^PHPDoc tag @throws with type InvalidArgumentException\|ValueError is not subtype of Throwable$#' path: src/wp-includes/compat.php reportUnmatched: false + + # Level 5: + # substr_compare()'s $length has always accepted null, meaning "compare the full length". PHP 7.4 spelled + # that `int $length = null`, where the null default makes the parameter implicitly nullable, and PHP 8.0 + # only made it explicit as `?int $length = null`. The behavior never differed: verified on PHP 7.4 that + # passing null compares the whole string rather than coercing to a length of 0. + # + # PHPStan reads the two spellings from two sources and only one is right. Its PHP 8 stub carries `?int`, + # but the pre-8.0 `resources/functionMap.php` records the type as plain `int`, having dropped the implicit + # nullability when it was transcribed from the old manual. Because `phpVersion.min` is 70400, the legacy + # map wins and null is reported as invalid. + # + # This lives here rather than in a baseline because a baseline entry records work still to be done, and + # there is none: the call is correct on every version WordPress supports, and the fault is in PHPStan's + # data. Passing an explicit length purely to satisfy it would change working code to suit a tooling bug. + # `reportUnmatched: false` so this entry lapses quietly if PHPStan corrects the map. + - + message: '#^Parameter \#4 \$length of function substr_compare expects int, null given\.$#' + path: src/wp-includes/html-api/class-wp-html-tag-processor.php + reportUnmatched: false diff --git a/tests/phpstan/baselines/argument.type.neon b/tests/phpstan/baselines/argument.type.neon index f2f45a7b3d3c1..f1c4da546ffc5 100644 --- a/tests/phpstan/baselines/argument.type.neon +++ b/tests/phpstan/baselines/argument.type.neon @@ -1143,11 +1143,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-includes/html-api/class-wp-html-processor.php - - - message: '#^Parameter \#4 \$length of function substr_compare expects int, null given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php - message: '#^Parameter \#1 \$user_id of function get_userdata expects int, string given\.$#' identifier: argument.type From cbcdd48b1fb67de95019374967fb84c362020cbb Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 14 Aug 2026 11:36:22 -0700 Subject: [PATCH 08/11] Document comment_shortcuts and infinite_scrolling on WP_User Both are user preferences read straight off a WP_User through the magic __get(), exactly like rich_editing and syntax_highlighting beside them, but neither was listed among the class's @property tags. Nothing could resolve them, so every read was unverifiable. That produced a misleading report on the profile screen. user-edit.php reads 43 properties off $profile_user, which is WP_User|false because get_user_to_edit() returns get_userdata() unchanged. Access on a union is only reported from level 7, so at level 5 the other 41 reads passed on the strength of their @property tags, and only these two, which resolved to nothing, fell through to a complaint about the union. The message named the union, but the union was not the cause: adding a guard for the false case merely turned each into "access to an undefined property" on the same line. Documenting the two properties resolves them with no guard at all. The false case is unreachable in any event. The screen already dies with "Invalid user ID." when get_userdata() rejects $user_id, and $user_id is not reassigned between that check and the call, so the user provably exists. PHPStan cannot connect a guard phrased in terms of get_userdata() to a later call to get_user_to_edit(). infinite_scrolling arrived after 7.0 with the Media Library option; comment_shortcuts long predates it and was missing for the same reason. Regenerating the baselines drops 2 entries from tests/phpstan/baselines/property.nonObject.neon. Co-Authored-By: Claude Opus 5 --- src/wp-includes/class-wp-user.php | 2 ++ tests/phpstan/baselines/property.nonObject.neon | 10 ---------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/wp-includes/class-wp-user.php b/src/wp-includes/class-wp-user.php index d921a83de7f1f..d11d3b67af534 100644 --- a/src/wp-includes/class-wp-user.php +++ b/src/wp-includes/class-wp-user.php @@ -33,6 +33,8 @@ * @property string $display_name * @property string $spam * @property string $deleted + * @property string $comment_shortcuts + * @property string $infinite_scrolling * @property string $locale * @property string $rich_editing * @property string $syntax_highlighting diff --git a/tests/phpstan/baselines/property.nonObject.neon b/tests/phpstan/baselines/property.nonObject.neon index 81a4af3e09511..13fd1ccf89fc9 100644 --- a/tests/phpstan/baselines/property.nonObject.neon +++ b/tests/phpstan/baselines/property.nonObject.neon @@ -178,16 +178,6 @@ parameters: identifier: property.nonObject count: 2 path: ../../../src/wp-admin/update.php - - - message: '#^Cannot access property \$comment_shortcuts on WP_User\|false\.$#' - identifier: property.nonObject - count: 1 - path: ../../../src/wp-admin/user-edit.php - - - message: '#^Cannot access property \$infinite_scrolling on WP_User\|false\.$#' - identifier: property.nonObject - count: 1 - path: ../../../src/wp-admin/user-edit.php - message: '#^Cannot access property \$id on int\|string\|WP_Term\.$#' identifier: property.nonObject From 5df03172a5f33c15696fed9cccb3b635625deabf Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sat, 15 Aug 2026 16:29:47 -0700 Subject: [PATCH 09/11] Include the array returns in WP_Block_Type::__get()'s type The method proxies four kinds of value: get_variations() gives array[], get_uses_context() gives string[], a handles property with more than one entry gives string[], and a single entry gives a string, with null for anything it does not recognise. The documented return listed only string|string[]|null, so the array[] from the variations branch was never covered. That branch has been there since 6.5.0, but the omission was invisible while void sat in the union: PHPStan takes void to mean the method may return nothing and does not hold the remaining types to account. r62178 dropped void in favour of null, which turned the union into a contract and surfaced the gap immediately. This is the second such report from that commit. The first was WP_Widget::form(), where the correct fix was to restore void because the subclasses genuinely return nothing. Here void was misleading, since every path returns a value, so the fix is to finish the union rather than reinstate it. Behaviour is unchanged. The 104 block type tests pass. Regenerating the baselines drops 1 entry from tests/phpstan/baselines/return.type.neon. Co-Authored-By: Claude Opus 5 --- src/wp-includes/class-wp-block-type.php | 5 +++-- tests/phpstan/baselines/return.type.neon | 5 ----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/wp-includes/class-wp-block-type.php b/src/wp-includes/class-wp-block-type.php index 86f0ea21a2a3c..09fa28e43d361 100644 --- a/src/wp-includes/class-wp-block-type.php +++ b/src/wp-includes/class-wp-block-type.php @@ -358,8 +358,9 @@ public function __construct( $block_type, $args = array() ) { * * @param string $name Deprecated property name. * - * @return string|string[]|null The value read from the new property if the first item in the array provided, - * null when value not found or when unknown property name provided. + * @return string|string[]|array[]|null The value read from the new property if the first item in the array + * provided, the variations or uses context arrays for those two names, + * null when value not found or when unknown property name provided. */ public function __get( $name ) { if ( 'variations' === $name ) { diff --git a/tests/phpstan/baselines/return.type.neon b/tests/phpstan/baselines/return.type.neon index 9d99e94d0abd6..1aa527f0387fd 100644 --- a/tests/phpstan/baselines/return.type.neon +++ b/tests/phpstan/baselines/return.type.neon @@ -48,11 +48,6 @@ parameters: identifier: return.type count: 1 path: ../../../src/wp-includes/class-wp-block-processor.php - - - message: '#^Method WP_Block_Type\:\:__get\(\) should return array\\|string\|null but returns array\\.$#' - identifier: return.type - count: 1 - path: ../../../src/wp-includes/class-wp-block-type.php - message: '#^Method WP_Image_Editor_Imagick\:\:set_imagick_time_limit\(\) should return int\|null but returns float\.$#' identifier: return.type From 84c63c3362224af9148517c46d4c9ad18770dff4 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sat, 15 Aug 2026 16:38:48 -0700 Subject: [PATCH 10/11] Correct term_exists()'s conditional return for the no-taxonomy case r62680 gave term_exists() a conditional return type, and the branch for an empty $taxonomy says int|null. The function returns a string there. Without a taxonomy the query keeps its default 'fields' => 'ids', so the value shifted off the result set is a term ID, and the function hands it back as `return (string) $_term;`. Only when a taxonomy is passed does 'fields' become 'all' and the array of term_id and term_taxonomy_id get returned instead. The prose above the tag says "Returns the term ID", which is silent on int versus string; the conditional type resolved that silence the wrong way. Say numeric-string|null for that branch. The error this clears is the analyzer correctly reporting the function against its own declared type, not a fault in the function. Nothing downstream depended on the incorrect int: a full run before regenerating the baselines reported no new errors anywhere, only the stale entry for this one. The 26 term_exists tests pass. Regenerating the baselines drops 1 entry from tests/phpstan/baselines/return.type.neon. Co-Authored-By: Claude Opus 5 --- src/wp-includes/taxonomy.php | 2 +- tests/phpstan/baselines/return.type.neon | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index 29317f0a8bf9b..ea473ba391415 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -1592,7 +1592,7 @@ function unregister_term_meta( $taxonomy, $meta_key ) { * @phpstan-return ( * $term is null ? null : ( * $term is 0 ? 0 : ( - * $taxonomy is '' ? int|null : ( + * $taxonomy is '' ? numeric-string|null : ( * array{ * term_id: numeric-string, * term_taxonomy_id: numeric-string, diff --git a/tests/phpstan/baselines/return.type.neon b/tests/phpstan/baselines/return.type.neon index 1aa527f0387fd..21cae5fee03ca 100644 --- a/tests/phpstan/baselines/return.type.neon +++ b/tests/phpstan/baselines/return.type.neon @@ -148,11 +148,6 @@ parameters: identifier: return.type count: 2 path: ../../../src/wp-includes/revision.php - - - message: '#^Function term_exists\(\) should return array\{term_id\: numeric\-string, term_taxonomy_id\: numeric\-string\}\|int\|null but returns string\.$#' - identifier: return.type - count: 1 - path: ../../../src/wp-includes/taxonomy.php - message: '#^Function _wp_get_current_user\(\) should return WP_User but returns null\.$#' identifier: return.type From 77dc415362903135acf21763247a752de564b52c Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sat, 15 Aug 2026 23:27:58 -0700 Subject: [PATCH 11/11] Allow an integer for WP_Comment's two ID properties r62822 typed $comment_ID and $comment_post_ID as numeric-string, which is what hydrating a comment from the database produces. One place in core then contradicts it: get_comment_to_edit() casts both to int and writes them back onto the same object, so from that point on the object no longer matches its own declared type. Widen both to numeric-string|int and say in the description which function does it. The alternative, dropping the casts in get_comment_to_edit(), would change what its callers have received for years, and this is the same hedge already applied to WP_User::$user_level, documented as int|numeric-string|''. The narrower type was also costing precision rather than buying it. Because the analysis runs with treatPhpDocTypesAsCertain disabled, a union carrying int satisfies the many core call sites that hand these properties to parameters typed int, all of which had been baselined as string given. Regenerating drops 39 entries across 9 files, from comment.php and the REST controller to the recent comments widget, and introduces nothing: a full run before regenerating reported no new errors anywhere. The 794 comment tests pass. Co-Authored-By: Claude Opus 5 --- src/wp-includes/class-wp-comment.php | 14 +- tests/phpstan/baselines/argument.type.neon | 185 ------------------ .../baselines/assign.propertyType.neon | 10 - 3 files changed, 8 insertions(+), 201 deletions(-) diff --git a/src/wp-includes/class-wp-comment.php b/src/wp-includes/class-wp-comment.php index f6b4d8d75f5e3..a1ff141c0d262 100644 --- a/src/wp-includes/class-wp-comment.php +++ b/src/wp-includes/class-wp-comment.php @@ -63,22 +63,24 @@ final class WP_Comment { /** * Comment ID. * - * A numeric string, for compatibility reasons. + * A numeric string, for compatibility reasons. Note that {@see get_comment_to_edit()} + * replaces it with an integer in place. * * @since 4.4.0 - * @var string - * @phpstan-var numeric-string + * @var string|int + * @phpstan-var numeric-string|int */ public $comment_ID; /** * ID of the post the comment is associated with. * - * A numeric string, for compatibility reasons. + * A numeric string, for compatibility reasons. Note that {@see get_comment_to_edit()} + * replaces it with an integer in place. * * @since 4.4.0 - * @var string - * @phpstan-var numeric-string + * @var string|int + * @phpstan-var numeric-string|int */ public $comment_post_ID = '0'; diff --git a/tests/phpstan/baselines/argument.type.neon b/tests/phpstan/baselines/argument.type.neon index f1c4da546ffc5..9d5342b085692 100644 --- a/tests/phpstan/baselines/argument.type.neon +++ b/tests/phpstan/baselines/argument.type.neon @@ -28,21 +28,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-admin/admin-header.php - - - message: '#^Parameter \#1 \$post of function get_edit_post_link expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-admin/comment.php - - - message: '#^Parameter \#1 \$post of function get_post_status expects int\|WP_Post\|null, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-admin/comment.php - - - message: '#^Parameter \#1 \$post of function get_the_title expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 2 - path: ../../../src/wp-admin/comment.php - message: '#^Parameter \#1 \$text of function esc_attr expects float\|int\|string, bool given\.$#' identifier: argument.type @@ -58,16 +43,6 @@ parameters: identifier: argument.type count: 2 path: ../../../src/wp-admin/edit-form-advanced.php - - - message: '#^Parameter \#1 \$post of function get_edit_post_link expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-admin/edit-form-comment.php - - - message: '#^Parameter \#1 \$post of function get_the_title expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 2 - path: ../../../src/wp-admin/edit-form-comment.php - message: '#^Parameter \#1 \$screen of function do_meta_boxes expects string\|WP_Screen, null given\.$#' identifier: argument.type @@ -98,11 +73,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-admin/includes/ajax-actions.php - - - message: '#^Parameter \#1 \$comment_id of function _wp_ajax_delete_comment_response expects int, string given\.$#' - identifier: argument.type - count: 2 - path: ../../../src/wp-admin/includes/ajax-actions.php - message: '#^Parameter \#2 \$compare_from of function wp_get_revision_ui_diff expects int, string given\.$#' identifier: argument.type @@ -143,16 +113,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-admin/includes/class-wp-automatic-updater.php - - - message: '#^Parameter \#1 \$post of function post_password_required expects int\|WP_Post\|null, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-admin/includes/class-wp-comments-list-table.php - - - message: '#^Parameter \#3 \$post of function get_comment_class expects int\|WP_Post\|null, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-admin/includes/class-wp-comments-list-table.php - message: '#^Parameter \#3 \$number of function _nx expects int, float given\.$#' identifier: argument.type @@ -183,21 +143,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-admin/includes/class-wp-upgrader.php - - - message: '#^Parameter \#1 \$post of function _draft_or_post_title expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-admin/includes/dashboard.php - - - message: '#^Parameter \#1 \$post of function get_the_permalink expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-admin/includes/dashboard.php - - - message: '#^Parameter \#1 \$post of function post_password_required expects int\|WP_Post\|null, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-admin/includes/dashboard.php - message: '#^Parameter \#3 \$name of function submit_button expects string, false given\.$#' identifier: argument.type @@ -488,11 +433,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-content/themes/twentyeleven/functions.php - - - message: '#^Parameter \#1 \$comment of function get_comment_link expects int\|WP_Comment\|null, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-content/themes/twentyeleven/functions.php - message: '#^Parameter \#1 \$size of function next_image_link expects array\\|string, false given\.$#' identifier: argument.type @@ -628,11 +568,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-content/themes/twentyten/functions.php - - - message: '#^Parameter \#1 \$comment of function get_comment_link expects int\|WP_Comment\|null, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-content/themes/twentyten/functions.php - message: '#^Parameter \#1 \$wp_head_callback of function add_custom_image_header expects callable\(\)\: mixed, '''' given\.$#' identifier: argument.type @@ -698,11 +633,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-content/themes/twentytwelve/functions.php - - - message: '#^Parameter \#1 \$comment of function get_comment_link expects int\|WP_Comment\|null, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-content/themes/twentytwelve/functions.php - message: '#^Parameter \#1 \$size of function next_image_link expects array\\|string, false given\.$#' identifier: argument.type @@ -798,16 +728,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-includes/class-wp-block-parser.php - - - message: '#^Parameter \#1 \$child_id of method WP_Comment\:\:get_child\(\) expects int, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/class-wp-comment-query.php - - - message: '#^Parameter \#1 \$ids of function _prime_post_caches expects array\, list\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/class-wp-comment-query.php - message: '#^Parameter \#1 \$ajax_message of method WP_Customize_Manager\:\:wp_die\(\) expects string\|WP_Error, int given\.$#' identifier: argument.type @@ -928,11 +848,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-includes/class-wp-widget.php - - - message: '#^Parameter \#1 \$post of function get_the_title expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/class-wp-xmlrpc-server.php - message: '#^Parameter \#1 \$term_id of method wp_xmlrpc_server\:\:get_term_custom_fields\(\) expects int, string given\.$#' identifier: argument.type @@ -943,46 +858,11 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-includes/class-wp-xmlrpc-server.php - - - message: '#^Parameter \#1 \$comment_id of function get_page_of_comment expects int, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/comment-template.php - - - message: '#^Parameter \#1 \$post of function get_permalink expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/comment-template.php - - - message: '#^Parameter \#1 \$post of function post_password_required expects int\|WP_Post\|null, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/comment-template.php - message: '#^Parameter \#1 \$user_id of function get_userdata expects int, string given\.$#' identifier: argument.type count: 2 path: ../../../src/wp-includes/comment-template.php - - - message: '#^Parameter \#1 \$comment of function get_comment_link expects int\|WP_Comment\|null, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/comment.php - - - message: '#^Parameter \#1 \$comment_id of function add_comment_meta expects int, string given\.$#' - identifier: argument.type - count: 5 - path: ../../../src/wp-includes/comment.php - - - message: '#^Parameter \#1 \$comment_id of function delete_comment_meta expects int, string given\.$#' - identifier: argument.type - count: 8 - path: ../../../src/wp-includes/comment.php - - - message: '#^Parameter \#1 \$comment_id of function get_comment_text expects int\|WP_Comment, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/comment.php - message: '#^Parameter \#1 \$comment_id of function get_page_of_comment expects int, string given\.$#' identifier: argument.type @@ -998,26 +878,11 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-includes/comment.php - - - message: '#^Parameter \#1 \$ids of function clean_comment_cache expects array\|int, string given\.$#' - identifier: argument.type - count: 2 - path: ../../../src/wp-includes/comment.php - - - message: '#^Parameter \#1 \$post_id of function wp_update_comment_count expects int\|null, string given\.$#' - identifier: argument.type - count: 2 - path: ../../../src/wp-includes/comment.php - message: '#^Parameter \#2 \$meta_id of function delete_metadata_by_mid expects int, string\|null given\.$#' identifier: argument.type count: 1 path: ../../../src/wp-includes/comment.php - - - message: '#^Parameter \#2 \$object_ids of function update_meta_cache expects array\\|string, list\ given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/comment.php - message: '#^Parameter \#1 \$gmt_time of function spawn_cron expects int, float given\.$#' identifier: argument.type @@ -1048,11 +913,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-includes/feed-rss2.php - - - message: '#^Parameter \#1 \$post of function get_the_guid expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/feed.php - message: '#^Parameter \#2 \$message of class WP_Error constructor expects string, list\ given\.$#' identifier: argument.type @@ -1238,16 +1098,6 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-includes/pluggable.php - - - message: '#^Parameter \#1 \$post of function get_edit_post_link expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/pluggable.php - - - message: '#^Parameter \#1 \$post of function get_permalink expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 4 - path: ../../../src/wp-includes/pluggable.php - message: '#^Parameter \#1 \$user of function user_can expects int\|WP_User, string given\.$#' identifier: argument.type @@ -1373,36 +1223,6 @@ parameters: identifier: argument.type count: 2 path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php - - - message: '#^Parameter \#1 \$comment_id of function get_comment_type expects int\|WP_Comment, string given\.$#' - identifier: argument.type - count: 2 - path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php - - - message: '#^Parameter \#1 \$comment_id of function wp_delete_comment expects int\|WP_Comment, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php - - - message: '#^Parameter \#1 \$comment_id of function wp_trash_comment expects int\|WP_Comment, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php - - - message: '#^Parameter \#1 \$object_id of method WP_REST_Meta_Fields\:\:get_value\(\) expects int, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php - - - message: '#^Parameter \#2 \$comment_id of method WP_REST_Comments_Controller\:\:handle_status_param\(\) expects int, string given\.$#' - identifier: argument.type - count: 2 - path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php - - - message: '#^Parameter \#2 \$object_id of method WP_REST_Meta_Fields\:\:update_value\(\) expects int, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php - message: '#^Parameter \#2 \$value of method WP_HTTP_Response\:\:header\(\) expects string, int given\.$#' identifier: argument.type @@ -1573,8 +1393,3 @@ parameters: identifier: argument.type count: 1 path: ../../../src/wp-includes/widgets.php - - - message: '#^Parameter \#1 \$post of function get_the_title expects int\|WP_Post, string given\.$#' - identifier: argument.type - count: 1 - path: ../../../src/wp-includes/widgets/class-wp-widget-recent-comments.php diff --git a/tests/phpstan/baselines/assign.propertyType.neon b/tests/phpstan/baselines/assign.propertyType.neon index f53f802b7d1da..54ac7a169b3ea 100644 --- a/tests/phpstan/baselines/assign.propertyType.neon +++ b/tests/phpstan/baselines/assign.propertyType.neon @@ -18,16 +18,6 @@ parameters: ignoreErrors: - - - message: '#^Property WP_Comment\:\:\$comment_ID \(numeric\-string\) does not accept int\.$#' - identifier: assign.propertyType - count: 1 - path: ../../../src/wp-admin/includes/comment.php - - - message: '#^Property WP_Comment\:\:\$comment_post_ID \(numeric\-string\) does not accept int\.$#' - identifier: assign.propertyType - count: 1 - path: ../../../src/wp-admin/includes/comment.php - message: '#^Property WP_Block_Template\:\:\$author \(int\|null\) does not accept string\.$#' identifier: assign.propertyType