Commit a4b7b4393f for wordpress.org

commit a4b7b4393f1003ae654268a7807ec284345ec070
Author: westonruter <westonruter@git.wordpress.org>
Date:   Thu Nov 12 04:00:43 2026 +0000

    Code Quality: Resolve return.unusedType PHPStan errors.

    Every `return.unusedType` error is fixed and its baseline removed. Most came from a `@return` tag that listed a type the function never returns. Others came from a filter `@param` tag that listed too few types: PHPStan derives the result of `apply_filters()` from the hook's first `@param`, so where the function's documented return was already right, the hook docs were corrected instead of loosening the function's type.

    Correcting these types uncovered a real bug in `wp_mime_type_icon()`: when an attachment ID matched no icon, the `wp_mime_type_icon` filter received an undefined `$icon`, so `null` along with a warning. It now always receives `string|false`, and values read from the object cache are only used when they are strings. The `is_object()` guard in `_set_preview()` is removed, since `WP_Query` only applies the `the_preview` filter to a post already passed through `get_post()`, and no plugin in the directory was found to return anything else from it. Conditional return types are also added to `get_post_gallery()` and `sanitize_term()`, so callers get the type matching the arguments they pass.

    The `wp_imagecreatetruecolor()` error moves to the permanent ignore list, because PHPStan analyzes against PHP 7.4, where `imagecreatetruecolor()` returns a resource rather than a `GdImage`.

    Developed in https://github.com/WordPress/wordpress-develop/pull/15387.
    Follow-up to r63023, r63941.

    Props mukesh27, westonruter.
    See #65817.

    Built from https://develop.svn.wordpress.org/trunk@65410


    git-svn-id: http://core.svn.wordpress.org/trunk@64549 1a063a9b-81f0-0310-95a4-ce76da25c4cd

diff --git a/wp-admin/includes/plugin-install.php b/wp-admin/includes/plugin-install.php
index ffae71c5b8..496b7ffd36 100644
--- a/wp-admin/includes/plugin-install.php
+++ b/wp-admin/includes/plugin-install.php
@@ -223,9 +223,9 @@ function plugins_api( $action, $args = array() ) {
 	 *
 	 * @since 2.7.0
 	 *
-	 * @param object|WP_Error $res    Response object or WP_Error.
-	 * @param string          $action The type of information being requested from the Plugin Installation API.
-	 * @param object          $args   Plugin API arguments.
+	 * @param object|array|WP_Error $res    Response object or array, or WP_Error on failure.
+	 * @param string                $action The type of information being requested from the Plugin Installation API.
+	 * @param object                $args   Plugin API arguments.
 	 */
 	return apply_filters( 'plugins_api_result', $res, $action, $args );
 }
