Commit cfdab1a6ba for wordpress.org

commit cfdab1a6ba05cd035fb23049ccbe7fa7b9ef2643
Author: westonruter <westonruter@git.wordpress.org>
Date:   Fri Sep 18 03:48:48 2026 +0000

    Code Quality: Type the object ID for metadata deletion.

    Three of the eight `delete_metadata()` calls in core passed `null` for `$object_id`, all of them the `$delete_all = true` case where the value no longer selects the rows to delete. The other five already wrote `0`. Nothing observed the difference, because `absint()` normalizes the argument on the statement after the guard, so the `delete_{$meta_type}_metadata` filter and the `delete_{$meta_type}_meta` and `deleted_{$meta_type}_meta` actions have always received `0` whichever spelling was used.

    The parameter is now annotated `non-negative-int`, which rejects a negative ID that `absint()` would otherwise turn positive and apply to a different object. A `numeric-string` branch is deliberately not added, since it would readmit `'-5'` through the same hole while `-5` stayed rejected. The five per-object wrappers and the two `WP_REST_Meta_Fields` methods that call the function directly are annotated `positive-int` instead, because none of them passes `$delete_all`, so an object ID of `0` always returns `false` there.

    The documentation for `$object_id` now describes the `$delete_all` case where a reader looks for it, rather than only on `$delete_all` itself, and the PHPStan baselines are regenerated for the entries this resolves.

    Developed in https://github.com/WordPress/wordpress-develop/pull/13577.
    Follow-up to r63024, r63618.

    Props soean, westonruter, mukesh27.
    See #65817, #65860.

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


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

