Transmiterea unui parametru către funcțiile de filtru și acțiune
Există o modalitate de a transmite parametrii mei proprii către funcția din add_filter
sau add_action
.
De exemplu, uitați-vă la următorul cod:
function my_content($content, $my_param)
{
// fă ceva...
// folosește $my_param aici ...
return $content;
}
add_filter('the_content', 'my_content', 10, 1);
Pot să transmit propriul parametru? ceva de genul:
add_filter('the_content', 'my_content($my_param)', 10, 1)
sau
add_filter('the_content', 'my_content', 10, 1, $my_param)
În mod implicit, acest lucru nu este posibil. Există soluții alternative dacă o faci în stilul OOP.
Poți crea o clasă pentru a stoca valorile pe care dorești să le folosești ulterior.
Exemplu:
/**
* Stochează o valoare și apelează orice funcție existentă cu această valoare.
*/
class WPSE_Filter_Storage
{
/**
* Populat de __construct(). Folosit de __call().
*
* @type mixed Orice tip de care ai nevoie.
*/
private $values;
/**
* Stochează valorile pentru utilizare ulterioară.
*
* @param mixed $values
*/
public function __construct( $values )
{
$this->values = $values;
}
/**
* Interceptează toate apelurile de funcții, cu excepția __construct().
*
* Atenție: Chiar dacă funcția este apelată cu un singur șir de caractere ca
* argument, acesta va fi trimis ca un array.
*
* @param string $callback Numele funcției
* @param array $arguments
* @return mixed
* @throws InvalidArgumentException
*/
public function __call( $callback, $arguments )
{
if ( is_callable( $callback ) )
return call_user_func( $callback, $arguments, $this->values );
// Funcție apelată greșit.
throw new InvalidArgumentException(
sprintf( 'Fișier: %1$s<br>Linia %2$d<br>Nu poate fi apelată: %3$s',
__FILE__, __LINE__, print_r( $callback, TRUE )
)
);
}
}
Acum poți apela clasa cu orice funcție dorești – dacă funcția există undeva, aceasta va fi apelată cu parametrii tăi stocați.
Să creăm o funcție demo …
/**
* Funcție de filtrare.
* @param array $content
* @param array $numbers
* @return string
*/
function wpse_45901_add_numbers( $args, $numbers )
{
$content = $args[0];
return $content . '<p>' . implode( ', ', $numbers ) . '</p>';
}
… și să o folosim o dată …
add_filter(
'the_content',
array (
new WPSE_Filter_Storage( array ( 1, 3, 5 ) ),
'wpse_45901_add_numbers'
)
);
… și din nou …
add_filter(
'the_content',
array (
new WPSE_Filter_Storage( array ( 2, 4, 6 ) ),
'wpse_45901_add_numbers'
)
);
Rezultat:
Cheia este reutilizarea: Poți reutiliza clasa (și în exemplele noastre, de asemenea, funcția).
PHP 5.3+
Dacă poți folosi o versiune PHP 5.3 sau mai nouă, closure-urile vor face acest lucru mult mai ușor:
$param1 = '<p>Aceasta funcționează!</p>';
$param2 = 'Și aceasta funcționează!';
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
);
/**
* Adaugă un șir de caractere la conținutul postării
*
* @param string $content
* @param string $string Acesta este $param2 în exemplul nostru.
* @return string
*/
function t5_param_test( $content, $string )
{
return "$content <p><b>$string</b></p>";
}
Dezavantajul este că nu poți scrie teste unitare pentru closure-uri.

Nu doar că primești un vot în sus pentru un răspuns de calitate la o problemă care ar trebui să aibă o soluție încorporată în nucleul WP, dar primești și unul pentru că ai revenit după cinci luni să îți actualizezi răspunsul cu exemplul de închidere (closure) PHP 5.3+.

Răspuns excelent! Dar cum pot face să elimin acest filtru creat de această funcție anonimă mai târziu?

