Commit 1bf4589124 for wordpress.org

commit 1bf45891246a5bd051fc459bad1cfda0624abeb0
Author: westonruter <westonruter@git.wordpress.org>
Date:   Mon Sep 14 20:23:50 2026 +0000

    Code Quality: Improve typing for the metadata getters.

    Annotate `get_metadata()`, `get_metadata_raw()`, `get_metadata_default()`, the five per-object wrappers, and the post custom field getters with `@phpstan-return` conditional types, so that static analysis resolves what a call returns instead of falling back to `mixed`.

    Each condition tests the meta key before `$single`, matching the runtime behavior that `$single` has no effect when no key is given. In that case the return value is the object cache exactly as `update_meta_cache()` built it, so each key holds a list of raw strings. Those keys are typed `array-key` rather than `string`, since PHP casts a meta key which is a numeric string to an integer.

    A single value is typed `mixed`. A default registered through `register_meta()` is validated against the schema `type` and then returned unchanged, so an integer, float or boolean reaches the caller with no plugin involved, and a narrower type would invite the conclusion that a scalar metadata value must be a string. `get_metadata_raw()` is the exception and keeps the narrower type, since it returns before any default is consulted and every value it produces has been through the `meta_value` column.

    The accompanying documentation is corrected to describe registered defaults, and `get_post_custom()` now returns early when there is no current post instead of passing `false` on to a lookup that cannot succeed.

    Developed in https://github.com/WordPress/wordpress-develop/pull/13519.
    Follow-up to r52795, r61718, r62178.

    See #65817, #65860.

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


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