diff --git a/wp-includes/comment.php b/wp-includes/comment.php
index 8293c8b750..03511ee4db 100644
--- a/wp-includes/comment.php
+++ b/wp-includes/comment.php
@@ -548,6 +548,8 @@ function add_comment_meta( $comment_id, $meta_key, $meta_value, $unique = false
  *                           rows will only be removed that match the value.
  *                           Must be serializable if non-scalar. Default empty string.
  * @return bool True on success, false on failure.
+ *
+ * @phpstan-param positive-int $comment_id
  */
 function delete_comment_meta( $comment_id, $meta_key, $meta_value = '' ) {
 	return delete_metadata( 'comment', $comment_id, $meta_key, $meta_value );
diff --git a/wp-includes/meta.php b/wp-includes/meta.php
index 62d28cdbd9..dd28b02721 100644
--- a/wp-includes/meta.php
+++ b/wp-includes/meta.php
@@ -382,7 +382,9 @@ function update_metadata( $meta_type, $object_id, $meta_key, $meta_value, $prev_
  *
  * @param string $meta_type  Type of object metadata is for. Accepts 'blog', 'post', 'comment', 'term',
  *                           'user', or any other object type with an associated meta table.
- * @param int    $object_id  ID of the object metadata is for.
+ * @param int    $object_id  ID of the object metadata is for. Pass 0 when `$delete_all` is true.
+ *                           The value no longer selects the rows to delete, but is still passed
+ *                           on to the hooks fired below.
  * @param string $meta_key   Metadata key.
  * @param mixed  $meta_value Optional. Metadata value. Must be serializable if non-scalar.
  *                           If specified, only delete metadata entries with this value.
@@ -395,6 +397,8 @@ function update_metadata( $meta_type, $object_id, $meta_key, $meta_value, $prev_
  *                           ignoring the specified object_id. Otherwise, only delete
  *                           matching metadata entries for the specified object_id. Default false.
  * @return bool True on successful delete, false on failure.
+ *
+ * @phpstan-param non-negative-int $object_id
  */
 function delete_metadata( $meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false ) {
 	global $wpdb;
diff --git a/wp-includes/ms-site.php b/wp-includes/ms-site.php
index 8540b27621..f18189c30d 100644
--- a/wp-includes/ms-site.php
+++ b/wp-includes/ms-site.php
@@ -1060,6 +1060,8 @@ function add_site_meta( $site_id, $meta_key, $meta_value, $unique = false ) {
  *                           rows will only be removed that match the value.
  *                           Must be serializable if non-scalar. Default empty.
  * @return bool True on success, false on failure.
+ *
+ * @phpstan-param positive-int $site_id
  */
 function delete_site_meta( $site_id, $meta_key, $meta_value = '' ) {
 	return delete_metadata( 'blog', $site_id, $meta_key, $meta_value );
@@ -1138,7 +1140,7 @@ function update_site_meta( $site_id, $meta_key, $meta_value, $prev_value = '' )
  * @return bool Whether the site meta key was deleted from the database.
  */
 function delete_site_meta_by_key( $meta_key ) {
-	return delete_metadata( 'blog', null, $meta_key, '', true );
+	return delete_metadata( 'blog', 0, $meta_key, '', true );
 }

 /**
diff --git a/wp-includes/post.php b/wp-includes/post.php
index 89ab25ab93..d36a44bde2 100644
--- a/wp-includes/post.php
+++ b/wp-includes/post.php
@@ -2738,6 +2738,8 @@ function add_post_meta( $post_id, $meta_key, $meta_value, $unique = false ) {
  *                           rows will only be removed that match the value.
  *                           Must be serializable if non-scalar. Default empty.
  * @return bool True on success, false on failure.
+ *
+ * @phpstan-param positive-int $post_id
  */
 function delete_post_meta( $post_id, $meta_key, $meta_value = '' ) {
 	// Make sure meta is deleted from the post, not from a revision.
@@ -2830,7 +2832,7 @@ function update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' )
  * @return bool Whether the post meta key was deleted from the database.
  */
 function delete_post_meta_by_key( $post_meta_key ) {
-	return delete_metadata( 'post', null, $post_meta_key, '', true );
+	return delete_metadata( 'post', 0, $post_meta_key, '', true );
 }

 /**
@@ -6975,7 +6977,7 @@ function wp_delete_attachment( $post_id, $force_delete = false ) {
 	wp_delete_object_term_relationships( $post_id, get_object_taxonomies( $post->post_type ) );

 	// Delete all for any posts.
-	delete_metadata( 'post', null, '_thumbnail_id', $post_id, true );
+	delete_metadata( 'post', 0, '_thumbnail_id', $post_id, true );

 	wp_defer_comment_counting( true );

diff --git a/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php b/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php
index a9c3fbcde8..71be09ec42 100644
--- a/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php
+++ b/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php
@@ -228,6 +228,8 @@ abstract class WP_REST_Meta_Fields {
 	 * @param string $meta_key  Key for the field.
 	 * @param string $name      Name for the field that is exposed in the REST API.
 	 * @return true|WP_Error True if meta field is deleted, WP_Error otherwise.
+	 *
+	 * @phpstan-param positive-int $object_id
 	 */
 	protected function delete_meta_value( $object_id, $meta_key, $name ) {
 		$meta_type = $this->get_meta_type();
@@ -275,6 +277,8 @@ abstract class WP_REST_Meta_Fields {
 	 * @param string $name      Name for the field that is exposed in the REST API.
 	 * @param array  $values    List of values to update to.
 	 * @return true|WP_Error True if meta fields are updated, WP_Error otherwise.
+	 *
+	 * @phpstan-param positive-int $object_id
 	 */
 	protected function update_multi_meta_value( $object_id, $meta_key, $name, $values ) {
 		$meta_type = $this->get_meta_type();
diff --git a/wp-includes/taxonomy.php b/wp-includes/taxonomy.php
index 56f12f7013..d13a11e655 100644
--- a/wp-includes/taxonomy.php
+++ b/wp-includes/taxonomy.php
@@ -1447,6 +1447,8 @@ function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
  *                           rows will only be removed that match the value.
  *                           Must be serializable if non-scalar. Default empty.
  * @return bool True on success, false on failure.
+ *
+ * @phpstan-param positive-int $term_id
  */
 function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
 	return delete_metadata( 'term', $term_id, $meta_key, $meta_value );
diff --git a/wp-includes/user.php b/wp-includes/user.php
index a13b3f75c0..b4ab594038 100644
--- a/wp-includes/user.php
+++ b/wp-includes/user.php
@@ -1270,6 +1270,8 @@ function add_user_meta( $user_id, $meta_key, $meta_value, $unique = false ) {
  *                           rows will only be removed that match the value.
  *                           Must be serializable if non-scalar. Default empty.
  * @return bool True on success, false on failure.
+ *
+ * @phpstan-param positive-int $user_id
  */
 function delete_user_meta( $user_id, $meta_key, $meta_value = '' ) {
 	return delete_metadata( 'user', $user_id, $meta_key, $meta_value );
diff --git a/wp-includes/version.php b/wp-includes/version.php
index 1eb0d326fe..0667deeb82 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
  *
  * @global string $wp_version
  */
-$wp_version = '7.2-alpha-63757';
+$wp_version = '7.2-alpha-63758';

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