Eliminar acciones / filtros agregados a través de funciones anónimas

10

Es una maldita mala práctica, debo decir. Pasé las últimas dos horas buscando una solución para eliminar acciones y filtros agregados a través de funciones anónimas.

Este es el código utilizado en un tema principal y necesito eliminarlo.

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

Tienes la respuesta de toscho , jugado con él en gran medida, pero sin ayuda. Entonces, ¿hay alguna otra alternativa que elimine las acciones / filtros agregados a través de funciones anónimas?

Gracias

Abhik
fuente
Sugeriría contactar al autor del tema. Es una solución relativamente fácil para él / ella usar una función con nombre en lugar del anónimo y mejoraría el código.
helgatheviking
gmazzap parece que @ vishalbasnet23 lo hizo aquí: gist.github.com/vishalbasnet23/5f74df4c800681199ab0246bc037d1d5 Lo estoy probando y hasta ahora funciona perfectamente.
Renan Oliveira

Respuestas:

10

El problema es que no puede distinguir entre una función anónima y otra, por lo que sí, es posible eliminar un cierre (es decir, una función anónima), pero si más de un cierre actúa sobre el mismo filtro con la misma prioridad, debe elegir , eliminarlos todos, o eliminar solo uno (sin saber exactamente cuál).

Mostraré cómo eliminarlos a todos utilizando una función altamente derivada de la que aparece en la respuesta @toscho que publicó:

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

Cambié el nombre de la función remove_object_filterporque puede eliminar todo tipo de filtros de objetos: métodos de clase estática, métodos de objetos dinámicos y cierres.

El $priorityargumento es opcional, pero cuando se eliminan los cierres, siempre se debe usar, de lo contrario, la función eliminará cualquier cierre agregado al filtro, sin importar en qué prioridad, porque cuando $priorityse omite, todos los filtros que usan la clase / método de destino o el cierre son remoto.

Cómo utilizar

// 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
fuente
He probado este y muchos otros, pero simplemente no funciona
Adamj
@adamj desde la versión 4.7, WordPress introdujo una nueva forma de ganchos mango, por lo que este ya no funcionan ...
gmazzap
¿Conoces alguna alternativa por casualidad?
adamj
1
@adamj Podría actualizar esto para 4.7+, pero no hay tiempo ahora, y no estoy seguro de cuándo lo haré. Está bien abrir una nueva pregunta, donde se vincula a este Q / A y dice que está desactualizado, de esa manera cualquiera puede responder, por lo que si no tengo tiempo, tal vez alguien más lo haga. Como alternativa, podría poner una recompensa por esta Q, explicando que la respuesta más votada aquí no funciona en la versión actual de WP ...
gmazzap
3

¿Qué pasa si agrega su filtro, con la prioridad 11, para que vaya después? Eso es feo, pero podría funcionar en su caso.

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

    return $default;
}, 11, 1 );
tivnet
fuente
2

Los filtros y las acciones anónimas se pueden eliminar de forma nativa utilizando lo siguiente:

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

Al generar la identificación única utilizando spl_object_hash(), las funciones anónimas son comparables entre sí, por lo que no es necesario volver a crear el objeto de cierre completo.

Si varios filtros o acciones están conectados a la misma etiqueta con la misma prioridad, eliminará el último filtro o acción que se agregó. Si necesita conservar uno, deberá eliminar todos los filtros hasta el que necesita eliminar y luego volver a agregar los demás según sea necesario.

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

Esto generalmente regresará a las mejores prácticas. Solo usaré funciones anónimas como parte de un tema personalizado que estoy desarrollando para un cliente, donde no quiero que se sobrescriba o elimine el filtro. En cualquier tema público o complemento que desarrolle, usaré una fábrica para inicializar una clase, agregar todos mis filtros y acciones, luego almacenar la instancia como una variable estática.

Shaun Cockerill
fuente