Come Passare Variabili Esterne a Filtri/Azioni
Mi trovo nella necessità di passare dati personalizzati a un filtro fornito da un plugin di terze parti. Tutti i modi che ho visto per farlo sono davvero complicati e difficili da comprendere.
Prendi questo esempio:
$score = 42; //Un calcolo complesso che non voglio ripetere.
function add_score_to_title($title) {
return 'Risultati Quiz (' . $score . '/') - ' . $title;
}
add_filter( 'aioseop_title_single', 'add_score_to_title');
Come posso passare la variabile $score
alla funzione add_score_to_title()
?
Quello che ho finito per fare è stato aggiungere la mia variabile all'oggetto globale $wp
. Quindi si ottiene questo:
global $wp;
$score = 42; //Un calcolo complesso che non voglio ripetere.
$wp->some_random_name_for_score = $score;
function add_score_to_title($title) {
global $wp;
$score = $wp->some_random_name_for_score;
return 'Risultati Quiz (' . $score . '/') - ' . $title;
}
add_filter( 'aioseop_title_single', 'add_score_to_title');
Sporco? Forse. Semplice? Sì! Ci sono svantaggi in questa tecnica? Vi prego di discuterne.
AGGIORNAMENTO Ecco il codice completo in questione -> http://pastebin.com/fkSXY04m
Hai almeno due opzioni:
- Globalizzare la variabile desiderata e poi riferirsi ad essa all'interno del callback
- Includere la logica di calcolo del punteggio in una funzione, quindi riferirsi ad essa all'interno del callback
Globalizzare la Variabile
<?php
global $score;
$score = 42; //Un calcolo complesso che non voglio ripetere.
function add_score_to_title($title) {
global $score;
return 'Risultati Quiz (' . $score . '/') - ' . $title;
}
add_filter( 'aioseop_title_single', 'add_score_to_title');
?>
Includere il Calcolo del Punteggio
Se hai bisogno del calcolo del punteggio solo all'interno del filtro, puoi inserire la logica direttamente nel callback:
<?php
function add_score_to_title($title) {
$score = 0;
$questions = get_quiz_result_questions();
$total_questions = 0;
foreach( $questions as $question ) {
$order = $question->order;
if( $order >= 100 ) {
break;
}
if( $question->correct == $_POST['Q'][$order] ) {
$score++;
}
$total_questions++;
return 'Risultati Quiz (' . $score . '/') - ' . $title;
}
add_filter( 'aioseop_title_single', 'add_score_to_title');
?>
Ancora meglio, potresti racchiudere il calcolo del punteggio in una funzione separata e poi chiamarla all'interno del tuo callback:
<?php
function wpse48677_get_score() {
$score = 0;
$questions = get_quiz_result_questions();
$total_questions = 0;
foreach( $questions as $question ) {
$order = $question->order;
if( $order >= 100 ) {
break;
}
if( $question->correct == $_POST['Q'][$order] ) {
$score++;
}
$total_questions++;
$output['score'] = $score;
$output['total_questions'] = $total_questions;
return $output;
}
function add_score_to_title($title) {
$score_results = wpse48677_get_score();
$score = $score_results['score'];
return 'Risultati Quiz (' . $score . '/') - ' . $title;
}
add_filter( 'aioseop_title_single', 'add_score_to_title');
?>
Se hai problemi a referenziare l'oggetto $_POST
, puoi anche registrare la tua variabile di query e poi usare get_query_var()
internamente per ottenere i dati:
function add_score_query_vars( $query_vars ) {
$query_vars[] = 'Q';
return $query_vars;
}
add_filter( 'query_vars', 'add_score_query_vars' );
Con questo impostato, $_POST['Q']
può essere sostituito con get_query_var('Q')
.

Questo non ha nulla a che fare con il numero di argomenti passati alla funzione da apply_filters...

Ho provato il metodo #1 che hai menzionato di globalizzare la variabile. Non funziona. Il parametro accepted args non mi aiuta neanche poiché non ho controllo su quali variabili vengono passate alla funzione di callback.

Scusa avevi ragione. Ho calcolato prima $score
e poi l'ho globalizzata. Non c'è da stupirsi che non funzionasse. Grazie!

-1. La prima opzione espone una variabile nello stato globale, la seconda opzione non funziona...

