Make WordPress Core

Opened 11 years ago

Closed 11 years ago

Last modified 11 years ago

#32224 closed defect (bug) (fixed)

delete_post_meta() not working as expected when $meta_value is specified as 0 or '0'

Reported by: husobj Owned by: boonebgorges
Priority: normal Milestone: 4.3
Component: Options, Meta APIs Version: 4.2.1
Severity: normal Keywords:
Cc: Focuses:

Description

The [delete_post_meta()](​https://codex.wordpress.org/Function_Reference/delete_post_meta) codex says that if $meta_value is specified this is used to differentiate between several fields with the same key. If left blank, all fields with the given key will be deleted.

I have just created an instance where I have multiple numeric meta values stored with the same key.
For example:

$meta = get_post_meta( $post_id, 'my_var' );
print_r( $meta );

outputs:

Array (
    [0] => 57
    [1] => 103
    [2] => 0
    [3] => 97
    [4] => 4
)

The following works as expected and deletes the meta value 103:

delete_post_meta( $post_id, 'my_var', 103 );

However, if I try to delete the zero value, it deletes all the meta!

delete_post_meta( $post_id, 'my_var', 0 );
// or
delete_post_meta( $post_id, 'my_var', '0' );

Is the empty check too strict? It should only be deleting all meta if the value is an empty string, not a zero value.

Change History (12)

#1 @husobj
11 years ago

  • Summary delete_post_meta() not working as expect when $meta_value is specified as 0 or '0' → delete_post_meta() not working as expected when $meta_value is specified as 0 or '0'

#2 @boonebgorges
11 years ago

  • Milestone Awaiting Review → 4.3
  • Owner set to boonebgorges
  • Status new → reviewing

Confirmed. I'll have a look.

#3 follow-up: @sc0ttkclark
11 years ago

delete_metadata uses this:

if ( $meta_value )
    $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value );

It should probably be:

if ( '' !== $meta_value && null !== $meta_value )
    $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value );

#4 in reply to: ↑ 3 @boonebgorges
11 years ago

Replying to sc0ttkclark:

delete_metadata uses this:

if ( $meta_value )
    $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value );

It should probably be:

if ( '' !== $meta_value && null !== $meta_value )
    $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value );

It's possible to add an empty string as metadata, so we don't want to remove the ability to delete empty-string meta values.

If this were the last argument passed to delete_metadata(), we could use func_num_args() to see if a value had been passed at all. But we also want it to be possible to specify falsey values for $meta_value while passing a value for $delete_all. To the unit tests, Batman!

#5 @sc0ttkclark
11 years ago

Right, this is assuming that $meta_value is by default '' as defined in the function itself currently. func_num_args() would still be tricky since delete_post_meta and other delete_metadata wrappers pass in all arguments, so it would only be available in those functions and not delete_metadata.

#6 @boonebgorges
11 years ago

Yeah, you're right about the wrappers. How about changing the default value of $meta_value to null for delete_metadata() and all wrappers, and then skipping the value clause when is_null( $_meta_value )?

#7 @boonebgorges
11 years ago

Scratch that idea. It'll break every plugin that has its own delete_metadata() wrappers.

There may be no backward-compatible way to fix this bug and also let delete_metadata() work properly with $meta_value = ''. We'll just have to document that quirk.

#8 @sc0ttkclark
11 years ago

So are we back at this proposed fix, since it still prevents zeros from being deleted?

if ( '' !== $meta_value && null !== $meta_value )
    $query .= $wpdb->prepare(" AND meta_value = %s", $meta_value );

#9 @boonebgorges
11 years ago

Yeah, though let's also make it possible to skip the $meta_value check with false.

#10 @boonebgorges
11 years ago

  • Resolution → fixed
  • Status reviewing → closed

In 32331:

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.

#11 @sc0ttkclark
11 years ago

Sounds great!

#12 @husobj
11 years ago

Thanks guys for jumping on this so quickly :)

Note: See TracTickets for help on using tickets.