Passare un parametro alle funzioni filter e action

17 mar 2012, 13:24:53
Visualizzazioni: 56.4K
Voti: 64

Esiste un modo per passare i propri parametri alla funzione in add_filter o add_action. Per esempio dai un'occhiata al seguente codice:

function my_content($content, $my_param)
{
// fai qualcosa...
// usa $my_param qui ...
return $content;
}
add_filter('the_content', 'my_content', 10, 1);

Posso passare il mio parametro personalizzato? Qualcosa come:

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

oppure

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

puoi utilizzare $_SESSION per memorizzare e recuperare i parametri.

Sunil Kumar Sunil Kumar
10 lug 2020 12:23:15
Tutte le risposte alla domanda 12
5
98

Di default non è possibile farlo. Esistono soluzioni alternative se lo si fa in modo OOP.
Si potrebbe creare una classe per memorizzare i valori che si desidera utilizzare in seguito.

Esempio:

/**
 * Memorizza un valore e chiama qualsiasi funzione esistente con questo valore.
 */
class WPSE_Filter_Storage
{
    /**
     * Riempito da __construct(). Utilizzato da __call().
     *
     * @type mixed Qualsiasi tipo di cui hai bisogno.
     */
    private $values;

    /**
     * Memorizza i valori per un uso successivo.
     *
     * @param  mixed $values
     */
    public function __construct( $values )
    {
        $this->values = $values;
    }

    /**
     * Intercetta tutte le chiamate di funzione tranne __construct().
     *
     * Attenzione: Anche se la funzione viene chiamata con una sola stringa come
     * argomento, sarà inviata come un array.
     *
     * @param  string $callback Nome della funzione
     * @param  array  $arguments
     * @return mixed
     * @throws InvalidArgumentException
     */
    public function __call( $callback, $arguments )
    {
        if ( is_callable( $callback ) )
            return call_user_func( $callback, $arguments, $this->values );

        // Funzione chiamata errata.
        throw new InvalidArgumentException(
            sprintf( 'File: %1$s<br>Line %2$d<br>Non chiamabile: %3$s',
                __FILE__, __LINE__, print_r( $callback, TRUE )
            )
        );
    }
}

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

Creiamo una funzione demo...

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

... e usiamola una volta...

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

... e ancora...

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

Output:

enter image description here

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

PHP 5.3+

Se puoi usare una versione di PHP 5.3 o più recente, le closure renderanno tutto molto più semplice:

$param1 = '<p>Questo funziona!</p>';
$param2 = 'Anche questo funziona!';

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

/**
 * Aggiunge una stringa al contenuto del post
 *
 * @param  string $content
 * @param  string $string Questo è $param2 nel nostro esempio.
 * @return string
 */
function t5_param_test( $content, $string )
{
    return "$content <p><b>$string</b></p>";
}

Lo svantaggio è che non puoi scrivere unit test per le closure.

17 mar 2012 20:32:12
Commenti

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 essere tornato cinque mesi dopo per aggiornare la tua risposta con l'esempio di chiusura PHP 5.3+.

Adam Adam
17 nov 2013 09:17:38

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

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

@ViniciusTavares Non puoi. Pensa bene prima di usarlo. :)

fuxia fuxia
12 ago 2014 11:17:41

Tieni presente però che se salvi la funzione anonima in una variabile (ad esempio $func = function() use ( $param1 ) { $param1; }; e add_action( $func, 11);) allora puoi rimuoverla tramite remove_action( $func, 11 );

bonger bonger
2 mag 2015 21:49:18

Ma non è consigliabile utilizzare funzioni anonime in plugin o temi che rilasci al pubblico (puoi usarle nei tuoi progetti personali). Il problema è che non sarai in grado di scollegarle. Qualunque approccio decidi di utilizzare dovrebbe poter essere scollegato in seguito.

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

Utilizza le funzioni anonime di PHP:

