Pasando un parámetro a funciones de filtro y acción

17 mar 2012, 13:24:53
Vistas: 56.4K
Votos: 64

Existe una forma de pasar mis propios parámetros a la función en add_filter o add_action. Por ejemplo, observa el siguiente código:

function my_content($content, $my_param)
{
// hacer algo...
// usando $my_param aquí ...
return $content;
}
add_filter('the_content', 'my_content', 10, 1);

¿Puedo pasar mi propio parámetro? ¿algo como:

add_filter('the_content', 'my_content($my_param)', 10, 1)

o

add_filter('the_content', 'my_content', 10, 1, $my_param)
1
Comentarios

puedes usar $_SESSION para almacenar y obtener parámetros.

Sunil Kumar Sunil Kumar
10 jul 2020 12:23:15
Todas las respuestas a la pregunta 12
5
98

Por defecto esto no es posible. Hay soluciones alternativas si lo haces de manera orientada a objetos.
Podrías crear una clase para almacenar los valores que quieras usar más tarde.

Ejemplo:

/**
 * Almacena un valor y llama a cualquier función existente con este valor.
 */
class WPSE_Filter_Storage
{
    /**
     * Rellenado por __construct(). Usado por __call().
     *
     * @type mixed Cualquier tipo que necesites.
     */
    private $values;

    /**
     * Almacena los valores para su uso posterior.
     *
     * @param  mixed $values
     */
    public function __construct( $values )
    {
        $this->values = $values;
    }

    /**
     * Captura todas las llamadas a funciones excepto __construct().
     *
     * Ten en cuenta: Incluso si la función se llama con solo una cadena como
     * argumento, se enviará como un array.
     *
     * @param  string $callback Nombre de la función
     * @param  array  $arguments
     * @return mixed
     * @throws InvalidArgumentException
     */
    public function __call( $callback, $arguments )
    {
        if ( is_callable( $callback ) )
            return call_user_func( $callback, $arguments, $this->values );

        // Función incorrecta llamada.
        throw new InvalidArgumentException(
            sprintf( 'Archivo: %1$s<br>Línea %2$d<br>No se puede llamar: %3$s',
                __FILE__, __LINE__, print_r( $callback, TRUE )
            )
        );
    }
}

Ahora puedes llamar a la clase con cualquier función que desees – si la función existe en algún lugar, se llamará con tus parámetros almacenados.

Vamos a crear una función de demostración ...

/**
 * Función de filtro.
 * @param  array $content
 * @param  array $numbers
 * @return string
 */
function wpse_45901_add_numbers( $args, $numbers )
{
    $content = $args[0];
    return $content . '<p>' . implode( ', ', $numbers ) . '</p>';
}

... y usarla una vez ...

add_filter(
    'the_content',
    array (
        new WPSE_Filter_Storage( array ( 1, 3, 5 ) ),
        'wpse_45901_add_numbers'
    )
);

... y otra vez ...

add_filter(
    'the_content',
    array (
        new WPSE_Filter_Storage( array ( 2, 4, 6 ) ),
        'wpse_45901_add_numbers'
    )
);

Salida:

Descripción de la imagen

La clave es la reutilización: Puedes reutilizar la clase (y en nuestros ejemplos también la función).

PHP 5.3+

Si puedes usar una versión de PHP 5.3 o superior, los cierres (closures) lo harán mucho más fácil:

$param1 = '<p>¡Esto funciona!</p>';
$param2 = '¡Esto también funciona!';

add_action( 'wp_footer', function() use ( $param1 ) {
        echo $param1;
    }, 11 
);
add_filter( 'the_content', function( $content ) use ( $param2 ) {
        return t5_param_test( $content, $param2 );
    }, 12
);

/**
 * Añade una cadena al contenido del post
 *
 * @param  string $content
 * @param  string $string Esto es $param2 en nuestro ejemplo.
 * @return string
 */
function t5_param_test( $content, $string )
{
    return "$content <p><b>$string</b></p>";
}

El inconveniente es que no puedes escribir pruebas unitarias para los cierres.

17 mar 2012 20:32:12
Comentarios

No solo obtienes un voto a favor por una respuesta de calidad a un problema que debería tener una solución incorporada en el núcleo de WP, sino que también obtienes uno por regresar cinco meses después para actualizar tu respuesta con el ejemplo de cierre (closure) para PHP 5.3+.

Adam Adam
17 nov 2013 09:17:38

¡Excelente respuesta! Pero, ¿cómo puedo hacer para eliminar este filtro creado por esta función anónima más adelante?

Vinicius Tavares Vinicius Tavares
12 ago 2014 06:33:54

@ViniciusTavares No puedes. Piensa antes de usarlo. :)

fuxia fuxia
12 ago 2014 11:17:41

Sin embargo, ten en cuenta que si guardas la función anónima en una variable (por ejemplo, $func = function() use ( $param1 ) { $param1; }; y add_action( $func, 11);) entonces puedes eliminarla mediante remove_action( $func, 11 );

bonger bonger
2 may 2015 21:49:18