diff --git a/wp-admin/includes/post.php b/wp-admin/includes/post.php
index b7ef9ec696..f08f81766d 100644
--- a/wp-admin/includes/post.php
+++ b/wp-admin/includes/post.php
@@ -1163,7 +1163,7 @@ function update_meta( $meta_id, $meta_key, $meta_value ) {
  * @access private
  *
  * @param int|WP_Post $post Post ID or post object.
- * @return void|int|WP_Error Void if nothing fixed. 0 or WP_Error on update failure. The post ID on update success.
+ * @return void|int Void if nothing fixed. 0 on update failure. The post ID on update success.
  */
 function _fix_attachment_links( $post ) {
 	$post    = get_post( $post, ARRAY_A );
diff --git a/wp-admin/includes/update.php b/wp-admin/includes/update.php
index 22f44a33db..e7b02a2a62 100644
--- a/wp-admin/includes/update.php
+++ b/wp-admin/includes/update.php
@@ -11,7 +11,7 @@
  *
  * @since 2.7.0
  *
- * @return object|array|false The response from the API on success, false on failure.
+ * @return object|false The response from the API on success, false on failure.
  */
 function get_preferred_from_update_core() {
 	$updates = get_core_updates();
diff --git a/wp-includes/category-template.php b/wp-includes/category-template.php
index f48ebe6adb..130f55e3fe 100644
--- a/wp-includes/category-template.php
+++ b/wp-includes/category-template.php
@@ -1224,11 +1224,12 @@ function get_the_tag_list( $before = '', $sep = '', $after = '', $post_id = 0 )
 	 *
 	 * @since 2.3.0
 	 *
-	 * @param string $tag_list List of tags.
-	 * @param string $before   String to use before the tags.
-	 * @param string $sep      String to use between the tags.
-	 * @param string $after    String to use after the tags.
-	 * @param int    $post_id  Post ID.
+	 * @param string|false|WP_Error $tag_list A list of tags on success, false if there are no terms,
+	 *                                        WP_Error on failure.
+	 * @param string                $before   String to use before the tags.
+	 * @param string                $sep      String to use between the tags.
+	 * @param string                $after    String to use after the tags.
+	 * @param int                   $post_id  Post ID.
 	 */
 	return apply_filters( 'the_tags', $tag_list, $before, $sep, $after, $post_id );
 }
diff --git a/wp-includes/category.php b/wp-includes/category.php
index e6085418e2..e93c6c122e 100644
--- a/wp-includes/category.php
+++ b/wp-includes/category.php
@@ -428,7 +428,7 @@ function clean_category_cache( $id ) {
  * @since 4.4.0 The `$category` parameter now also accepts a WP_Term object.
  * @access private
  *
- * @param array|object|WP_Term $category Category row object or array.
+ * @param array|object|WP_Term|null $category Category row object or array. Null is left unchanged.
  */
 function _make_cat_compat( &$category ) {
 	if ( is_object( $category ) && ! is_wp_error( $category ) ) {
diff --git a/wp-includes/class-wp-recovery-mode-cookie-service.php b/wp-includes/class-wp-recovery-mode-cookie-service.php
index a2ee34a723..feefc942b6 100644
--- a/wp-includes/class-wp-recovery-mode-cookie-service.php
+++ b/wp-includes/class-wp-recovery-mode-cookie-service.php
@@ -195,7 +195,7 @@ final class WP_Recovery_Mode_Cookie_Service {
 	 * @since 5.2.0
 	 *
 	 * @param string $data Data to hash.
-	 * @return string|false The hashed $data, or false on failure.
+	 * @return string The hashed $data.
 	 */
 	private function recovery_mode_hash( $data ) {
 		$default_keys = array_unique(
diff --git a/wp-includes/general-template.php b/wp-includes/general-template.php
index 3344738229..4c6945a626 100644
--- a/wp-includes/general-template.php
+++ b/wp-includes/general-template.php
@@ -4760,9 +4760,9 @@ function wp_get_code_editor_settings( $args ) {
 	 *
 	 * @since 4.9.0
 	 *
-	 * @param array $settings The array of settings passed to the code editor.
-	 *                        A falsey value disables the editor.
-	 * @param array $args {
+	 * @param array|false $settings The array of settings passed to the code editor.
+	 *                              A falsey value disables the editor.
+	 * @param array       $args {
 	 *     Args passed when calling `get_code_editor_settings()`.
 	 *
 	 *     @type string   $type       The MIME type of the file to be edited.
diff --git a/wp-includes/media.php b/wp-includes/media.php
index 4cd69ade6c..3e84e97f40 100644
--- a/wp-includes/media.php
+++ b/wp-includes/media.php
@@ -5587,7 +5587,11 @@ function get_post_galleries( $post, $html = true ) {
  *
  * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
  * @param bool        $html Optional. Whether to return HTML or data. Default is true.
- * @return string|array Gallery data and srcs parsed from the expanded shortcode.
+ * @return string|array|false Gallery HTML or an array of gallery data and srcs parsed from
+ *                            the expanded shortcode, depending on `$html`. False if the post has
+ *                            no gallery.
+ *
+ * @phpstan-return ( $html is false ? array<mixed>|false : string|false )
  */
 function get_post_gallery( $post = 0, $html = true ) {
 	$galleries = get_post_galleries( $post, $html );
@@ -5598,9 +5602,10 @@ function get_post_gallery( $post = 0, $html = true ) {
 	 *
 	 * @since 3.6.0
 	 *
-	 * @param array       $gallery   The first-found post gallery.
-	 * @param int|WP_Post $post      Post ID or object.
-	 * @param array       $galleries Associative array of all found post galleries.
+	 * @param string|array<mixed>|false $gallery   The first-found post gallery, or false if the post has no gallery.
+	 *                                             An HTML string when `$html` is true, otherwise an array.
+	 * @param int|WP_Post               $post      Post ID or object.
+	 * @param array                     $galleries Associative array of all found post galleries.
 	 */
 	return apply_filters( 'get_post_gallery', $gallery, $post, $galleries );
 }
diff --git a/wp-includes/post.php b/wp-includes/post.php
index d73d945ef8..e0afc05cd1 100644
--- a/wp-includes/post.php
+++ b/wp-includes/post.php
@@ -3895,7 +3895,7 @@ function get_post_mime_types() {
  * @param string|string[] $wildcard_mime_types Mime types, e.g. `audio/mpeg`, `image` (same as `image/*`),
  *                                             or `flash` (same as `*flash*`).
  * @param string|string[] $real_mime_types     Real post mime type values.
- * @return array array(wildcard=>array(real types)).
+ * @return array<string[]> array(wildcard=>array(real types)).
  */
 function wp_match_mime_types( $wildcard_mime_types, $real_mime_types ) {
 	$matches = array();
@@ -7637,11 +7637,15 @@ function wp_attachment_is_image( $post = null ) {
  *
  * @param string|int $mime          MIME type or attachment ID.
  * @param string     $preferred_ext File format to prefer in return. Default '.png'.
- * @return string|false Icon, false otherwise.
+ * @return string|false Icon URL, or false if no icon was found.
  */
 function wp_mime_type_icon( $mime = 0, $preferred_ext = '.png' ) {
+	$icon = false;
 	if ( ! is_numeric( $mime ) ) {
-		$icon = wp_cache_get( "mime_type_icon_$mime" );
+		$cached_icon = wp_cache_get( "mime_type_icon_$mime" );
+		if ( is_string( $cached_icon ) ) {
+			$icon = $cached_icon;
+		}
 	}

 	// Check if preferred file format variable is present and is a validly formatted file extension.
@@ -7756,11 +7760,12 @@ function wp_mime_type_icon( $mime = 0, $preferred_ext = '.png' ) {

 		foreach ( $matches as $match => $wilds ) {
 			foreach ( $wilds as $wild ) {
-				if ( ! isset( $types[ $wild ] ) ) {
+				$type_icon = $types[ $wild ] ?? null;
+				if ( ! is_string( $type_icon ) ) {
 					continue;
 				}

-				$icon = $types[ $wild ];
+				$icon = $type_icon;
 				if ( ! is_numeric( $mime ) ) {
 					wp_cache_add( "mime_type_icon_$mime", $icon );
 				}
@@ -7774,10 +7779,10 @@ function wp_mime_type_icon( $mime = 0, $preferred_ext = '.png' ) {
 	 *
 	 * @since 2.1.0
 	 *
-	 * @param string $icon    Path to the mime type icon.
-	 * @param string $mime    Mime type.
-	 * @param int    $post_id Attachment ID. Will equal 0 if the function passed
-	 *                        the mime type.
+	 * @param string|false $icon    URL of the mime type icon, or false if no icon was found.
+	 * @param string|int   $mime    Mime type, or 0 if no post was found for the passed ID.
+	 * @param int          $post_id Attachment ID. Will equal 0 if the function passed
+	 *                              the mime type or no post was found for the passed ID.
 	 */
 	return apply_filters( 'wp_mime_type_icon', $icon, $mime, $post_id );
 }
diff --git a/wp-includes/revision.php b/wp-includes/revision.php
index 77b0b6425e..03fb126029 100644
--- a/wp-includes/revision.php
+++ b/wp-includes/revision.php
@@ -870,13 +870,9 @@ function wp_revisions_to_keep( $post ) {
  * @access private
  *
  * @param WP_Post $post
- * @return WP_Post|false
+ * @return WP_Post
  */
 function _set_preview( $post ) {
-	if ( ! is_object( $post ) ) {
-		return $post;
-	}
-
 	$preview = wp_get_post_autosave( $post->ID );

 	if ( is_object( $preview ) ) {
diff --git a/wp-includes/taxonomy.php b/wp-includes/taxonomy.php
index 12a5db2b79..2bf9f30dfb 100644
--- a/wp-includes/taxonomy.php
+++ b/wp-includes/taxonomy.php
@@ -1273,7 +1273,10 @@ 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 The term sanitized for editing, WP_Error if the term ID is empty or the
+ *                                 taxonomy does not exist, or an empty string if the term does not exist.
+ *
+ * @phpstan-return WP_Term|''|WP_Error
  */
 function get_term_to_edit( $id, $taxonomy ) {
 	$term = get_term( $id, $taxonomy );
@@ -1786,12 +1789,18 @@ function term_is_ancestor_of( $term1, $term2, $taxonomy ) {
  *
  * @since 2.3.0
  *
- * @param array|object $term     The term to check.
- * @param string       $taxonomy The taxonomy name to use.
- * @param string       $context  Optional. Context in which to sanitize the term.
- *                               Accepts 'raw', 'edit', 'db', 'display', 'rss',
- *                               'attribute', or 'js'. Default 'display'.
- * @return array|object Term with all fields sanitized.
+ * @param array<string, mixed>|object $term     The term to check.
+ * @param string                      $taxonomy The taxonomy name to use.
+ * @param string                      $context  Optional. Context in which to sanitize the term.
+ *                                              Accepts 'raw', 'edit', 'db', 'display', 'rss',
+ *                                              'attribute', or 'js'. Default 'display'.
+ * @return array|object Term with all fields sanitized (will be the same type as `$term`).
+ *
+ * @phpstan-return (
+ *     $term is WP_Term ? WP_Term : (
+ *         $term is array ? array<string, mixed> : object
+ *     )
+ * )
  */
 function sanitize_term( $term, $taxonomy, $context = 'display' ) {
 	$fields = array( 'term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group', 'term_taxonomy_id', 'object_id' );
@@ -1836,16 +1845,16 @@ function sanitize_term( $term, $taxonomy, $context = 'display' ) {
  *
  * @since 2.3.0
  *
- * @param string $field    Term field to sanitize.
- * @param string $value    Search for this term value.
- * @param int    $term_id  Term ID.
- * @param string $taxonomy Taxonomy name.
- * @param string $context  Context in which to sanitize the term field.
- *                         Accepts 'raw', 'edit', 'db', 'display', 'rss',
- *                         'attribute', or 'js'.
+ * @param string     $field    Term field to sanitize.
+ * @param string|int $value    Search for this term value.
+ * @param int        $term_id  Term ID.
+ * @param string     $taxonomy Taxonomy name.
+ * @param string     $context  Context in which to sanitize the term field.
+ *                             Accepts 'raw', 'edit', 'db', 'display', 'rss',
+ *                             'attribute', or 'js'.
  * @return mixed Sanitized field.
  *
- * @phpstan-template T of string
+ * @phpstan-template T of string|int
  * @phpstan-param T $value
  * @phpstan-return (
  *     $field is 'parent'|'term_id'|'count'|'term_group'|'term_taxonomy_id'|'object_id'
diff --git a/wp-includes/user.php b/wp-includes/user.php
index 02a412b291..518278feb9 100644
--- a/wp-includes/user.php
+++ b/wp-includes/user.php
@@ -5341,8 +5341,9 @@ function wp_is_password_reset_allowed_for_user( $user ) {
 	 *
 	 * @since 2.7.0
 	 *
-	 * @param bool $allow   Whether to allow the password to be reset. Default true.
-	 * @param int  $user_id The ID of the user attempting to reset a password.
+	 * @param bool|WP_Error $allow   Whether to allow the password to be reset, or a WP_Error to explain
+	 *                               why it is not allowed. Default true.
+	 * @param int           $user_id The ID of the user attempting to reset a password.
 	 */
 	return apply_filters( 'allow_password_reset', $allow, $user->ID );
 }
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 58b35ba139..3bb43757c4 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '7.2-beta5-65409';
+$wp_version = '7.2-beta5-65410';

 /**
  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
diff --git a/wp-signup.php b/wp-signup.php
index 4eb8c60b21..dd4e5d5365 100644
--- a/wp-signup.php
+++ b/wp-signup.php
@@ -443,8 +443,8 @@ function signup_another_blog( $blogname = '', $blog_title = '', $errors = '' ) {
  * @global string   $domain     The new site's domain.
  * @global string   $path       The new site's path.
  *
- * @return null|bool True if site signup was validated, false on error.
- *                   The function halts all execution if the user is not logged in.
+ * @return bool True if site signup was validated, false on error.
+ *              The function halts all execution if the user is not logged in.
  */
 function validate_another_blog_signup() {
 	global $blogname, $blog_title, $errors, $domain, $path;