diff --git a/wp-includes/comment.php b/wp-includes/comment.php
index 817ad17fa9..8293c8b750 100644
--- a/wp-includes/comment.php
+++ b/wp-includes/comment.php
@@ -576,7 +576,19 @@ function delete_comment_meta( $comment_id, $meta_key, $meta_value = '' ) {
  *               - true values are returned as '1'
  *               - numbers are returned as strings
  *               Arrays and objects retain their original type.
+ *               These conversions apply to stored values. A default value registered
+ *               with {@see register_meta()} is never stored, so it is returned with
+ *               the type it was registered with, which may be an integer, float, or
+ *               boolean.
+ *
  * @phpstan-param int|numeric-string $comment_id
+ * @phpstan-return (
+ *     $key is ''|'0'
+ *         ? array<array-key, list<string>>|false
+ *         : ( $single is true
+ *             ? mixed
+ *             : list<mixed>|false )
+ * )
  */
 function get_comment_meta( $comment_id, $key = '', $single = false ) {
 	return get_metadata( 'comment', $comment_id, $key, $single );
diff --git a/wp-includes/meta.php b/wp-includes/meta.php
index 7bce5f40c0..62d28cdbd9 100644
--- a/wp-includes/meta.php
+++ b/wp-includes/meta.php
@@ -592,11 +592,28 @@ function delete_metadata( $meta_type, $object_id, $meta_key, $meta_value = '', $
  *               or if `$meta_type` is not specified.
  *               An empty array if a valid but non-existing object ID is passed and `$single` is false.
  *               An empty string if a valid but non-existing object ID is passed and `$single` is true.
+ *               The same empty array or empty string if `$meta_type` has no metadata table, in which
+ *               case there is no cache to return even when `$meta_key` is not specified.
  *               Note: Non-serialized values are returned as strings:
  *               - false values are returned as empty strings ('')
  *               - true values are returned as '1'
  *               - numbers (both integer and float) are returned as strings
  *               Arrays and objects retain their original type.
+ *               These conversions apply to stored values. A default value registered
+ *               with {@see register_meta()} is never stored, so it is returned with
+ *               the type it was registered with, which may be an integer, float, or
+ *               boolean.
+ *
+ * @phpstan-param int|numeric-string $object_id
+ * @phpstan-return (
+ *     $meta_key is ''|'0'
+ *         ? ( $single is true
+ *             ? array<array-key, list<string>>|string|false
+ *             : array<array-key, list<string>>|false )
+ *         : ( $single is true
+ *             ? mixed
+ *             : list<mixed>|false )
+ * )
  */
 function get_metadata( $meta_type, $object_id, $meta_key = '', $single = false ) {
 	$value = get_metadata_raw( $meta_type, $object_id, $meta_key, $single );
@@ -624,6 +641,21 @@ function get_metadata( $meta_type, $object_id, $meta_key = '', $single = false )
  *               False for an invalid `$object_id` (non-numeric, zero, or negative value),
  *               or if `$meta_type` is not specified.
  *               Null if the value does not exist.
+ *               Only stored values are returned. Unlike {@see get_metadata()}, a default
+ *               registered with {@see register_meta()} is never consulted, so a value is
+ *               always a string unless it was stored serialized, in which case the array
+ *               or object retains its original type.
+ *               When `$meta_key` is not specified, the values are returned exactly as
+ *               they are held in the object cache, which means they are still serialized.
+ *
+ * @phpstan-param int|numeric-string $object_id
+ * @phpstan-return (
+ *     $meta_key is ''|'0'
+ *         ? array<array-key, list<string>>|false|null
+ *         : ( $single is true
+ *             ? string|array<mixed>|object|false|null
+ *             : list<string|array<mixed>|object>|false|null )
+ * )
  */
 function get_metadata_raw( $meta_type, $object_id, $meta_key = '', $single = false ) {
 	if ( ! $meta_type || ! is_numeric( $object_id ) ) {
@@ -708,6 +740,9 @@ function get_metadata_raw( $meta_type, $object_id, $meta_key = '', $single = fal
  *                          This parameter has no effect if `$meta_key` is not specified. Default false.
  * @return mixed An array of default values if `$single` is false.
  *               The default value of the meta field if `$single` is true.
+ *
+ * @phpstan-param int|numeric-string $object_id
+ * @phpstan-return ( $single is true ? mixed : list<mixed> )
  */
 function get_metadata_default( $meta_type, $object_id, $meta_key, $single = false ) {
 	if ( $single ) {
diff --git a/wp-includes/ms-site.php b/wp-includes/ms-site.php
index 65f5259fe1..8540b27621 100644
--- a/wp-includes/ms-site.php
+++ b/wp-includes/ms-site.php
@@ -1086,6 +1086,18 @@ function delete_site_meta( $site_id, $meta_key, $meta_value = '' ) {
  *               - true values are returned as '1'
  *               - numbers (both integer and float) are returned as strings
  *               Arrays and objects retain their original type.
+ *               These conversions apply to stored values. A default value registered
+ *               with {@see register_meta()} is never stored, so it is returned with
+ *               the type it was registered with, which may be an integer, float, or
+ *               boolean.
+ *
+ * @phpstan-return (
+ *     $key is ''|'0'
+ *         ? array<array-key, list<string>>|false
+ *         : ( $single is true
+ *             ? mixed
+ *             : list<mixed>|false )
+ * )
  */
 function get_site_meta( $site_id, $key = '', $single = false ) {
 	return get_metadata( 'blog', $site_id, $key, $single );
diff --git a/wp-includes/post-template.php b/wp-includes/post-template.php
index 86ea3eca58..b817653aaf 100644
--- a/wp-includes/post-template.php
+++ b/wp-includes/post-template.php
@@ -1110,8 +1110,11 @@ function _wp_link_page( $i ) {
  * @since 1.5.0
  *
  * @param string $key Meta data key name.
- * @return array|string|false Array of values, or single value if only one element exists.
- *                            False if the key does not exist.
+ * @return string[]|string|false Array of values, or single value if only one element exists.
+ *                               False if the key does not exist.
+ *                               Values are always strings, as described for {@see get_post_custom()}.
+ *
+ * @phpstan-return list<string>|string|false
  */
 function post_custom( $key = '' ) {
 	$custom = get_post_custom();
diff --git a/wp-includes/post.php b/wp-includes/post.php
index aeea4e5baf..89ab25ab93 100644
--- a/wp-includes/post.php
+++ b/wp-includes/post.php
@@ -2770,6 +2770,18 @@ function delete_post_meta( $post_id, $meta_key, $meta_value = '' ) {
  *               - true values are returned as '1'
  *               - numbers (both integer and float) are returned as strings
  *               Arrays and objects retain their original type.
+ *               These conversions apply to stored values. A default value registered
+ *               with {@see register_meta()} is never stored, so it is returned with
+ *               the type it was registered with, which may be an integer, float, or
+ *               boolean.
+ *
+ * @phpstan-return (
+ *     $key is ''|'0'
+ *         ? array<array-key, list<string>>|false
+ *         : ( $single is true
+ *             ? mixed
+ *             : list<mixed>|false )
+ * )
  */
 function get_post_meta( $post_id, $key = '', $single = false ) {
 	return get_metadata( 'post', $post_id, $key, $single );
@@ -2863,17 +2875,23 @@ function unregister_post_meta( $post_type, $meta_key ) {
  * @since 1.2.0
  *
  * @param int $post_id Optional. Post ID. Default is the ID of the global `$post`.
- * @return array<string, array<int, string>>|false Array of post meta values keyed by meta key, or false on failure.
- *                                                 Post meta values will always be strings, even for values which would
- *                                                 otherwise be retrieved individually as arrays or objects via
- *                                                 {@see get_post_meta()}. An empty array is returned if the post has
- *                                                 no post meta.
+ * @return array<string|int, array<int, string>>|false Array of post meta values keyed by meta key, or false on failure.
+ *                                                     Post meta values will always be strings, even for values which
+ *                                                     would otherwise be retrieved individually as arrays or objects
+ *                                                     via {@see get_post_meta()}. A meta key which is a numeric string
+ *                                                     is keyed by the equivalent integer, as PHP casts such array keys.
+ *                                                     An empty array is returned if the post has no post meta.
+ *
+ * @phpstan-return array<array-key, list<string>>|false
  */
 function get_post_custom( $post_id = 0 ) {
 	$post_id = absint( $post_id );

 	if ( ! $post_id ) {
 		$post_id = get_the_ID();
+		if ( false === $post_id ) {
+			return false;
+		}
 	}

 	return get_post_meta( $post_id );
@@ -2887,7 +2905,11 @@ function get_post_custom( $post_id = 0 ) {
  * @since 1.2.0
  *
  * @param int $post_id Optional. Post ID. Default is the ID of the global `$post`.
- * @return array|null Array of the keys, if retrieved.
+ * @return array<string|int>|null Array of the meta field keys, if retrieved. Null if the post has no
+ *                                post meta, or if the post meta could not be retrieved. A key which is
+ *                                a numeric string is returned as the equivalent integer.
+ *
+ * @phpstan-return non-empty-list<array-key>|null
  */
 function get_post_custom_keys( $post_id = 0 ) {
 	$custom = get_post_custom( $post_id );
@@ -2913,7 +2935,11 @@ function get_post_custom_keys( $post_id = 0 ) {
  *
  * @param string $key     Optional. Meta field key. Default empty.
  * @param int    $post_id Optional. Post ID. Default is the ID of the global `$post`.
- * @return array|null Meta field values.
+ * @return string[]|null Meta field values. Null if `$key` is not specified, if the post has no
+ *                       meta for that key, or if the post meta could not be retrieved.
+ *                       Values are always strings, as described for {@see get_post_custom()}.
+ *
+ * @phpstan-return ( $key is ''|'0' ? null : list<string>|null )
  */
 function get_post_custom_values( $key = '', $post_id = 0 ) {
 	if ( ! $key ) {
diff --git a/wp-includes/taxonomy.php b/wp-includes/taxonomy.php
index 6dbc336395..56f12f7013 100644
--- a/wp-includes/taxonomy.php
+++ b/wp-includes/taxonomy.php
@@ -1473,6 +1473,18 @@ function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
  *               - true values are returned as '1'
  *               - numbers are returned as strings
  *               Arrays and objects retain their original type.
+ *               These conversions apply to stored values. A default value registered
+ *               with {@see register_meta()} is never stored, so it is returned with
+ *               the type it was registered with, which may be an integer, float, or
+ *               boolean.
+ *
+ * @phpstan-return (
+ *     $key is ''|'0'
+ *         ? array<array-key, list<string>>|false
+ *         : ( $single is true
+ *             ? mixed
+ *             : list<mixed>|false )
+ * )
  */
 function get_term_meta( $term_id, $key = '', $single = false ) {
 	return get_metadata( 'term', $term_id, $key, $single );
diff --git a/wp-includes/user.php b/wp-includes/user.php
index 6ce8dbf051..a13b3f75c0 100644
--- a/wp-includes/user.php
+++ b/wp-includes/user.php
@@ -1298,6 +1298,18 @@ function delete_user_meta( $user_id, $meta_key, $meta_value = '' ) {
  *               - true values are returned as '1'
  *               - numbers (both integer and float) are returned as strings
  *               Arrays and objects retain their original type.
+ *               These conversions apply to stored values. A default value registered
+ *               with {@see register_meta()} is never stored, so it is returned with
+ *               the type it was registered with, which may be an integer, float, or
+ *               boolean.
+ *
+ * @phpstan-return (
+ *     $key is ''|'0'
+ *         ? array<array-key, list<string>>|false
+ *         : ( $single is true
+ *             ? mixed
+ *             : list<mixed>|false )
+ * )
  */
 function get_user_meta( $user_id, $key = '', $single = false ) {
 	return get_metadata( 'user', $user_id, $key, $single );
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 022c0ecbc0..0a3a6358af 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '7.2-alpha-63617';
+$wp_version = '7.2-alpha-63618';

 /**
  * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.