Pero no es recomendable usar funciones anónimas en plugins o temas que vayas a distribuir públicamente (puedes usarlas en tus propios proyectos). El problema con esto es que no podrás desengancharlas. Cualquier enfoque que decidas usar debería permitir ser desenganchado posteriormente.

Mueyiwa Moses Ikomi Mueyiwa Moses Ikomi
22 feb 2018 18:04:32
0

Usa funciones anónimas en PHP (funciones anónimas):

$my_param = 'mi nombre de tema';
add_filter('the_content', function ($content) use ($my_param) {
    //$my_param está disponible ahora
    if (is_page()) {
        $content = $my_param . ':<br>' . $content;
    }
    return $content;
}, 10, 1);
23 ene 2016 12:26:32
0

La forma correcta, realmente corta y más eficiente de pasar cualquier número de argumentos a los filtros y acciones de WordPress es de @Wesam Alalem aquí, que utiliza un cierre (closure).

Solo agregaría que podrías hacerlo aún más claro y mucho más flexible separando el método que realiza la acción del cierre anónimo. Para esto, simplemente llamas al método desde el cierre de la siguiente manera (ejemplo modificado de la respuesta de @Wesam Alalem).

De esta forma, puedes escribir una lógica tan larga o complicada como desees léxicamente fuera del cierre que utilizas para llamar al método que realiza la acción.

// ... dentro de alguna clase

private function myMethod() {
    $my_param = 'mi nombre de tema';
    add_filter('the_content', function ($content) use ($my_param) {
        // Este es el cierre anónimo que permite pasar
        // cualquier número de parámetros que desees mediante la palabra clave 'use'.
        // Esto es solo una línea.
        // $my_param está disponible para ti ahora a través de la palabra clave 'use' anterior
        return $this->doThings($content, $my_param);
    }, 10, 2);
}

private function doThings($content, $my_param) {
    // Llama aquí a algún otro método para hacer más cosas
    // por muy complicadas que sean.
    $morethings = '';
    if ($content = 'algunas cosas más') {
        $morethings = (new MoreClass())->get();
    }
    return $my_param . ':<br>' . $content . $morethings;
}
14 oct 2018 19:10:58
0

Crea una función con los argumentos necesarios que retorne otra función. Pasa esta función (función anónima, también conocida como closure) al hook de WordPress.

Mostrado aquí para un aviso de administración en el backend de WordPress.

public function admin_notice_func( $message = '')
{
$class = 'error';
    $output = sprintf('<div class="%s"><p>%s</p></div>',$class, $message);
    $func = function() use($output) { print $output; };
    return $func;
}
$func = admin_notice_func('Mensaje');
add_action('admin_notices', $func);
20 ene 2016 20:53:14
0

Como se mencionó en otras respuestas, pasar un parámetro a la función de callback no es posible por defecto. La POO y las funciones anónimas de PHP son soluciones alternativas PERO:

  1. Tu código podría no estar orientado a objetos
  2. Podrías necesitar eliminar ese filtro posteriormente

Si ese es tu caso, existe otra solución alternativa que puedes utilizar: haz uso de las funciones add_filter y apply_filters para hacer que ese parámetro que deseas pasar esté disponible en la función de callback:

// Solución alternativa para "guardar" el parámetro que se pasará a tu función de callback.
add_filter( 'pass_param', function() use ( $param ){ return $param; } );

// Enlaza tu función para filtrar lo que necesites filtrar.
add_filter( 'actual_filter', 'myCallback' );

// Tu función de callback que realmente filtra lo que necesites.
function myCallback()
{
   // Obtiene el parámetro que no pudimos pasar directamente a esta función.
   $param = apply_filters( 'pass_param', '' );

   // Haz lo que necesites con el parámetro pasado alternativamente para usarlo en el filtrado.
   return $param;
}
7 may 2020 12:12:35
3

Siempre puedes usar variables globales..

  global $mi_parametro;
25 ago 2017 02:47:08
Comentarios

Esto no proporciona una respuesta a la pregunta. Una vez que tengas suficiente reputación podrás comentar cualquier publicación; en su lugar, proporciona respuestas que no requieran aclaración del que pregunta. - De la revisión

cjbj cjbj
25 ago 2017 07:25:56

@cjbj En realidad sí lo hace. La pregunta es si se pueden pasar parámetros a la "función" que está en add_filter o add_action. No estaba claro si el usuario quería pasarlo en la propia función add_filter o add_action, aunque esa sea la suposición. :)

samjco-com samjco-com
25 ago 2017 08:17:43

Esto no es Jeopardy. Responder en forma de pregunta es más apropiado para comentarios, no para respuestas. Creo que a eso se refiere cjbj.

Jake Jake
9 dic 2020 18:40:25
0

A pesar de llamar a una función directamente, hazlo de una manera más elegante: pasa una función anónima como callback.

Por ejemplo:

Tengo una única función para traducir el título, el contenido y el extracto de mis publicaciones. Por lo tanto, necesito pasar a esta función principal algunos argumentos que indiquen quién está llamando.

add_filter( 'the_title', function( $text ) { 
    return translate_text( $text, 'title', 'pl' );
});

