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

9

Esa es una 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 );
});

Obtuve la respuesta de toscho , jugó con ella en gran medida, pero no me ayudó. Entonces, ¿hay alguna otra alternativa que elimine las acciones / filtros agregados a través de funciones anónimas?

Gracias

    
pregunta Abhik 12.03.2014 - 12:44

3 respuestas

9

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

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

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

He cambiado el nombre de la función remove_object_filter porque puede eliminar todos los tipos de filtros de objetos: métodos de clase estáticos, métodos de objetos dinámicos y cierres.

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

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 );
    
respondido por el gmazzap 11.04.2014 - 08:37
2

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

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

    return $default;
}, 11, 1 );
    
respondido por el tivnet 23.03.2014 - 22:37
2

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

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

Cuando se genera el ID único con 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 se conectan varios filtros o acciones a la misma etiqueta con la misma prioridad, se eliminará el último filtro o acción que se agregó. Si hay uno que deba conservar, tendrá que 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 el filtro se sobrescriba o elimine. 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.

    
respondido por el Shaun Cockerill 07.08.2017 - 09:33

Lea otras preguntas en las etiquetas