Passare un parametro alle funzioni filter e action
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)
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:
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.

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+.

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

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

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.

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

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

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

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:
- Il tuo codice potrebbe non essere OOP
- 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;
}

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 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. :)

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.

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.

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

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

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

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) {...}

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.

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.
