From 544414a2e4f9260a1861c61f0bb106ffa01ec548 Mon Sep 17 00:00:00 2001 From: Christoph Daum Date: Mon, 23 Feb 2026 10:50:17 +0100 Subject: [PATCH 1/8] Docs: Replace void with null in union return types in Administration Fixes #64702. See #64694. Co-Authored-By: xateman --- src/wp-admin/includes/class-wp-importer.php | 4 ++-- .../class-wp-privacy-requests-table.php | 2 +- src/wp-admin/includes/class-wp-site-health.php | 2 +- src/wp-admin/includes/dashboard.php | 2 +- src/wp-admin/includes/file.php | 2 +- src/wp-admin/includes/media.php | 2 +- src/wp-admin/includes/plugin.php | 4 ++-- src/wp-admin/includes/post.php | 2 +- src/wp-includes/class-wp-admin-bar.php | 18 +++++++++--------- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/wp-admin/includes/class-wp-importer.php b/src/wp-admin/includes/class-wp-importer.php index 085a5adc0e71a..8b7624ccb72df 100644 --- a/src/wp-admin/includes/class-wp-importer.php +++ b/src/wp-admin/includes/class-wp-importer.php @@ -136,7 +136,7 @@ public function get_imported_comments( $blog_id ) { /** * @param int $blog_id - * @return int|void + * @return int */ public function set_blog( $blog_id ) { if ( is_numeric( $blog_id ) ) { @@ -177,7 +177,7 @@ public function set_blog( $blog_id ) { /** * @param int $user_id - * @return int|void + * @return int */ public function set_user( $user_id ) { if ( is_numeric( $user_id ) ) { diff --git a/src/wp-admin/includes/class-wp-privacy-requests-table.php b/src/wp-admin/includes/class-wp-privacy-requests-table.php index cffd2218f11f7..59f926e9d7b27 100644 --- a/src/wp-admin/includes/class-wp-privacy-requests-table.php +++ b/src/wp-admin/includes/class-wp-privacy-requests-table.php @@ -435,7 +435,7 @@ public function column_cb( $item ) { * @since 4.9.6 * * @param WP_User_Request $item Item being shown. - * @return string|void Status column markup. Returns a string if no status is found, + * @return string|null Status column markup. Returns a string if no status is found, * otherwise it displays the markup. */ public function column_status( $item ) { diff --git a/src/wp-admin/includes/class-wp-site-health.php b/src/wp-admin/includes/class-wp-site-health.php index 44c04175abaf2..ab13202c95d32 100644 --- a/src/wp-admin/includes/class-wp-site-health.php +++ b/src/wp-admin/includes/class-wp-site-health.php @@ -167,7 +167,7 @@ public function enqueue_scripts() { * @since 5.4.0 * * @param callable $callback - * @return mixed|void + * @return mixed */ private function perform_test( $callback ) { /** diff --git a/src/wp-admin/includes/dashboard.php b/src/wp-admin/includes/dashboard.php index 214b6c22c686a..befc7a811f2cf 100644 --- a/src/wp-admin/includes/dashboard.php +++ b/src/wp-admin/includes/dashboard.php @@ -1648,7 +1648,7 @@ function wp_dashboard_primary_output( $widget_id, $feeds ) { * * @since 3.0.0 * - * @return true|void True if not multisite, user can't upload files, or the space check option is disabled. + * @return true|null True if not multisite, user can't upload files, or the space check option is disabled. */ function wp_dashboard_quota() { if ( ! is_multisite() || ! current_user_can( 'upload_files' ) diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php index 99dc03c6cd656..3abdc4ad10fe0 100644 --- a/src/wp-admin/includes/file.php +++ b/src/wp-admin/includes/file.php @@ -734,7 +734,7 @@ function wp_tempnam( $filename = '', $dir = '' ) { * @param string $file File the user is attempting to edit. * @param string[] $allowed_files Optional. Array of allowed files to edit. * `$file` must match an entry exactly. - * @return string|void Returns the file name on success, dies on failure. + * @return string Returns the file name on success, dies on failure. */ function validate_file_to_edit( $file, $allowed_files = array() ) { $code = validate_file( $file, $allowed_files ); diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php index 1d45224f5b7e4..7bd1c96d39f98 100644 --- a/src/wp-admin/includes/media.php +++ b/src/wp-admin/includes/media.php @@ -736,7 +736,7 @@ function get_upload_iframe_src( $type = null, $post_id = null, $tab = null ) { * * @since 2.5.0 * - * @return null|array|void Array of error messages keyed by attachment ID, null or void on success. + * @return null|array Array of error messages keyed by attachment ID, null on success. */ function media_upload_form_handler() { check_admin_referer( 'media-form' ); diff --git a/src/wp-admin/includes/plugin.php b/src/wp-admin/includes/plugin.php index fae10f1a679a4..ce5e7b8fbaab7 100644 --- a/src/wp-admin/includes/plugin.php +++ b/src/wp-admin/includes/plugin.php @@ -1296,8 +1296,8 @@ function is_uninstallable_plugin( $plugin ) { * @since 2.7.0 * * @param string $plugin Path to the plugin file relative to the plugins directory. - * @return true|void True if a plugin's uninstall.php file has been found and included. - * Void otherwise. + * @return true|null True if a plugin's uninstall.php file has been found and included. + * Null otherwise. */ function uninstall_plugin( $plugin ) { $file = plugin_basename( $plugin ); diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php index de5aa4fb7d0fa..d19d3208aa42b 100644 --- a/src/wp-admin/includes/post.php +++ b/src/wp-admin/includes/post.php @@ -982,7 +982,7 @@ function wp_write_post() { * * @since 2.0.0 * - * @return int|void Post ID on success, void on failure. + * @return int Post ID on success. Dies on failure. */ function write_post() { $result = wp_write_post(); diff --git a/src/wp-includes/class-wp-admin-bar.php b/src/wp-includes/class-wp-admin-bar.php index dfebbb20e4c86..a6e718e6bed02 100644 --- a/src/wp-includes/class-wp-admin-bar.php +++ b/src/wp-includes/class-wp-admin-bar.php @@ -193,7 +193,7 @@ final protected function _set_node( $args ) { * @since 3.3.0 * * @param string $id - * @return object|void Node. + * @return object|null Node. */ final public function get_node( $id ) { $node = $this->_get_node( $id ); @@ -206,11 +206,11 @@ final public function get_node( $id ) { * @since 3.3.0 * * @param string $id - * @return object|void + * @return object|null */ final protected function _get_node( $id ) { if ( $this->bound ) { - return; + return null; } if ( empty( $id ) ) { @@ -225,12 +225,12 @@ final protected function _get_node( $id ) { /** * @since 3.3.0 * - * @return array|void + * @return array|null */ final public function get_nodes() { $nodes = $this->_get_nodes(); if ( ! $nodes ) { - return; + return null; } foreach ( $nodes as &$node ) { @@ -242,11 +242,11 @@ final public function get_nodes() { /** * @since 3.3.0 * - * @return array|void + * @return array|null */ final protected function _get_nodes() { if ( $this->bound ) { - return; + return null; } return $this->nodes; @@ -307,11 +307,11 @@ public function render() { /** * @since 3.3.0 * - * @return object|void + * @return object|null */ final protected function _bind() { if ( $this->bound ) { - return; + return null; } /* From b12386873376e9825135d37515bff3b0ec65ef79 Mon Sep 17 00:00:00 2001 From: Christoph Daum Date: Mon, 23 Feb 2026 12:36:09 +0100 Subject: [PATCH 2/8] fix: resolve PHPStan warnings in file.php and post.php Thanks to @mukeshpanchal27 for catching these. --- src/wp-admin/includes/file.php | 2 +- src/wp-admin/includes/post.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php index 3abdc4ad10fe0..14027a56192ed 100644 --- a/src/wp-admin/includes/file.php +++ b/src/wp-admin/includes/file.php @@ -734,7 +734,7 @@ function wp_tempnam( $filename = '', $dir = '' ) { * @param string $file File the user is attempting to edit. * @param string[] $allowed_files Optional. Array of allowed files to edit. * `$file` must match an entry exactly. - * @return string Returns the file name on success, dies on failure. + * @return string|null Returns the file name on success, dies on failure. */ function validate_file_to_edit( $file, $allowed_files = array() ) { $code = validate_file( $file, $allowed_files ); diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php index d19d3208aa42b..fe8008224d9e7 100644 --- a/src/wp-admin/includes/post.php +++ b/src/wp-admin/includes/post.php @@ -988,9 +988,9 @@ function write_post() { $result = wp_write_post(); if ( is_wp_error( $result ) ) { wp_die( $result->get_error_message() ); - } else { - return $result; } + + return $result; } // From 2f1d8d5f97f4f6a338bdb5bd3c0161498a4f98e1 Mon Sep 17 00:00:00 2001 From: Christoph Daum Date: Wed, 25 Feb 2026 08:53:16 +0100 Subject: [PATCH 3/8] Docs: Address review feedback for return types Add `never` to return types for functions that can exit or die, add explicit `return null` in `WP_Admin_Bar::get_node()`, and improve the PHPDoc for `WP_Importer::set_blog()`. --- src/wp-admin/includes/class-wp-importer.php | 12 +++++++++--- src/wp-admin/includes/file.php | 2 +- src/wp-admin/includes/media.php | 4 ++-- src/wp-admin/includes/post.php | 2 +- src/wp-includes/class-wp-admin-bar.php | 1 + 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/wp-admin/includes/class-wp-importer.php b/src/wp-admin/includes/class-wp-importer.php index 8b7624ccb72df..0c66b02a96bdd 100644 --- a/src/wp-admin/includes/class-wp-importer.php +++ b/src/wp-admin/includes/class-wp-importer.php @@ -135,8 +135,14 @@ public function get_imported_comments( $blog_id ) { } /** - * @param int $blog_id - * @return int + * Sets the blog to import to. + * + * Accepts a numeric blog ID or a URL string. When given a URL, + * the blog is looked up by domain and path. On multisite, switches + * to the resolved blog. Exits with an error if the blog cannot be found. + * + * @param int|string $blog_id Blog ID or URL. + * @return int|never Blog ID on success. Exits on failure. */ public function set_blog( $blog_id ) { if ( is_numeric( $blog_id ) ) { @@ -177,7 +183,7 @@ public function set_blog( $blog_id ) { /** * @param int $user_id - * @return int + * @return int|never */ public function set_user( $user_id ) { if ( is_numeric( $user_id ) ) { diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php index 14027a56192ed..f5b7c2bc2a0b5 100644 --- a/src/wp-admin/includes/file.php +++ b/src/wp-admin/includes/file.php @@ -734,7 +734,7 @@ function wp_tempnam( $filename = '', $dir = '' ) { * @param string $file File the user is attempting to edit. * @param string[] $allowed_files Optional. Array of allowed files to edit. * `$file` must match an entry exactly. - * @return string|null Returns the file name on success, dies on failure. + * @return string|never Returns the file name on success, dies on failure. */ function validate_file_to_edit( $file, $allowed_files = array() ) { $code = validate_file( $file, $allowed_files ); diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php index 7bd1c96d39f98..01b1f3e3ef163 100644 --- a/src/wp-admin/includes/media.php +++ b/src/wp-admin/includes/media.php @@ -736,7 +736,7 @@ function get_upload_iframe_src( $type = null, $post_id = null, $tab = null ) { * * @since 2.5.0 * - * @return null|array Array of error messages keyed by attachment ID, null on success. + * @return null|array|never Array of error messages keyed by attachment ID, null on success, or exit. */ function media_upload_form_handler() { check_admin_referer( 'media-form' ); @@ -959,7 +959,7 @@ function wp_media_upload_handler() { $html = apply_filters( 'image_send_to_editor_url', $html, sanitize_url( $src ), $alt, $align ); } - return media_send_to_editor( $html ); + media_send_to_editor( $html ); } if ( isset( $_POST['save'] ) ) { diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php index fe8008224d9e7..e19977cb2d24f 100644 --- a/src/wp-admin/includes/post.php +++ b/src/wp-admin/includes/post.php @@ -982,7 +982,7 @@ function wp_write_post() { * * @since 2.0.0 * - * @return int Post ID on success. Dies on failure. + * @return int|never Post ID on success. Dies on failure. */ function write_post() { $result = wp_write_post(); diff --git a/src/wp-includes/class-wp-admin-bar.php b/src/wp-includes/class-wp-admin-bar.php index a6e718e6bed02..a65df3ea3ee88 100644 --- a/src/wp-includes/class-wp-admin-bar.php +++ b/src/wp-includes/class-wp-admin-bar.php @@ -200,6 +200,7 @@ final public function get_node( $id ) { if ( $node ) { return clone $node; } + return null; } /** From 7d677fab980389aa89470dba9d4749848fea56a0 Mon Sep 17 00:00:00 2001 From: Christoph Daum Date: Wed, 25 Feb 2026 08:54:20 +0100 Subject: [PATCH 4/8] Remove return for media_send_to_editor() calls media_send_to_editor() always exits and never returns a value, making the return statement dead code. --- src/wp-admin/includes/media.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php index 01b1f3e3ef163..ea55ab9e8cd3d 100644 --- a/src/wp-admin/includes/media.php +++ b/src/wp-admin/includes/media.php @@ -857,7 +857,7 @@ function media_upload_form_handler() { */ $html = apply_filters( 'media_send_to_editor', $html, $send_id, $attachment ); - return media_send_to_editor( $html ); + media_send_to_editor( $html ); } return $errors; From 12a2bc562b5dc483dba164298ec8ce734b6d7a1a Mon Sep 17 00:00:00 2001 From: Christoph Daum Date: Wed, 25 Feb 2026 09:08:24 +0100 Subject: [PATCH 5/8] Docs: Use array shape for perform_test() return type --- src/wp-admin/includes/class-wp-site-health.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/wp-admin/includes/class-wp-site-health.php b/src/wp-admin/includes/class-wp-site-health.php index ab13202c95d32..75e046ef8ffa7 100644 --- a/src/wp-admin/includes/class-wp-site-health.php +++ b/src/wp-admin/includes/class-wp-site-health.php @@ -167,7 +167,17 @@ public function enqueue_scripts() { * @since 5.4.0 * * @param callable $callback - * @return mixed + * @return array{ + * label: string, + * status: 'good'|'recommended'|'critical', + * badge: array{ + * label: string, + * color: string, + * }, + * description: string, + * actions: string, + * test: string, + * } */ private function perform_test( $callback ) { /** From 0a3e8f1b556f0983a3d08bc218b0a980d1a7b390 Mon Sep 17 00:00:00 2001 From: Christoph Daum Date: Wed, 25 Feb 2026 17:16:32 +0100 Subject: [PATCH 6/8] fix: Add default case to validate_file_to_edit() switch The switch only handled codes 1 and 3 from validate_file(), but code 2 (absolute Windows drive paths) fell through without returning or dying. This caused PHPStan to warn about a missing return statement for the string|never return type. --- src/wp-admin/includes/file.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php index f5b7c2bc2a0b5..16f819ca97d2a 100644 --- a/src/wp-admin/includes/file.php +++ b/src/wp-admin/includes/file.php @@ -751,6 +751,7 @@ function validate_file_to_edit( $file, $allowed_files = array() ) { // wp_die( __('Sorry, cannot call files with their real path.' )); case 3: + default: wp_die( __( 'Sorry, that file cannot be edited.' ) ); } } From 4013816c617dc7a1071de7aef3f593b795d6ec23 Mon Sep 17 00:00:00 2001 From: Christoph Daum Date: Wed, 25 Feb 2026 22:01:37 +0100 Subject: [PATCH 7/8] docs: Add @return never to media_send_to_editor() The function unconditionally calls exit, so the return type should be documented as never. --- src/wp-admin/includes/media.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php index ea55ab9e8cd3d..abc1e35da8347 100644 --- a/src/wp-admin/includes/media.php +++ b/src/wp-admin/includes/media.php @@ -269,6 +269,7 @@ function _cleanup_image_add_caption( $matches ) { * @since 2.5.0 * * @param string $html + * @return never */ function media_send_to_editor( $html ) { ?> From 8f8ec7097d800340dda256fb802924d3a3c23686 Mon Sep 17 00:00:00 2001 From: Christoph Daum Date: Thu, 26 Feb 2026 09:45:33 +0100 Subject: [PATCH 8/8] fix: Use return null as default in validate_file_to_edit() Replace the default wp_die() with return null to preserve the existing runtime behavior for validate_file() code 2 (absolute Windows drive paths). This gives westonruter the option to revert to the wp_die() approach if preferred. --- src/wp-admin/includes/file.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php index 16f819ca97d2a..b07ce6c4ae84f 100644 --- a/src/wp-admin/includes/file.php +++ b/src/wp-admin/includes/file.php @@ -734,7 +734,7 @@ function wp_tempnam( $filename = '', $dir = '' ) { * @param string $file File the user is attempting to edit. * @param string[] $allowed_files Optional. Array of allowed files to edit. * `$file` must match an entry exactly. - * @return string|never Returns the file name on success, dies on failure. + * @return string|null|never Returns the file name on success, null in case of absolute Windows drive paths, and dies on failure. */ function validate_file_to_edit( $file, $allowed_files = array() ) { $code = validate_file( $file, $allowed_files ); @@ -751,9 +751,9 @@ function validate_file_to_edit( $file, $allowed_files = array() ) { // wp_die( __('Sorry, cannot call files with their real path.' )); case 3: - default: wp_die( __( 'Sorry, that file cannot be edited.' ) ); } + return null; } /**