diff --git a/src/wp-includes/category.php b/src/wp-includes/category.php index e6085418e255d..38fe4e6adba65 100644 --- a/src/wp-includes/category.php +++ b/src/wp-includes/category.php @@ -291,6 +291,8 @@ function cat_is_ancestor_of( $cat1, $cat2 ) { * @param object|array $category Category data. * @param string $context Optional. Default 'display'. * @return object|array Same type as $category with sanitized data for safe use. + * + * @phpstan-return ($category is WP_Term ? WP_Term : ($category is array ? array : object)) */ function sanitize_category( $category, $context = 'display' ) { return sanitize_term( $category, 'category', $context ); diff --git a/src/wp-includes/class-wp-widget-factory.php b/src/wp-includes/class-wp-widget-factory.php index 1f6ed3a58919e..f7009788549e4 100644 --- a/src/wp-includes/class-wp-widget-factory.php +++ b/src/wp-includes/class-wp-widget-factory.php @@ -69,11 +69,14 @@ public function WP_Widget_Factory() { * @since 7.1.1 The key for an instance is prefixed so that it is never cast to an integer. * * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass. + * + * @phpstan-param class-string|WP_Widget $widget */ public function register( $widget ) { if ( $widget instanceof WP_Widget ) { $this->widgets[ self::INSTANCE_KEY_PREFIX . spl_object_id( $widget ) ] = $widget; } else { + // @phpstan-ignore arguments.count (Widget classes declare their own constructor, which takes no arguments.) $this->widgets[ $widget ] = new $widget(); } } @@ -87,6 +90,8 @@ public function register( $widget ) { * @since 7.1.1 The key for an instance is prefixed so that it is never cast to an integer. * * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass. + * + * @phpstan-param class-string|WP_Widget $widget */ public function unregister( $widget ) { if ( $widget instanceof WP_Widget ) { diff --git a/src/wp-includes/class-wp-widget.php b/src/wp-includes/class-wp-widget.php index b131c50db3226..1f854f4b70b53 100644 --- a/src/wp-includes/class-wp-widget.php +++ b/src/wp-includes/class-wp-widget.php @@ -16,6 +16,8 @@ * * @since 2.8.0 * @since 4.4.0 Moved to its own file from wp-includes/widgets.php + * + * @phpstan-template T of array = array */ #[AllowDynamicProperties] class WP_Widget { @@ -109,6 +111,8 @@ class WP_Widget { * @param array $args Display arguments including 'before_title', 'after_title', * 'before_widget', and 'after_widget'. * @param array $instance The settings for the particular instance of the widget. + * + * @phpstan-param T $instance */ public function widget( $args, $instance ) { die( 'function WP_Widget::widget() must be overridden in a subclass.' ); @@ -127,6 +131,10 @@ public function widget( $args, $instance ) { * WP_Widget::form(). * @param array $old_instance Old settings for this instance. * @return array Settings to save or bool false to cancel saving. + * + * @phpstan-param array $new_instance + * @phpstan-param T|array{} $old_instance + * @phpstan-return array|false */ public function update( $new_instance, $old_instance ) { return $new_instance; @@ -140,6 +148,8 @@ public function update( $new_instance, $old_instance ) { * @param array $instance The settings for the particular instance of the widget. * @return string|void Default return is 'noform'. A subclass which echoes its own * form returns nothing. + * + * @phpstan-param T|array{} $instance */ public function form( $instance ) { echo '

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

'; diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php index c39beaf7b1d68..3a18046999864 100644 --- a/src/wp-includes/formatting.php +++ b/src/wp-includes/formatting.php @@ -2926,6 +2926,10 @@ function stripslashes_from_strings_only( $value ) { * * @param mixed $value The array or string to be encoded. * @return mixed The encoded value. + * + * @phpstan-template T + * @phpstan-param T $value + * @phpstan-return (T is array ? array, mixed> : (T is object ? T : string)) */ function urlencode_deep( $value ) { return map_deep( $value, 'urlencode' ); @@ -2938,6 +2942,10 @@ function urlencode_deep( $value ) { * * @param mixed $value The array or string to be encoded. * @return mixed The encoded value. + * + * @phpstan-template T + * @phpstan-param T $value + * @phpstan-return (T is array ? array, mixed> : (T is object ? T : string)) */ function rawurlencode_deep( $value ) { return map_deep( $value, 'rawurlencode' ); @@ -2950,6 +2958,10 @@ function rawurlencode_deep( $value ) { * * @param mixed $value The array or string to be decoded. * @return mixed The decoded value. + * + * @phpstan-template T + * @phpstan-param T $value + * @phpstan-return (T is array ? array, mixed> : (T is object ? T : string)) */ function urldecode_deep( $value ) { return map_deep( $value, 'urldecode' ); diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index 1159ca64e6d2d..0a2f6434fcd18 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -1267,7 +1267,7 @@ function get_term_field( $field, $term, $taxonomy = '', $context = 'display' ) { * * @param int|object $id Term ID or object. * @param string $taxonomy Taxonomy name. - * @return string|int|null|WP_Error Will return empty string if $term is not an object. + * @return WP_Term|string|WP_Error Sanitized term, an empty string if `$id` is not a term, or WP_Error on failure. */ function get_term_to_edit( $id, $taxonomy ) { $term = get_term( $id, $taxonomy ); @@ -1786,6 +1786,8 @@ function term_is_ancestor_of( $term1, $term2, $taxonomy ) { * Accepts 'raw', 'edit', 'db', 'display', 'rss', * 'attribute', or 'js'. Default 'display'. * @return array|object Term with all fields sanitized. + * + * @phpstan-return ($term is WP_Term ? WP_Term : ($term is array ? array : object)) */ function sanitize_term( $term, $taxonomy, $context = 'display' ) { $fields = array( 'term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group', 'term_taxonomy_id', 'object_id' ); diff --git a/src/wp-includes/widgets.php b/src/wp-includes/widgets.php index 5e679f4b92ca9..5b38cb1cab2ac 100644 --- a/src/wp-includes/widgets.php +++ b/src/wp-includes/widgets.php @@ -116,6 +116,8 @@ * @global WP_Widget_Factory $wp_widget_factory * * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass. + * + * @phpstan-param class-string|WP_Widget $widget */ function register_widget( $widget ) { global $wp_widget_factory; @@ -138,6 +140,8 @@ function register_widget( $widget ) { * @global WP_Widget_Factory $wp_widget_factory * * @param string|WP_Widget $widget Either the name of a `WP_Widget` subclass or an instance of a `WP_Widget` subclass. + * + * @phpstan-param class-string|WP_Widget $widget */ function unregister_widget( $widget ) { global $wp_widget_factory; diff --git a/tests/phpstan/baselines/argument.type.neon b/tests/phpstan/baselines/argument.type.neon index 193d2aa64f6f3..64dcc14b98a43 100644 --- a/tests/phpstan/baselines/argument.type.neon +++ b/tests/phpstan/baselines/argument.type.neon @@ -824,7 +824,7 @@ parameters: count: 1 path: ../../../src/wp-includes/class-wp-user.php - - message: '#^Parameter \#1 \$number of method WP_Widget\:\:_set\(\) expects int, string given\.$#' + message: '#^Parameter \#1 \$number of method WP_Widget\\>\:\:_set\(\) expects int, string given\.$#' identifier: argument.type count: 1 path: ../../../src/wp-includes/class-wp-widget.php diff --git a/tests/phpstan/baselines/isset.property.neon b/tests/phpstan/baselines/isset.property.neon index f5e272b598f34..fa7b3d126e71d 100644 --- a/tests/phpstan/baselines/isset.property.neon +++ b/tests/phpstan/baselines/isset.property.neon @@ -144,7 +144,7 @@ parameters: count: 1 path: ../../../src/wp-includes/class-wp-user.php - - message: '#^Property WP_Widget\:\:\$alt_option_name \(string\) in isset\(\) is not nullable\.$#' + message: '#^Property WP_Widget\\>\:\:\$alt_option_name \(string\) in isset\(\) is not nullable\.$#' identifier: isset.property count: 1 path: ../../../src/wp-includes/class-wp-widget.php diff --git a/tests/phpstan/baselines/property.nonObject.neon b/tests/phpstan/baselines/property.nonObject.neon index 895c9e3656d3d..4c8e2bfea6150 100644 --- a/tests/phpstan/baselines/property.nonObject.neon +++ b/tests/phpstan/baselines/property.nonObject.neon @@ -73,16 +73,6 @@ parameters: identifier: property.nonObject count: 1 path: ../../../src/wp-admin/includes/class-wp-plugin-install-list-table.php - - - message: '#^Cannot access property \$parent on array\|object\.$#' - identifier: property.nonObject - count: 1 - path: ../../../src/wp-admin/includes/class-wp-terms-list-table.php - - - message: '#^Cannot access property \$term_id on array\|object\.$#' - identifier: property.nonObject - count: 2 - path: ../../../src/wp-admin/includes/class-wp-terms-list-table.php - message: '#^Cannot access property \$info on array\|object\.$#' identifier: property.nonObject diff --git a/tests/phpstan/baselines/return.unusedType.neon b/tests/phpstan/baselines/return.unusedType.neon index 2acebf529a781..a1a27541a6f7c 100644 --- a/tests/phpstan/baselines/return.unusedType.neon +++ b/tests/phpstan/baselines/return.unusedType.neon @@ -78,16 +78,6 @@ parameters: identifier: return.unusedType count: 1 path: ../../../src/wp-includes/revision.php - - - message: '#^Function get_term_to_edit\(\) never returns int so it can be removed from the return type\.$#' - identifier: return.unusedType - count: 1 - path: ../../../src/wp-includes/taxonomy.php - - - message: '#^Function get_term_to_edit\(\) never returns null so it can be removed from the return type\.$#' - identifier: return.unusedType - count: 1 - path: ../../../src/wp-includes/taxonomy.php - message: '#^Function wp_is_password_reset_allowed_for_user\(\) never returns WP_Error so it can be removed from the return type\.$#' identifier: return.unusedType