Usuń akcje / filtry dodane za pomocą funkcji anonimowych

10

To cholernie zła praktyka, muszę powiedzieć. Ostatnie dwie godziny spędziłem na znalezieniu rozwiązania do usunięcia akcji i filtrów dodanych za pomocą funkcji anonimowych.

To jest kod użyty w motywie nadrzędnym i muszę go usunąć.

/**
 * 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 );
});

Mam odpowiedź Toscho, bawiłem się nią intensywnie, ale bez pomocy. Czy jest więc jakaś alternatywa, która usunie akcje / filtry dodane za pomocą anonimowych funkcji?

Dzięki

Abhik
źródło
Sugerowałbym skontaktowanie się z autorem tematu. Jest to stosunkowo łatwa poprawka dla niego, aby użyć nazwanej funkcji zamiast anonimowego i poprawić kod.
helgatheviking
gmazzap wygląda na to, że @ vishalbasnet23 zrobił to tutaj: gist.github.com/vishalbasnet23/5f74df4c800681199ab0246bc037d1d5 Testuję to i do tej pory działa idealnie.
Renan Oliveira

Odpowiedzi:

10

Problem polega na tym, że nie można rozróżnić funkcji anonimowej od innej, więc tak, możliwe jest usunięcie zamknięcia (tj. Funkcji anonimowej), ale jeśli więcej niż jedno zamknięcie działa na tym samym filtrze z tym samym priorytetem, musisz dokonać wyboru , usuń je wszystkie, lub usuń tylko jeden (nie wiedząc dokładnie, które).

Pokażę, jak je wszystkie usunąć za pomocą funkcji pochodzącej z tej z odpowiedzi @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] );
      }
    }
  }
}

Zmieniłem nazwę funkcji, remove_object_filterponieważ może ona usuwać wszystkie typy filtrów obiektów: metody klas statycznych, metody obiektów dynamicznych i zamknięcia.

$priorityArgument jest opcjonalny, ale podczas zdejmowania zamknięć należy zawsze stosować, inaczej funkcja usunie wszelkie zamknięcie dodany do filtra, bez względu na to, w którym priorytetem, bo gdy $priorityzostanie pominięty, wszystkie filtry wykorzystujące klasę docelową / metody lub zamknięcie są oddalony.

Jak używać

// 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
źródło
Próbowałem tego i wielu innych, ale po prostu nie działa
adamj
@adamj od wersji 4.7, WordPress wprowadził nowy sposób obsługi haków, więc to już nie działa ...
gmazzap
czy znasz jakieś alternatywy przypadkiem?
adamj
1
@adamj Mógłbym to zaktualizować do wersji 4.7+, ale nie mam teraz czasu i nie jestem pewien, kiedy to zrobię. Dobrze jest otworzyć nowe pytanie, w którym link do tego pytania i odpowiedzi jest nieaktualny, w ten sposób każdy może odpowiedzieć, więc jeśli nie będę miał czasu, może zrobi to ktoś inny. Alternatywnie, możesz wystawić nagrodę za to Q, wyjaśniając, że najbardziej uprzywilejowana odpowiedź tutaj nie działa w obecnej wersji WP ...
gmazzap
3

Co się stanie, jeśli dodasz filtr z priorytetem 11, więc będzie on realizowany? To brzydkie, ale może działać w twoim przypadku.

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

    return $default;
}, 11, 1 );
tivnet
źródło
2

Anonimowe filtry i akcje można usunąć natywnie za pomocą:

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

Podczas generowania unikalnego identyfikatora za pomocą spl_object_hash()anonimowe funkcje są do siebie porównywalne, więc obiekt pełnego zamknięcia nie musi być ponownie tworzony.

Jeśli wiele filtrów lub akcji jest połączonych z tym samym tagiem o tym samym priorytecie, usunie najnowszy filtr lub akcję, która została dodana. Jeśli jest taki, który musisz zachować, musisz usunąć wszystkie filtry aż do tego, który chcesz usunąć, a następnie ponownie dodać pozostałe, jeśli to konieczne.

// 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(){} );

Ogólnie powróci to do najlepszych praktyk. Będę kiedykolwiek używał anonimowych funkcji tylko jako część niestandardowego motywu, który tworzę dla klienta, w którym nie chcę, aby filtr został nadpisany lub usunięty. W każdym opracowanym przeze mnie publicznym motywie lub wtyczce użyję fabryki, aby zainicjować klasę, dodać wszystkie moje filtry i akcje, a następnie zapisać instancję jako zmienną statyczną.

Shaun Cockerill
źródło