Make WordPress Core

Opened 4 years ago

Closed 4 years ago

#52787 closed defect (bug) (fixed)

Empty array for non-single post meta breaks post save through REST API

Reported by: brechtvds's profile BrechtVds Owned by: peterwilsoncc's profile peterwilsoncc
Milestone: 5.7.1 Priority: high
Severity: major Version: 5.7
Component: REST API Keywords: good-first-bug has-patch has-unit-tests commit fixed-major dev-reviewed
Focuses: rest-api Cc:

Description

The change in #50790 causes an "Updating failed. Could not delete meta value from database." error when saving post meta in Gutenberg.

The reason seems to be that Gutenberg uses default values for any post meta that has been registered for the REST API. For non-single meta that's an empty array. Now when someone makes a meta change and tries to save it in Gutenberg, that empty array gets passed along. Because of the change, the WP_REST_Meta_Fields::update_value() sees an empty array and wants to delete that non-existing meta, causing the error.

Can be replicated by adding this sample plugin file:

<?php
/*
Plugin Name: Test Bug Plugin
Description: Testing bug.
Version: 1.0
License: GPLv2 or later
*/

function test_bug_plugin_register_meta() {
    register_meta( 'post', 'example-post-meta-field', array(
		'show_in_rest' => true,
		'single' => false, // Is the default value. Single = true doesn't cause the problem.
	) );
}
add_action( 'init', 'test_bug_plugin_register_meta');

Then use a simple plugin like https://wordpress.org/plugins/conditionally-display-featured-image-on-singular-pages/ which adds a checkbox in the "Featured Image" section when creating a post, which gets saved as post meta.

This video shows the error message: https://www.loom.com/share/025fe7b6f2f44955b303daf3317f88d0

Wasn't sure if this should be logged as a Gutenberg or core bug. But Gutenberg defaulting to an empty array for non-single meta seems logical to me, so I feel like this should get fixed in the REST API.

First Trac ticket. Let me know if I need to add/change anything!

Attachments (2)

52787.diff (1.6 KB) - added by goaroundagain 4 years ago.
52787.2.diff (2.2 KB) - added by peterwilsoncc 4 years ago.

Download all attachments as: .zip

Change History (16)

#1 @BrechtVds
4 years ago

Forgot to include the exact error message the REST API returns when trying to save:

{"code":"rest_meta_database_error","message":"Could not delete meta value from database.","data":{"key":"example-post-meta-field","status":500}}

#2 @TimothyBlynJacobs
4 years ago

  • Keywords needs-patch good-first-bug added
  • Milestone changed from Awaiting Review to 5.7.1

Thanks for the report @BrechtVds and welcome to trac!

Yeah, this is definitely something to be fixed on the REST API side. Gutenberg isn't doing anything special to cause this behavior. The issue is that delete_metadata errors if there is nothing to delete.

I think we should probably add a safe guard in \WP_REST_Meta_Fields::delete_meta_value to check that get_metadata_raw returns at least one value. If it doesn't, IMO, we should return true and treat it as a no-op the same way we do for updating metadata to an identical value.

#3 @TimothyBlynJacobs
4 years ago

#52793 was marked as a duplicate.

#4 @TimothyBlynJacobs
4 years ago

  • Priority changed from normal to high
  • Severity changed from normal to major

#5 @goaroundagain
4 years ago

I've updated the unit test in my (duplicate) ticket to reproduce the issue. Maybe it can help https://core.trac.wordpress.org/attachment/ticket/52793/52793.diff

#6 @TimothyBlynJacobs
4 years ago

Thanks for the test @goaroundagain! Could you separate it out into a different test case? Something like test_delete_does_not_trigger_error_if_no_meta_values?

@BrechtVds, @goaroundagain Would either of you be interested in working on a patch for this issue?

#7 @BrechtVds
4 years ago

A bit strapped for time and I'd have to educate myself about the process and best practices first. I will follow along to see how it's supposed to be handled and hopefully have some more time to contribute to core in the future.

#8 @goaroundagain
4 years ago

  • Keywords has-patch has-unit-tests added; needs-patch removed

I patched the error by checking in \WP_REST_Meta_Fields::delete_meta_value if get_metadata_raw is null and then return true

@goaroundagain
4 years ago

#9 @peterwilsoncc
4 years ago

This looks good to me, tests well locally too.

In 52787.2.diff:

  • No functional change to 52787.diff
  • Added a duplicate test for deleting non-existent data with null as well as when using an empty array

#10 @peterwilsoncc
4 years ago

  • Keywords commit added

#11 @peterwilsoncc
4 years ago

  • Owner set to peterwilsoncc
  • Resolution set to fixed
  • Status changed from new to closed

In 50567:

REST API: Prevent database error when deleting meta data.

Add a check to WP_REST_Meta_Fields::delete_meta_value() ensuring meta data is set before attempting to delete it from the database. If the data does not exist, the delete is considered successful as the data matches the desired state.

Props BrechtVds, goaroundagain, TimothyBlynJacobs.
Fixes #52787.

#12 @peterwilsoncc
4 years ago

  • Keywords fixed-major dev-feedback added
  • Resolution fixed deleted
  • Status changed from closed to reopened

Reopening for commit to the 5.7 branch following second a committer's sign-off.

#13 @TimothyBlynJacobs
4 years ago

  • Keywords dev-reviewed added; dev-feedback removed

Patch looks great to me.

#14 @peterwilsoncc
4 years ago

  • Resolution set to fixed
  • Status changed from reopened to closed

In 50573:

REST API: Prevent database error when deleting meta data.

Add a check to WP_REST_Meta_Fields::delete_meta_value() ensuring meta data is set before attempting to delete it from the database. If the data does not exist, the delete is considered successful as the data matches the desired state.

Props BrechtVds, goaroundagain, TimothyBlynJacobs.
Merges [50567] to the 5.7 branch.
Fixes #52787.

Note: See TracTickets for help on using tickets.