From eb73e622ddd1f08adce1996293dd295838d2c43d Mon Sep 17 00:00:00 2001 From: Ryan McCue Date: Thu, 6 Oct 2016 17:49:45 -0400 Subject: [PATCH] Handle multiple duplicate values correctly --- lib/fields/class-wp-rest-meta-fields.php | 31 +++++++++++++++++++----- tests/test-rest-post-meta-fields.php | 28 +++++++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/lib/fields/class-wp-rest-meta-fields.php b/lib/fields/class-wp-rest-meta-fields.php index eabf5bef70..ab674a42e3 100644 --- a/lib/fields/class-wp-rest-meta-fields.php +++ b/lib/fields/class-wp-rest-meta-fields.php @@ -162,11 +162,30 @@ protected function update_multi_meta_value( $object, $name, $values ) { } $current = get_metadata( $this->get_meta_type(), $object, $name, false ); - $to_add = array_diff( $values, $current ); - $to_remove = array_diff( $current, $values ); - foreach ( $to_add as $value ) { - if ( ! add_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { + $to_remove = $current; + $to_add = $values; + foreach ( $to_add as $add_key => $value ) { + $remove_keys = array_keys( $to_remove, $value, true ); + if ( empty( $remove_keys ) ) { + continue; + } + + if ( count( $remove_keys ) > 1 ) { + // To remove, we need to remove first, then add, so don't touch. + continue; + } + + $remove_key = $remove_keys[0]; + unset( $to_remove[ $remove_key ] ); + unset( $to_add[ $add_key ] ); + } + + // `delete_metadata` removes _all_ instances of the value, so only call + // once. + $to_remove = array_unique( $to_remove ); + foreach ( $to_remove as $value ) { + if ( ! delete_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { return new WP_Error( 'rest_meta_database_error', __( 'Could not update meta value in database.' ), @@ -174,8 +193,8 @@ protected function update_multi_meta_value( $object, $name, $values ) { ); } } - foreach ( $to_remove as $value ) { - if ( ! delete_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { + foreach ( $to_add as $value ) { + if ( ! add_metadata( $this->get_meta_type(), $object, wp_slash( $name ), wp_slash( $value ) ) ) { return new WP_Error( 'rest_meta_database_error', __( 'Could not update meta value in database.' ), diff --git a/tests/test-rest-post-meta-fields.php b/tests/test-rest-post-meta-fields.php index 9de32dfb0f..b4c3472914 100644 --- a/tests/test-rest-post-meta-fields.php +++ b/tests/test-rest-post-meta-fields.php @@ -340,6 +340,34 @@ public function test_set_value_multiple() { $this->assertContains( 'val2', $meta ); } + /** + * Test removing only one item with duplicate items. + */ + public function test_set_value_remove_one() { + add_post_meta( $this->post_id, 'test_multi', 'c' ); + add_post_meta( $this->post_id, 'test_multi', 'n' ); + add_post_meta( $this->post_id, 'test_multi', 'n' ); + + $this->grant_write_permission(); + + $data = array( + 'meta' => array( + 'test_multi' => array( 'c', 'n' ), + ), + ); + $request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', $this->post_id ) ); + $request->set_body_params( $data ); + + $response = $this->server->dispatch( $request ); + $this->assertEquals( 200, $response->get_status() ); + + $meta = get_post_meta( $this->post_id, 'test_multi', false ); + $this->assertNotEmpty( $meta ); + $this->assertCount( 2, $meta ); + $this->assertContains( 'c', $meta ); + $this->assertContains( 'n', $meta ); + } + /** * @depends test_set_value_multiple */