Удалить действия / фильтры, добавленные через анонимные функции

10

Это чертовски плохая практика, я должен сказать. Потратил последние два часа на поиск решения для удаления действий и фильтров, добавленных через анонимные функции.

Это код, используемый в родительской теме, и мне нужно удалить его.

/**
 * Add custom columns to admin comments grid
 *  * Rate that user set.
 */
add_filter( 'manage_edit-comments_columns', function( $default ) {
    $columns['smr_comment_rate']  = __( 'Rate', 'txtdmn' );

    return array_slice( $default, 0, 3, true ) + $columns + array_slice( $default, 2, NULL, true );
});

Получил ответ Тошо , играл с ним тяжело, но без помощи. Итак, есть ли другая альтернатива, которая удалит действия / фильтры, добавленные через анонимные функции?

Спасибо

Abhik
источник
Я бы предложил связаться с автором темы. Для него / нее относительно легко исправить использование именованной функции вместо анонимной, что улучшит код.
helgatheviking
gmazzap, похоже, @ vishalbasnet23 сделал это здесь: gist.github.com/vishalbasnet23/5f74df4c800681199ab0246bc037d1d5 Я тестирую его, и пока он работает отлично.
Ренан Оливейра

Ответы:

10

Проблема в том, что вы не можете отличить анонимную функцию от другой, так что да, можно удалить замыкание (то есть анонимную функцию), но если несколько фильтров замыкания действуют на один и тот же приоритет с одним и тем же приоритетом, вы должны сделать выбор , удалите их все, удалите только одну (не зная точно, какую).

Я покажу, как удалить их все, используя функцию, очень производную от функции в ответе @toscho, который вы разместили:

/**
 * Remove an object filter.
 *
 * @param  string $tag                Hook name.
 * @param  string $class              Class name. Use 'Closure' for anonymous functions.
 * @param  string|void $method        Method name. Leave empty for anonymous functions.
 * @param  string|int|void $priority  Priority
 * @return void
 */
function remove_object_filter( $tag, $class, $method = NULL, $priority = NULL ) {
  $filters = $GLOBALS['wp_filter'][ $tag ];
  if ( empty ( $filters ) ) {
    return;
  }
  foreach ( $filters as $p => $filter ) {
    if ( ! is_null($priority) && ( (int) $priority !== (int) $p ) ) continue;
    $remove = FALSE;
    foreach ( $filter as $identifier => $function ) {
      $function = $function['function'];
      if (
        is_array( $function )
        && (
          is_a( $function[0], $class )
          || ( is_array( $function ) && $function[0] === $class )
        )
      ) {
        $remove = ( $method && ( $method === $function[1] ) );
      } elseif ( $function instanceof Closure && $class === 'Closure' ) {
        $remove = TRUE;
      }
      if ( $remove ) {
        unset( $GLOBALS['wp_filter'][$tag][$p][$identifier] );
      }
    }
  }
}

Я переименовал функцию, remove_object_filterпотому что она может удалять все типы фильтров объектов: методы статических классов, методы динамических объектов и замыкания.

$priorityАргумент является необязательным, но при удалении замыкания следует всегда используются, в противном случае функция будет удалить любое замыкание добавленного к фильтру, независимо от того , на котором приоритет, потому что , когда $priorityопущено, все фильтры , использующие целевой класс / метод или замыкание являются удален.

Как пользоваться

// remove a static method
remove_object_filter( 'a_filter_hook', 'AClass', 'a_static_method', 10 );

// remove a dynamic method
remove_object_filter( 'a_filter_hook', 'AClass', 'a_dynamic_method', 10 );

// remove a closure
remove_object_filter( 'a_filter_hook', 'Closure', NULL, 10 );
Gmazzap
источник
Я пробовал этот и многие другие, но он просто не работает
adamj
@adamj начиная с версии 4.7, WordPress представил новый способ обработки хуков, так что это больше не работает ...
gmazzap
Вы знаете какие-нибудь альтернативы случайно?
adamj
1
@adamj Я мог бы обновить это для 4.7+, но сейчас нет времени, и не уверен, когда у меня будет. Это нормально, чтобы открыть новый вопрос, где вы ссылаетесь на этот вопрос и говорите, что он устарел, так что каждый может ответить, поэтому, если у меня не будет времени, может быть, кто-то еще. В качестве альтернативы, вы можете назначить щедрость на этот вопрос, объяснив, что ответ с наибольшим количеством голосов здесь не работает в текущей версии WP ...
gmazzap
3

Что, если вы добавите свой фильтр с приоритетом 11, чтобы он шел после? Это некрасиво, но может сработать в вашем случае.

add_filter( 'manage_edit-comments_columns', function( $default ) {
    unset( $default['smr_comment_rate'] );

    return $default;
}, 11, 1 );
tivnet
источник
2

Анонимные фильтры и действия могут быть удалены с помощью следующего:

remove_filter( $tag, function(){}, $priority )

При генерации уникального идентификатора с использованием spl_object_hash()анонимные функции сравнимы друг с другом, поэтому объект полного замыкания не нужно заново создавать.

Если несколько фильтров или действий связаны с одним и тем же тегом с одинаковым приоритетом, он удалит последний фильтр или действие, которое было добавлено. Если вам нужно сохранить один, вам нужно будет удалить все фильтры до того, который вам нужен, затем заново добавить остальные при необходимости.

// Filter which was added and needs to be removed
add_filter( 'manage_edit-comments_columns', function( $default ) {
    $columns['smr_comment_rate']  = __( 'Rate', 'txtdmn' );

    return array_slice( $default, 0, 3, true ) + $columns + array_slice( $default, 2, NULL, true );
} );

// Removes the last anonymous filter to be added
remove_filter( 'manage_edit-comments_columns', function(){} );

Как правило, это вернется к лучшим практикам. Я буду использовать анонимные функции только как часть пользовательской темы, которую разрабатываю для клиента, где я не хочу, чтобы фильтр был перезаписан или удален. В любой общедоступной теме или плагине, который я разрабатываю, я буду использовать фабрику для инициализации класса, добавления всех своих фильтров и действий, а затем сохранять экземпляр как статическую переменную.

Шон Кокерилл
источник