Totuși, rețineți că dacă salvați funcția anonimă într-o variabilă (de exemplu $func = function() use ( $param1 ) { $param1; };
și add_action( $func, 11);
) atunci o puteți elimina prin remove_action( $func, 11 );

Dar nu este recomandat să folosiți funcții anonime în plugin-uri sau teme pe care le lansați public (le puteți folosi în proiectele personale). Problema cu aceasta este că nu veți putea să le deconectați. Orice abordare alegeți ar trebui să poată fi deconectată ulterior.

Folosește funcții anonime în PHP:
$my_param = 'numele temei mele';
add_filter('the_content', function ($content) use ($my_param) {
//$my_param este acum disponibil pentru tine
if (is_page()) {
$content = $my_param . ':<br>' . $content;
}
return $content;
}, 10, 1);

Modul corect, foarte scurt și cel mai eficient de a transmite orice număr de argumente către filtrele și acțiunile din WordPress este cel propus de @Wesam Alalem aici, care utilizează o funcție anonimă (closure).
Aș adăuga doar că puteți face acest lucru și mai clar și mult mai flexibil separând logica principală de funcția anonimă. Pentru aceasta, pur și simplu apelați metoda din closure, după cum urmează (exemplu modificat din răspunsul lui @Wesam Alalem).
În acest fel, puteți scrie oricât de lungă sau complicată logica doriți, în afara closure-ului folosit pentru a apela funcția principală.
// ... în interiorul unei clase
private function myMethod() {
$my_param = 'numele temei mele';
add_filter('the_content', function ($content) use ($my_param) {
// Acesta este closure-ul anonim care permite transmiterea
// oricărui număr de parametri prin cuvântul cheie 'use'.
// Acesta este doar o singură linie de cod.
// $my_param este disponibil acum prin 'use' de mai sus
return $this->doThings($content, $my_param);
}, 10, 2);
}
private function doThings($content, $my_param) {
// Aici puteți apela alte metode pentru a face lucruri suplimentare
// oricât de complicate doriți.
$morethings = '';
if ($content = 'alte lucruri') {
$morethings = (new MoreClass())->get();
}
return $my_param . ':<br>' . $content . $morethings;
}

Crează o funcție cu argumentele necesare care returnează o funcție. Transmite această funcție (funcție anonimă, cunoscută și sub numele de closure) la hook-ul wp.
Exemplu prezentat pentru un mesaj de administrare (admin notice) în backend-ul 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('Mesaj');
add_action('admin_notices', $func);

După cum s-a menționat în alte răspunsuri, transmiterea unui parametru către funcția de callback nu este posibilă în mod implicit. OOP și funcțiile anonime din PHP sunt soluții alternative, DAR:
- Codul tău poate să nu fie OOP
- Poate fi necesar să elimini acel filtru ulterior
Dacă acesta este cazul tău, există o altă soluție pe care o poți folosi: utilizează funcțiile add_filter
și apply_filters
pentru a face acel parametru disponibil în funcția de callback:
// Soluție alternativă pentru a "salva" parametrul care trebuie transmis funcției de callback.
add_filter( 'pass_param', function() use ( $param ){ return $param; } );
// Conectează funcția ta la filtrul pe care dorești să-l filtrezi.
add_filter( 'actual_filter', 'myCallback' );
// Funcția ta de callback care filtrează efectiv ceea ce dorești.
function myCallback()
{
// Obține parametrul pe care nu am putut să-l transmitem direct acestei funcții.
$param = apply_filters( 'pass_param', '' );
// Folosește parametrul transmis indirect pentru a filtra.
return $param;
}

Acest lucru nu oferă un răspuns la întrebare. Odată ce vei avea suficientă reputație vei putea să comentezi orice postare; în schimb, oferă răspunsuri care nu necesită clarificări din partea celui care întreabă. - Din Recenzie