Aggiornato per riflettere il mio errore sulla seconda opzione. Ma cosa c'è di male nell'esporre una variabile globale? È sicuramente meglio che usare una funzione anonima in un callback. :)

No, non lo è. E qui ci sono alcune ragioni per cui dovresti evitare questa pratica. Forse va bene per il suo caso specifico, ma se qualcuno sviluppasse davvero un plugin pubblico usando la tua soluzione?

"Le variabili globali sono il male"? Davvero? Allora tutto il codice di WordPress dovrebbe essere riscritto, visto che si basa su diverse variabili globali.

Esatto. Questa è una delle ragioni per cui il codice base di WP è tra i peggiori sul web. Comunque, WP ha una scusa - la necessaria compatibilità con plugin progettati per versioni più vecchie. Tu non hai questo problema :)

Sì... lascerò perdere questo punto. Grazie per aver segnalato il problema con la seconda opzione; l'ho rimossa dalla domanda. Mantengo la mia posizione sull'accettabilità dell'uso di variabili globali. Se sapessi come viene generato o restituito l'output del Plugin, potrei probabilmente offrire una soluzione migliore.

Vedi la risposta aggiornata; dopo aver esaminato il Pastebin, ho proposto due metodi che preferirei invece di utilizzare una variabile globale.

Meglio, ma vuole che il "punteggio" sia accessibile più avanti nello script, senza ricalcolarlo, quindi l'uso di una variabile "statica" ha senso in questo caso.

Utilizzando una funzione per calcolare il punteggio: non si potrebbe memorizzare il calcolo nella cache degli oggetti?

autunno 2015 e WP fa ancora affidamento su variabili globali dannose. La scusa è diventata troppo vecchia. E +1 per il suggerimento sulla globalizzazione. Nel mio caso la callback aveva bisogno di accedere a $user
che ho dovuto globalizzare visto che la mia chiamata apply_filters
veniva inizializzata all'interno di una funzione.

Queste globali sono dannose, la gente deve rilassarsi. Mi piace molto questa risposta. L'OP ha chiesto come passare variabili tra funzioni. Questa risposta spiega diversi modi per farlo. Inizia con le globali, che è meglio evitare, ma rimangono una cosa che esiste e risolve il problema in questione. Poi la risposta procede spiegando diverse opzioni migliori che potrebbero funzionare in alcune circostanze.

function add_score_to_title($title = false) {
static $score = false;
if($score === false){
// esegui il calcolo
}
// chiamata del plugin (filtro)
if($title !== false)
return 'Risultati del Quiz (' . $score . ') - ' . $title;
// tua chiamata
return $score;
}
Chiama la funzione in qualsiasi punto del tuo script per ottenere il punteggio, verrà calcolato solo una volta.
Un altro modo, utilizzando funzioni anonime:
// esegui il calcolo
$score = 'xxx';
add_filter('aioseop_title_single', function($title) use($score){
return 'Risultati del Quiz (' . $score . ') - ' . $title;
});

Le funzioni anonime non dovrebbero essere utilizzate nelle chiamate add_filter()
o add_action()
. Non possono essere rimosse tramite remove_function()
.

Intendi remove_filter, che viene principalmente utilizzato per rimuovere i filtri integrati, non i filtri aggiunti da plugin/temi...

Il seguente esempio mostra la variabile $my_calculation
nell'ambito globale, tuttavia dalla nostra funzione locale dobbiamo dichiarare global $my_calculation
per poter accedere alla variabile nell'ambito globale.
<?php
$my_calculation = 'risultato!';
function my_function() {
global $my_calculation;
return $my_calculation;
}
add_filter( 'function_something_here', 'my_function');
?>
Questo è solo uno dei modi per procedere e sembra essere ordinato. Funzionerebbe per te?

Una dichiarazione in meno di "global". Guarda il suo secondo esempio, dichiara global $wp due volte!

Sei in grado di print
o echo
il tuo risultato per assicurarti che la tua funzione stia effettivamente funzionando prima di passarla al filtro?

Ops! Rendere globale $score
funziona davvero. Ho sbagliato e ho impostato prima $score
e poi l'ho globalizzato, cosa che chiaramente non funziona. Facendolo nel modo corretto, cioè globalizzando prima $score
e poi assegnandogli un valore, funziona come previsto. Grazie a tutti.
