WordPress.org

Make WordPress Core

Opened 3 years ago

Closed 3 years ago

Last modified 3 years ago

#40192 closed defect (bug) (invalid)

apply_filters() works only once, if doing multiple array merge

Reported by: esemlabel Owned by:
Milestone: Priority: normal
Severity: normal Version:
Component: General Keywords:
Focuses: Cc:
PR Number:

Description

<?php
$array = array( 'one', 'two' );
$array = array_merge( $array, (array) apply_filters( 'example_filter', array() ) );

Such array_merge() need when we want only extend original array without modifying it. If we hook in this filter multiple times, the last one hooked functions will override all previously returned to filter values.

<?php
add_filter( 'example_filter', 'three' );
function three() {
    return 'three';
}

add_filter( 'example_filter', 'four_n_five' );
function four_n_five() {
    return array( 'four', 'five' );
}

Result $array will be

<?php
$array = array( 'one', 'two', 'four', 'five' );

The only way to return all values is to always use original $array in apply_filters, and always perform array_merge() inside every hooked function. Look like the logic is gone.

<?php
$array = array( 'one', 'two' );
$array = apply_filters( 'example_filter', $array );

add_filter( 'example_filter', 'three' );
function three( $array ) {
    return array_merge( $array, array( 'three' ) );
}

add_filter( 'example_filter', 'four_n_five' );
function four_n_five( $array ) {
    return array_merge( $array, array( 'four', 'five' ) );
}

Result $array will be

<?php
$array = array( 'one', 'two', 'three', 'four', 'five' );

Change History (3)

#1 @ocean90
3 years ago

  • Milestone Awaiting Review deleted
  • Resolution set to invalid
  • Status changed from new to closed
  • Version trunk deleted

Hello @esemlabel, thanks for your report. That's actually how apply_filters() and `add_filter() are working. Filters have to make sure to either return the original value or an extended/modified value based on the original value.

Feel free to look at our plugin handbook if you want to know more about hooks in general.

#2 @esemlabel
3 years ago

Understood. But why the core files uses array_merge() in apply_filters() in

https://core.trac.wordpress.org/browser/trunk/src/wp-admin/maint/repair.php#L88
https://core.trac.wordpress.org/browser/trunk/src/wp-includes/cron.php#L409

There is no any note that we can't use these filter more than once, because of array_merge() in it doesnt handle more than one return of value.

If different plugins will use one of this filters from links, only the last one plugin will work. I don't think it is a normal behavior of apply_filters().

Last edited 3 years ago by esemlabel (previous) (diff)

#3 @ocean90
3 years ago

tables_to_repair can be used to add additional tables. The array_merge() ensures that the default tables are always in $tables variable. Same for cron_schedules. The default schedules cannot be removed as it would break core's default cron events.

As mentioned before, if plugins are using these filters they have to make sure to extend (for example with array_merge()) the previous value.

Note: See TracTickets for help on using tickets.