[wp-trac] [WordPress Trac] #60618: REST API: Meta update fails if unrelated unchanged field is a multi-item array

WordPress Trac noreply at wordpress.org
Fri Feb 23 09:32:02 UTC 2024


#60618: REST API: Meta update fails if unrelated unchanged field is a multi-item
array
--------------------------+-----------------------------
 Reporter:  kadamwhite    |      Owner:  (none)
     Type:  defect (bug)  |     Status:  new
 Priority:  normal        |  Milestone:  Awaiting Review
Component:  REST API      |    Version:  trunk
 Severity:  normal        |   Keywords:
  Focuses:  rest-api      |
--------------------------+-----------------------------
 In some plugins there may be code which repeatedly calls `add_post_meta`
 without registration, e.g. calling


 {{{#!php
 <?php
 add_post_meta( 1, 'example_meta_key', 'A' );
 add_post_meta( 1, 'example_meta_key', 'A' );
 add_post_meta( 1, 'example_meta_key', 'A' );
 }}}

 In the case where this bug was observed, the meta value was always
 retrieved as `single`, but the `add_post_meta()` call never utilized the
 `unique` flag. This results in multiple rows in the database for meta_key
 `example_meta_key` and meta_value `A`, for the post `1`.

 If the plugin later ''adds'' meta registration for this field, and both

 - registers the post meta field as `'single' => true`
 - exposes the post meta field as `'show_in_rest' => true`

 then subsequent saves to this post through the REST API will fail.

 The reason is that the REST API iterates through post meta that is passed
 back in the REST post, and checks whether the incoming value is the same
 as the stored value using this check in
 `WP_REST_Meta_Fields::update_meta_value`:

 {{{#!php
 <?php
 if ( is_array( $old_value ) && 1 === count( $old_value )
         && $this->is_meta_value_same_as_stored_value( $meta_key, $subtype,
 $old_value[0], $value )
 ) {
         return true;
 }
 }}}
 In our case the `$old_value` will be an array, but the count will be 3, so
 we never opt in to our similar-data check.

 This means that the incoming value will be passed through and will call
 `update_meta`, which will return `false` because update_meta returns
 `false` "on failure **or if the value passed to the function is the same**
 as the one that is already in the database." (emphasis added)

 If a ''new'' value is passed for the existing meta, all rows will be
 updated as expected. It is only unchanged values which fail the
 comparison.

 Summary: Our logic in our update meta function is problematic, and doesn't
 handle existing arrays of metadata properly when checking for an identical
 existing value.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/60618>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list