add_filter( 'the_content', function( $text ) { 
    return translate_text( $text, 'content', 'pl' );
});

add_filter( 'the_excerpt', function( $text ) { 
    return translate_text( $text, 'excerpt', 'pl' );
});

Así, la función principal translate_text recibe tantos parámetros como desee, simplemente porque he pasado una función anónima como callback.

25 oct 2019 23:30:52
1

Estoy de acuerdo en que la respuesta de fuxia anterior proporciona los enfoques preferidos. Pero mientras intentaba entender la solución OOP, encontré una manera de hacerlo que establece y luego elimina tanto el filtro como una variable global:

function my_function() {
    
    // Declarar la variable global y establecerla en algo
    global $my_global;
    $my_global = 'algo';
        
    // Añadir el filtro
    add_filter( 'some_filter', 'my_filter_function' );
    
    // Hacer lo que sea que necesitabas el filtro para
    echo $filtered_stuff; 
    
    // Eliminar el filtro (para que no afecte a algo más que se ejecute después)
    remove_filter( 'some_filter', 'my_filter_function' );

    // Eliminar la global (porque no nos gustan las variables globales flotando en nuestro código)
    my_unset_function( 'my_global' );
    
}

function my_filter_function( $arg ) {
    
    // Declarar la global
    global $my_global;

    // Usar $my_global para hacer algo con $arg
    $arg = $arg . $my_global;

    return $arg;

}

function my_unset_function( $var_name ) {

    // Declarar la global
    $GLOBALS[$var_name];

    // Eliminar la global
    unset($GLOBALS[$var_name];

}

Soy un desarrollador sin formación y trabajo estrictamente en mis propios sitios, así que por favor tome este boceto con cautela. Funciona para mí, pero si hay algo incorrecto en lo que estoy haciendo aquí, agradecería que alguien con más conocimiento lo señalara.

22 jun 2020 17:48:30
Comentarios

Las variables globales no están protegidas: cualquiera puede asignarles cualquier valor (piensa en colisiones de nombres), y son muy difíciles de depurar. En general, se consideran una mala práctica.

fuxia fuxia
22 jun 2020 19:21:30
0

En mi solución de POO simplemente usé una variable miembro de la clase que es llamada en la función de callback. En este ejemplo el post_title es filtrado por un término de búsqueda:

class MyClass
{
  protected $searchterm = '';

  protected function myFunction()
  {
    query = [
      'numberposts' => -1,
      'post_type' => 'my_custom_posttype',
      'post_status' => 'publish'
    ];

    $this->searchterm = 'xyz';
    add_filter('posts_where', [$this, 'searchtermPostsWhere']);
    $myPosts = get_posts($query);
    remove_filter('posts_where', [$this, 'searchtermPostsWhere']);
  }

  public function searchtermPostsWhere($where)
  {
    $where .= ' AND ' . $GLOBALS['wpdb']->posts . '.post_title LIKE \'%' . esc_sql(like_escape($this->searchterm)) . '%\'';
    return $where;
  }
}
25 jul 2020 21:49:39
2
-1

si creas tu propio hook, aquí tienes un ejemplo.

// digamos que tenemos tres parámetros [ https://codex.wordpress.org/Function_Reference/add_filter ]
add_filter( 'filter_name', 'my_func', 10, 3 );
my_func( $first, $second, $third ) {
  // código
}

luego implementa el hook:

// [ https://codex.wordpress.org/Function_Reference/apply_filters ]
echo apply_filters( 'filter_name', $first, $second, $third );
14 may 2015 12:20:16
Comentarios

Esto no pasa la información del registro al callback. Solo indica cuántos parámetros puede aceptar el callback.

fuxia fuxia
18 may 2015 01:15:01

@fuxia, ¿puedes sugerir un cambio simple para que la información sí se pase? ¿Sería simplemente añadir los valores de los parámetros después del 3?

SherylHohman SherylHohman
25 may 2019 11:32:51
2
-1

Ya sé que ha pasado tiempo, pero tuve algunos problemas para pasar mi propio parámetro hasta que descubrí que el cuarto parámetro en add_filter es el número de parámetros pasados incluyendo el contenido a modificar. Así que si pasas 1 parámetro adicional, el número debería ser 2 y no 1 en tu caso

add_filter('the_content', 'my_content', 10, 2, $my_param)

y usando

function my_content($content, $my_param) {...}
16 feb 2017 14:48:58
Comentarios

¿Estás seguro de que puedes pasar un quinto parámetro a add_filter? Según la documentación oficial, esto no es correcto. ¿Has probado tu respuesta? Por favor, ten cuidado con difundir información errónea.

plong0 plong0
23 sept 2020 22:02:20

Esto no es así como funciona, y mis pruebas hasta ahora confirman que esto no funciona de esta manera.

Jake Jake
9 dic 2020 18:52:47
0
-2

Tenía la esperanza de hacer lo mismo pero como no es posible, supongo que una solución simple es llamar a una función diferente como add_filter('the_content', 'my_content_filter', 10, 1);

Entonces my_content_filter() puede simplemente llamar a my_content() pasando cualquier argumento que desee.

12 dic 2017 23:24:31