@cjbj De fapt, oferă. Întrebarea este dacă parametrii pot fi transmiși "funcției" care se află în add_filter sau add_action. Nu era clar dacă utilizatorul dorea să îi transmită în funcția add_filter sau add_action în sine, deși aceasta este presupunerea. :)

În loc să apelezi o funcție direct, fă-o într-un mod mai elegant: folosește o funcție anonimă ca callback.
De exemplu:
Am o singură funcție pentru a traduce titlul, conținutul și rezumatul postărilor mele. Așadar, trebuie să transmit funcției principale câteva argumente care să indice cine o apelează.
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' );
});
Astfel, funcția principală translate_text
primește câți parametri doresc, tocmai pentru că am folosit o funcție anonimă ca callback.

Sunt de acord că răspunsul lui fuxia de mai sus oferă abordările preferate. Dar în timp ce încercam să înțeleg soluția OOP, am dat peste o modalitate de a o face care setează și apoi anulează atât filtrul, cât și o variabilă globală:
function my_function() {
// Declară variabila globală și setează-o la o valoare
global $my_global;
$my_global = 'ceva';
// Adaugă filtrul
add_filter( 'some_filter', 'my_filter_function' );
// Execută orice ai nevoie de filtrul respectiv
echo $filtered_stuff;
// Elimină filtrul (pentru a nu afecta altceva care se execută mai târziu)
remove_filter( 'some_filter', 'my_filter_function' );
// Anulează variabila globală (deoarece nu ne plac variabilele globale rătăcitoare în cod)
my_unset_function( 'my_global' );
}
function my_filter_function( $arg ) {
// Declară variabila globală
global $my_global;
// Folosește $my_global pentru a face ceva cu $arg
$arg = $arg . $my_global;
return $arg;
}
function my_unset_function( $var_name ) {
// Declară variabila globală
$GLOBALS[$var_name];
// Anulează variabila globală
unset($GLOBALS[$var_name];
}
Sunt un dezvoltator fără pregătire formală și lucrez strict pe propriile site-uri, așa că vă rog să luați această schiță cu rezerve. Funcționează pentru mine, dar dacă este ceva greșit în ceea ce fac aici, aș fi recunoscător dacă cineva mai cunoscător ar indica problema.

În soluția mea OOP am folosit simplu o variabilă membru a clasei care este apelată în funcția de callback. În acest exemplu post_title este filtrat după un termen de căutare:
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;
}
}

dacă creezi propriul tău hook, iată un exemplu.
// să presupunem că avem trei parametri [ https://codex.wordpress.org/Function_Reference/add_filter ]
add_filter( 'filter_name', 'my_func', 10, 3 );
my_func( $first, $second, $third ) {
// cod
}
apoi implementează hook-ul:
// [ https://codex.wordpress.org/Function_Reference/apply_filters ]
echo apply_filters( 'filter_name', $first, $second, $third );

Acest lucru nu transferă informațiile de la înregistrare către callback. Doar specifică câți parametri poate accepta callback-ul.

Știu că a trecut ceva timp, dar am avut o problemă cu transmiterea propriului meu parametru până când am descoperit că al 4-lea parametru din add_filter reprezintă numărul de parametri transmiși inclusiv conținutul de modificat. Deci dacă transmiți 1 parametru suplimentar, numărul ar trebui să fie 2 și nu 1 în cazul tău
add_filter('the_content', 'my_content', 10, 2, $my_param)
și folosind
function my_content($content, $my_param) {...}

Ești sigur că poți pasa un al cincilea parametru la add_filter
? Conform documentației oficiale, acest lucru nu este corect. Ai testat răspunsul tău? Te rog să fii atent la răspândirea informațiilor eronate.

Am sperat să fac același lucru, dar din moment ce nu este posibil, cred că o soluție simplă ar fi să apelez o altă funcție, cum ar fi
add_filter('the_content', 'my_content_filter', 10, 1);
Apoi, my_content_filter() poate pur și simplu să apeleze my_content() transmitându-i orice argument dorește.
