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

52

Es una forma de pasar mis propios parámetros a la función en add_filtero add_action. Por ejemplo, eche un vistazo al siguiente código:

function my_content($content, $my_param)
{
do something...
using $my_param here ...
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)
Aakash Chakravarthy
fuente

Respuestas:

78

Por defecto esto no es posible. Hay soluciones alternativas si lo hace de la manera OOP.
Puede crear una clase para almacenar los valores que desea usar más adelante.

Ejemplo:

/**
 * Stores a value and calls any existing function with this value.
 */
class WPSE_Filter_Storage
{
    /**
     * Filled by __construct(). Used by __call().
     *
     * @type mixed Any type you need.
     */
    private $values;

    /**
     * Stores the values for later use.
     *
     * @param  mixed $values
     */
    public function __construct( $values )
    {
        $this->values = $values;
    }

    /**
     * Catches all function calls except __construct().
     *
     * Be aware: Even if the function is called with just one string as an
     * argument it will be sent as an array.
     *
     * @param  string $callback Function name
     * @param  array  $arguments
     * @return mixed
     * @throws InvalidArgumentException
     */
    public function __call( $callback, $arguments )
    {
        if ( is_callable( $callback ) )
            return call_user_func( $callback, $arguments, $this->values );

        // Wrong function called.
        throw new InvalidArgumentException(
            sprintf( 'File: %1$s<br>Line %2$d<br>Not callable: %3$s',
                __FILE__, __LINE__, print_r( $callback, TRUE )
            )
        );
    }
}

Ahora puede llamar a la clase con cualquier función que desee; si la función existe en algún lugar, se llamará con sus parámetros almacenados.

Creemos una función de demostración ...

/**
 * Filter function.
 * @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 úsalo 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:

ingrese la descripción de la imagen aquí

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

PHP 5.3+

Si puede usar una versión PHP 5.3 o cierres más nuevos, será mucho más fácil:

$param1 = '<p>This works!</p>';
$param2 = 'This works too!';

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
);

/**
 * Add a string to post content
 *
 * @param  string $content
 * @param  string $string This is $param2 in our example.
 * @return string
 */
function t5_param_test( $content, $string )
{
    return "$content <p><b>$string</b></p>";
}

La desventaja es que no puede escribir pruebas unitarias para cierres. 

fuxia
fuente
17
No solo obtiene un voto positivo por una respuesta de calidad a un problema que debería tener una solución integrada dentro del núcleo de WP , sino que también obtiene una por regresar cinco meses después para actualizar su respuesta con el ejemplo de cierre de PHP 5.3+.
Adam
1
Excelente respuesta! ¿Pero cómo puedo hacer para eliminar este filtro creado por esta función anónima más tarde?
Vinicius Tavares
2
@ViniciusTavares No puedes. Piensa antes de usarlo. :)
fuxia
55
Sin embargo, tenga en cuenta que si guarda la función anónima en una variable (por ejemplo, $func = function() use ( $param1 ) { $param1; };y add_action( $func, 11);), puede eliminarla a través deremove_action( $func, 11 );
bonger
1
Pero no es recomendable usar funciones anónimas en complementos o temas que está lanzando al mundo (puede usarlos en sus propios proyectos). El problema con esto es que no podrás desengancharlos. Cualquier enfoque con el que decida ir debería ser desenganchado más tarde.
Mueyiwa Moses Ikomi
1

Cree una función con los argumentos necesarios que devuelva una función. Pase esta función (función anónima, también conocida como cierre) al gancho wp.

Aquí se muestra un aviso de administrador 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('Message');
add_action('admin_notices', $func);
adorno
fuente
1

Utilice las funciones anónimas de php :

$my_param = 'my theme name';
add_filter('the_content', function ($content) use ($my_param) {
    //$my_param is available for you now
    if (is_page()) {
        $content = $my_param . ':<br>' . $content;
    }
    return $content;
}, 10, 1);
Wesamly
fuente
1

Sé que ha pasado el tiempo, pero tuve algún problema al pasar mi propio parámetro hasta que descubrí que el cuarto parámetro en add_filter es el número de parámetros pasados, incluido el contenido que se debe cambiar. Entonces, si pasa 1 parámetro adicional, el número debe ser 2 y no 1 en su caso

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

y usando

function my_content($content, $my_param) {...}
giacoder
fuente
1

La forma correcta, realmente corta y más eficiente de pasar cualquier número de argumentos a los filtros y acciones de WP es de @Wesam Alalem aquí , que usa el cierre.

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

De esta manera, puede escribir una lógica tan larga o complicada como desee léxicamente fuera del cierre que usa para llamar al autor real.

// ... inside some class

private function myMethod() {
    $my_param = 'my theme name';
    add_filter('the_content', function ($content) use ($my_param) {
        // This is the anonymous closure that allows to pass 
        // whatever number of parameters you want via 'use' keyword.
        // This is just oneliner.
        // $my_param is available for you now via 'use' keyword above
        return $this->doThings($content, $my_param);
    }, 10, 2);
}

private function doThings($content, $my_param) {
    // Call here some other method to do some more things
    // however complicated you want.
    $morethings = '';
    if ($content = 'some more things') {
        $morethings = (new MoreClass())->get();
    }
    return $my_param . ':<br>' . $content . $morethings;
}
bob-12345
fuente
0

si crea su propio gancho, aquí hay un ejemplo.

// lets say we have three parameters  [ https://codex.wordpress.org/Function_Reference/add_filter ]
add_filter( 'filter_name', 'my_func', 10, 3 );
my_func( $first, $second, $third ) {
  // code
}

luego implemente el gancho:

// [ https://codex.wordpress.org/Function_Reference/apply_filters ]
echo apply_filters( 'filter_name', $first, $second, $third );
T.Todua
fuente
Esto no pasa información del registro a la devolución de llamada. Solo dice cuántos parámetros puede aceptar la devolución de llamada.
fuxia
@fuxia, ¿puede sugerir un cambio simple para que se pase la información? ¿Se agregarían los valores de parámetro después de 3?
SherylHohman
0

Siempre puedes usar global ¿no?

  global $my_param;
samjco
fuente
Esto no proporciona una respuesta a la pregunta. Una vez que tenga suficiente reputación , podrá comentar cualquier publicación ; en su lugar, proporcione respuestas que no requieran una aclaración del autor de la pregunta . - De la opinión
cjbj
@cjbj En realidad lo hace. La pregunta es si los parámetros se pueden pasar a la "función" que se encuentra en add_filter o add_action. No estaba claro si el usuario quería pasarlo en la función add_filter o add_action, aunque esa sea la suposición. :)
samjco
0

A pesar de llamar a una función directamente, haga esto de una manera más elegante: pase una función anónima como devolución de llamada.

Por ejemplo:

Tengo una sola función para traducir el título, el contenido y el extracto de mis publicaciones. Entonces, necesito pasar a esta función principal algunos argumentos que dicen 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' );
});

Entonces, la función principal translate_textrecibe tantos parámetros como quiera, solo porque he pasado una función anónima como devolución de llamada.

Marcos Rezende
fuente
-1

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.

Pierre-Verthume Larivière
fuente