Passando un parametro alle funzioni di filtro e azione


52

È un modo per passare i miei parametri alla funzione in add_filtero add_action. Ad esempio, dai un'occhiata al seguente codice:

function my_content($content, $my_param)
{
do something...
using $my_param here ...
return $content;
}
add_filter('the_content', 'my_content', 10, 1);

Posso passare il mio parametro? qualcosa di simile a:

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

o

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

Risposte:


78

Di default questo non è possibile. Ci sono soluzioni alternative se lo fai nel modo OOP.
È possibile creare una classe per archiviare i valori che si desidera utilizzare in seguito.

Esempio:

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

Ora puoi chiamare la classe con qualsiasi funzione tu voglia - se la funzione esiste da qualche parte, verrà chiamata con i parametri memorizzati.

Creiamo una funzione demo ...

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

... e usalo una volta ...

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

… e di nuovo …

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

Produzione:

inserisci qui la descrizione dell'immagine

La chiave è la riusabilità : puoi riutilizzare la classe (e nei nostri esempi anche la funzione).

PHP 5.3+

Se è possibile utilizzare una versione 5.3 di PHP o chiusure più recenti, sarà molto più semplice:

$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>";
}

Il rovescio della medaglia è che non è possibile scrivere unit test per chiusure. 


17
Non solo ottieni un voto positivo per una risposta di qualità a un problema che dovrebbe avere una soluzione integrata nel core di WP , ma ne ottieni anche uno per tornare cinque mesi dopo per aggiornare la tua risposta con l'esempio di chiusura di PHP 5.3+.
Adam,

1
Risposta eccellente! Ma come posso fare per rimuovere questo filtro creato da questa funzione anonima in un secondo momento?
Vinicius Tavares,

2
@ViniciusTavares Non puoi. Pensa prima di usarlo. :)
fuxia

5
Si noti tuttavia che se si salva la funzione anonima in una variabile (ad es. $func = function() use ( $param1 ) { $param1; };E add_action( $func, 11);), è possibile rimuoverla tramiteremove_action( $func, 11 );
bonger

1
Ma non è consigliabile utilizzare funzioni anonime su plugin o temi che stai rilasciando al mondo (puoi usarli sui tuoi progetti). Il problema è che non sarai in grado di sganciarli. Qualunque sia il tuo approccio, decidi di seguirlo dovrebbe essere inattaccabile in seguito.
Mueyiwa Moses Ikomi,

1

Creare una funzione con gli argomenti necessari che restituiscono una funzione. Passa questa funzione (funzione anonima, nota anche come chiusura) all'hook wp.

Indicato qui per un avviso di amministrazione nel backend di 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);

1

Usa le funzioni anonime 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);

1

So che il tempo è passato, ma ho avuto qualche problema con il passaggio del mio parametro fino a quando ho scoperto che il quarto parametro in add_filter è il numero di parametri passati compreso il contenuto da modificare. Quindi, se passi 1 parametro aggiuntivo, il numero dovrebbe essere 2 e non 1 nel tuo caso

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

e usando

function my_content($content, $my_param) {...}

1

Il modo corretto, veramente breve ed efficiente per passare qualsiasi numero di argomenti ai filtri e alle azioni WP è quello di @Wesam Alalem qui , che utilizza la chiusura.

Vorrei solo aggiungere che potresti renderlo ancora più chiaro e molto più flessibile separando il metodo effettivo da una chiusura anonima. Per questo basta chiamare il metodo dalla chiusura come segue (esempio modificato dalla risposta di @Wesam Alalem).

In questo modo puoi scrivere la logica lunga o complicata che desideri lessicamente al di fuori della chiusura che usi per chiamare l'autore effettivo.

// ... 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;
}

0

se crei il tuo hook, ecco un esempio.

// 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
}

quindi implementare hook:

// [ https://codex.wordpress.org/Function_Reference/apply_filters ]
echo apply_filters( 'filter_name', $first, $second, $third );

Questo non passa le informazioni dalla registrazione al callback. Indica solo quanti parametri può accettare il callback.
fuxia

@fuxia, puoi suggerire una semplice modifica in modo che le informazioni vengano passate? Uno si limiterebbe a fissare i valori param dopo il 3?
SherylHohman,

0

Puoi sempre usare il globale no?

  global $my_param;

Questo non fornisce una risposta alla domanda. Una volta che hai una reputazione sufficiente , sarai in grado di commentare qualsiasi post ; fornire invece risposte che non richiedono chiarimenti da parte del richiedente . - Dalla recensione
cjbj

@cjbj In realtà lo fa. La domanda è: i parametri possono essere passati alla "funzione" che si trova in add_filter o add_action. Non era chiaro se l'utente volesse passarlo nella funzione add_filter o add_action stessa anche se questo è il presupposto. :)
samjco,

0

Nonostante si chiami direttamente una funzione, farlo in un modo più elegante: passare una funzione anonima come callback.

Per esempio:

Ho una sola funzione per tradurre titolo, contenuto ed estratto dai miei post. Quindi, devo passare a questa funzione principale alcuni argomenti che dicono chi sta chiamando.

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

Quindi, la funzione principale translate_textriceve tutti i parametri che voglio, solo perché ho passato una funzione anonima come callback.


-1

Speravo di fare lo stesso, ma dal momento che non è possibile immagino che una semplice soluzione alternativa sia quella di chiamare una funzione diversa come add_filter('the_content', 'my_content_filter', 10, 1);

quindi my_content_filter () può semplicemente chiamare my_content () passando qualsiasi argomento voglia.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.