$my_param = 'my theme name';
add_filter('the_content', function ($content) use ($my_param) {
    //$my_param è ora disponibile per te
    if (is_page()) {
        $content = $my_param . ':<br>' . $content;
    }
    return $content;
}, 10, 1);
23 gen 2016 12:26:32
0

Il modo corretto, davvero breve e più efficiente per passare qualsiasi numero di argomenti ai filtri e alle azioni di WordPress è quello proposto da @Wesam Alalem qui, che utilizza una chiusura (closure).

Aggiungerei solo che potresti renderlo ancora più chiaro e molto più flessibile separando il metodo effettivo che esegue l'operazione dalla chiusura anonima. Per farlo, basta chiamare il metodo dalla chiusura come segue (esempio modificato dalla risposta di @Wesam Alalem).

In questo modo puoi scrivere una logica lunga o complicata quanto vuoi, lessicalmente al di fuori della chiusura che usi per chiamare l'effettivo esecutore.

// ... all'interno di una classe

private function myMethod() {
    $my_param = 'il nome del mio tema';
    add_filter('the_content', function ($content) use ($my_param) {
        // Questa è la chiusura anonima che permette di passare
        // qualsiasi numero di parametri desideri tramite la keyword 'use'.
        // Questa è solo una riga di codice.
        // $my_param è ora disponibile grazie alla keyword 'use' sopra
        return $this->doThings($content, $my_param);
    }, 10, 2);
}

private function doThings($content, $my_param) {
    // Chiama qui qualche altro metodo per fare altre operazioni
    // per quanto complicate tu voglia.
    $morethings = '';
    if ($content = 'alcune altre cose') {
        $morethings = (new MoreClass())->get();
    }
    return $my_param . ':<br>' . $content . $morethings;
}
14 ott 2018 19:10:58
0

Crea una funzione con gli argomenti necessari che restituisce un'altra funzione. Passa questa funzione (funzione anonima, anche conosciuta come closure) all'hook di WordPress.

Mostrato qui per un admin notice 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('Messaggio');
add_action('admin_notices', $func);
20 gen 2016 20:53:14
0

Come menzionato in altre risposte, passare un parametro alla funzione di callback non è possibile di default. La programmazione OOP e le funzioni anonime di PHP sono soluzioni alternative MA:

  1. Il tuo codice potrebbe non essere OOP
  2. Potresti aver bisogno di rimuovere quel filtro successivamente

Se questo è il tuo caso, esiste un'altra soluzione alternativa che puoi utilizzare: sfrutta le funzioni add_filter e apply_filters per rendere disponibile il parametro che vuoi passare nella funzione di callback:

// Soluzione alternativa per "salvare" il parametro da passare alla tua funzione di callback.
add_filter( 'pass_param', function() use ( $param ){ return $param; } );

// Collega la tua funzione al filtro che vuoi applicare.
add_filter( 'actual_filter', 'myCallback' );

// La tua funzione di callback che effettivamente filtra ciò che vuoi filtrare.
function myCallback()
{
   // Ottieni il parametro che non siamo riusciti a passare direttamente a questa funzione.
   $param = apply_filters( 'pass_param', '' );

   // Fai quello che vuoi con il parametro passato indirettamente per poterlo usare nel filtro.
   return $param;
}
7 mag 2020 12:12:35
3

Puoi sempre usare le variabili globali..

  global $my_param;
25 ago 2017 02:47:08
Commenti

Questo non fornisce una risposta alla domanda. Una volta che avrai sufficiente reputazione potrai commentare qualsiasi post; invece, fornisci risposte che non richiedano chiarimenti da parte di chi ha posto la domanda. - Da Revisione

cjbj cjbj
25 ago 2017 07:25:56

@cjbj In realtà lo fa. La domanda è se i parametri possono essere passati alla "funzione" che è in add_filter o add_action. Non era chiaro se l'utente volesse passarli nella funzione add_filter o add_action stessa anche se questa è l'assunzione. :)

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

Questo non è Jeopardy. Rispondere sotto forma di domanda è più appropriato per i commenti che per le risposte. Credo che questo sia ciò a cui si riferisce cjbj.

