[wp-trac] [WordPress Trac] #55600: Can't save registered post meta field of type string that equals registered default value via REST API

WordPress Trac noreply at wordpress.org
Thu Apr 21 13:47:24 UTC 2022

#55600: Can't save registered post meta field of type string that equals registered
default value via REST API
 Reporter:  kraftner            |      Owner:  (none)
     Type:  defect (bug)        |     Status:  new
 Priority:  normal              |  Milestone:  Awaiting Review
Component:  Options, Meta APIs  |    Version:
 Severity:  normal              |   Keywords:
  Focuses:  rest-api            |
 == Current behaviour

 Currently if you register a post meta key as string and set a default

     'show_in_rest' => true,
     'single' => true,
     'type' => 'string',
     'default' => 'foo'

 and then save the default value it is not actually being written to the

 If you save any other type, e.g. a boolean

     'show_in_rest' => true,
     'single' => true,
     'type' => 'boolean',
     'default' => true

 it is being written to the database.

 Also not saving via the REST API, but via `update_metadata()` works for

 == What seems to happen

 The problem seems to happen like this:

 - Post meta is only saved if it differs from the currently stored value.
 - So before saving each field the new value is compared with the stored
 - When doing so the assumption is (rightfully) that all stored data is a
 string since that is how post meta is stored in the DB.
 - If the key doesn't exist though, the comparison happens with the default
 - The default value though isn't necessarily a string, but is handled as
 such in the strict equality check.
 - So the strict equality check fails on anything but a string field.

 **-> String fields can't save the default value, anything else can.**

 == How did it come to this?

 I am not absolutely sure what is actually the intended behavior, but I
 assume if there is nothing stored in the DB the value should be saved,
 even if it equals the default.

 I assume this because the behavior of `update_metadata()`
 [https://core.trac.wordpress.org/changeset/48402 got changed] to only
 consider DB data, not default values for the comparison by retrieving the
 stored data using `get_metadata_raw()` instead of `get_metadata()`.

 `WP_REST_Meta_Fields` duplicates some of the checks in `update_metadata()`
 /rest-api/fields/class-wp-rest-meta-fields.php#L382 even explicitly states
 that in a comment]) but `WP_REST_Meta_Fields::update_meta_value()` (and
 some other places in that class) didn't get the change to use
 `get_metadata_raw()` instead of `get_metadata()`.

 I assume this got overlooked when introducing the default metadata values
 in https://core.trac.wordpress.org/changeset/48402

 It seems that replacing get_metadata with get_metadata_raw in that class
 should fix the issue, but I haven't found time yet to prepare a patch, so
 I thought I'd at least document the issue for now to see if someone else
 finds time for a fix before me.

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

More information about the wp-trac mailing list