From e5e467a41bbfc2bb0741ca3e96894e89515cb2f9 Mon Sep 17 00:00:00 2001 From: Boone Gorges Date: Fri, 1 May 2015 16:37:35 +0000 Subject: [PATCH] Allow metadata to be deleted when meta_value matches 0 or '0'. In `delete_metadata()`, be stricter about when to ignore a falsey value of `$meta_value`. For backward compatibility, an empty string for `$meta_value` is equivalent to `null` or `false`. Props sc0ttkclark. Fixes #32224. git-svn-id: https://develop.svn.wordpress.org/trunk@32331 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/meta.php | 21 ++-- tests/phpunit/tests/meta/deleteMetadata.php | 100 ++++++++++++++++++++ 2 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 tests/phpunit/tests/meta/deleteMetadata.php diff --git a/src/wp-includes/meta.php b/src/wp-includes/meta.php index b57e761f46..bcfc847e80 100644 --- a/src/wp-includes/meta.php +++ b/src/wp-includes/meta.php @@ -294,14 +294,17 @@ function update_metadata($meta_type, $object_id, $meta_key, $meta_value, $prev_v * * @global wpdb $wpdb WordPress database abstraction object. * - * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) - * @param int $object_id ID of the object metadata is for - * @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. Otherwise, delete all entries with the specified meta_key. - * @param bool $delete_all Optional, default is false. If true, delete matching metadata entries - * for all objects, ignoring the specified object_id. Otherwise, only delete matching - * metadata entries for the specified object_id. + * @param string $meta_type Type of object metadata is for (e.g., comment, post, or user) + * @param int $object_id ID of the object metadata is for + * @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. Otherwise, delete all entries with the specified meta_key. + * Pass `null, `false`, or an empty string to skip this check. (For backward compatibility, + * it is not possible to pass an empty string to delete those entries with an empty string + * for a value.) + * @param bool $delete_all Optional, default is false. If true, delete matching metadata entries for all objects, + * ignoring the specified object_id. Otherwise, only delete matching metadata entries for + * the specified object_id. * @return bool True on successful delete, false on failure. */ function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $delete_all = false) { @@ -356,7 +359,7 @@ function delete_metadata($meta_type, $object_id, $meta_key, $meta_value = '', $d if ( !$delete_all ) $query .= $wpdb->prepare(" AND $type_column = %d", $object_id ); - if ( $meta_value ) + if ( '' !== $meta_value && null !== $meta_value && false !== $meta_value ) $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value ); $meta_ids = $wpdb->get_col( $query ); diff --git a/tests/phpunit/tests/meta/deleteMetadata.php b/tests/phpunit/tests/meta/deleteMetadata.php new file mode 100644 index 0000000000..1be8204ea4 --- /dev/null +++ b/tests/phpunit/tests/meta/deleteMetadata.php @@ -0,0 +1,100 @@ +assertEqualSets( $vals, $m ); + + delete_metadata( 'post', 12345, 'foo' ); + $m = get_metadata( 'post', 12345, 'foo', false ); + $this->assertEqualSets( array(), $m ); + } + + public function test_with_meta_value() { + $vals = array( '0', '1', '2' ); + foreach ( $vals as $val ) { + add_metadata( 'post', 12345, 'foo', $val ); + } + $m = get_metadata( 'post', 12345, 'foo', false ); + $this->assertEqualSets( $vals, $m ); + + delete_metadata( 'post', 12345, 'foo', '1' ); + $m = get_metadata( 'post', 12345, 'foo', false ); + $expected = array_diff( $vals, array( '1' ) );; + $this->assertEqualSets( $expected, $m ); + } + + /** + * @ticket 32224 + */ + public function test_with_falsey_meta_value_should_not_delete_all_meta() { + $vals = array( '0', '1', '2' ); + foreach ( $vals as $val ) { + add_metadata( 'post', 12345, 'foo', $val ); + } + $m = get_metadata( 'post', 12345, 'foo', false ); + $this->assertEqualSets( $vals, $m ); + + delete_metadata( 'post', 12345, 'foo', '0' ); + $m = get_metadata( 'post', 12345, 'foo', false ); + $expected = array_diff( $vals, array( '0' ) );; + $this->assertEqualSets( $expected, $m ); + } + + /** + * @ticket 32224 + * + * This is a backwards compatiblity quirk. + */ + public function test_meta_value_should_be_ignored_when_empty_string() { + $vals = array( '0', '1', '2', '' ); + foreach ( $vals as $val ) { + add_metadata( 'post', 12345, 'foo', $val ); + } + $m = get_metadata( 'post', 12345, 'foo', false ); + $this->assertEqualSets( $vals, $m ); + + delete_metadata( 'post', 12345, 'foo', '' ); + $m = get_metadata( 'post', 12345, 'foo', false ); + $this->assertEqualSets( array(), $m ); + } + + /** + * @ticket 32224 + */ + public function test_meta_value_should_be_ignored_when_null() { + $vals = array( '0', '1', '2', '' ); + foreach ( $vals as $val ) { + add_metadata( 'post', 12345, 'foo', $val ); + } + $m = get_metadata( 'post', 12345, 'foo', false ); + $this->assertEqualSets( $vals, $m ); + + delete_metadata( 'post', 12345, 'foo', null ); + $m = get_metadata( 'post', 12345, 'foo', false ); + $this->assertEqualSets( array(), $m ); + } + + /** + * @ticket 32224 + */ + public function test_meta_value_should_be_ignored_when_false() { + $vals = array( '0', '1', '2', '' ); + foreach ( $vals as $val ) { + add_metadata( 'post', 12345, 'foo', $val ); + } + $m = get_metadata( 'post', 12345, 'foo', false ); + $this->assertEqualSets( $vals, $m ); + + delete_metadata( 'post', 12345, 'foo', false ); + $m = get_metadata( 'post', 12345, 'foo', false ); + $this->assertEqualSets( array(), $m ); + } +}