Jake Jake
9 dic 2020 18:40:25
0

Anziché chiamare direttamente una funzione, fallo in modo più elegante: passa una funzione anonima come callback.

Ad esempio:

Ho una singola funzione per tradurre il titolo, il contenuto e l'estratto dei miei articoli. Quindi, devo passare a questa funzione principale alcuni argomenti che indicano 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_text riceve tutti i parametri che voglio, semplicemente perché ho passato una funzione anonima come callback.

25 ott 2019 23:30:52
1

Sono d'accordo che la risposta di fuxia sopra fornisca gli approcci preferiti. Ma mentre cercavo di capire la soluzione OOP, mi sono imbattuto in un modo per farlo che imposta e poi rimuove sia il filtro che una variabile globale:

function my_function() {
    
    // Dichiaro la variabile globale e le assegno un valore
    global $my_global;
    $my_global = 'qualcosa';
        
    // Aggiungo il filtro
    add_filter( 'some_filter', 'my_filter_function' );
    
    // Faccio qualunque cosa per cui avevi bisogno del filtro
    echo $filtered_stuff; 
    
    // Rimuovo il filtro (per non interferire con altro codice che viene eseguito dopo)
    remove_filter( 'some_filter', 'my_filter_function' );

    // Rimuovo la variabile globale (perché non ci piacciono variabili globali che fluttuano nel codice)
    my_unset_function( 'my_global' );
    
}

function my_filter_function( $arg ) {
    
    // Dichiaro la variabile globale
    global $my_global;

    // Uso $my_global per fare qualcosa con $arg
    $arg = $arg . $my_global;

    return $arg;

}

function my_unset_function( $var_name ) {

    // Dichiaro la variabile globale
    $GLOBALS[$var_name];

    // Rimuovo la variabile globale
    unset($GLOBALS[$var_name];

}

Sono uno sviluppatore autodidatta e lavoro esclusivamente sui miei siti, quindi per favore prendi questo esempio con le pinze. Funziona per me, ma se c'è qualcosa di sbagliato in quello che sto facendo qui, sarei grato se qualcuno più esperto me lo facesse notare.

22 giu 2020 17:48:30
Commenti

Le variabili globali non sono protette: chiunque può impostarle su qualsiasi valore (pensa alle collisioni di nomi), e sono molto difficili da debuggare. In generale, sono considerate una cattiva pratica.

fuxia fuxia
22 giu 2020 19:21:30
0

Nella mia soluzione OOP ho semplicemente utilizzato una variabile membro della classe che viene chiamata nella funzione di callback. In questo esempio il post_title viene filtrato in base a un termine di ricerca:

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 lug 2020 21:49:39
2
-1

se crei il tuo hook personalizzato, ecco un esempio.

// supponiamo di avere tre parametri [ https://codex.wordpress.org/Function_Reference/add_filter ]
add_filter( 'filter_name', 'my_func', 10, 3 );
my_func( $first, $second, $third ) {
  // codice
}

poi implementa l'hook:

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

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

fuxia fuxia
18 mag 2015 01:15:01

@fuxia, puoi suggerire una modifica semplice in modo che le informazioni vengano effettivamente passate? Basterebbe aggiungere i valori dei parametri dopo il 3?

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

So che è passato del tempo, ma ho avuto qualche problema con il passaggio del mio parametro finché non ho scoperto che il 4° parametro in add_filter è il numero di parametri passati incluso 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) {...}
16 feb 2017 14:48:58
Commenti

Sei sicuro di poter passare un quinto parametro a add_filter? Secondo la documentazione ufficiale, questo non è corretto. Hai testato la tua risposta? Per favore, sii attento a diffondere informazioni errate.

plong0 plong0
23 set 2020 22:02:20

Non funziona in questo modo, e i miei test finora confermano che non funziona così.

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

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

poi my_content_filter() può semplicemente chiamare my_content() passando qualsiasi argomento desideri.

12 dic 2017 23:24:31