Come utilizzare do_action e ottenere un valore di ritorno?
Ecco il seguente scenario.
Aggiungo un'azione per pulire i log dal database:
add_action( 'myplugin_clean_logs', array( 'MyPlugin_Logs', 'clean_logs' ) );
Ora voglio eseguire questa azione periodicamente:
wp_schedule_event( current_time( 'timestamp' ), 'daily', 'myplugin_clean_logs' );
ed eseguirla manualmente:
do_action( 'myplugin_clean_logs' );
Il metodo MyPlugin_Logs::clean_logs
restituisce il conteggio delle righe interessate o false se qualcosa è andato nell'altra direzione.
Ora voglio visualizzare il numero di righe che sono state eliminate. Immaginerei qualcosa del genere:
$affected_rows = do_action( 'myplugin_clean_logs' );
echo $affected_rows . ' elementi sono stati eliminati.';
Ma poiché do_action
non restituirà alcun valore, non ho idea di come ottenere il valore di ritorno.
Dovrei eseguire il metodo direttamente in un'esecuzione manuale, ma utilizzare l'azione sugli eventi programmati?

La cosa interessante è che un filtro è uguale a un'azione, solo che restituisce un valore, quindi basta configurarlo come filtro invece:
add_filter( 'myplugin_clean_logs', array( 'MyPlugin_Logs', 'clean_logs' ) );
Poi qualcosa come:
$affected_rows = '';
$affected_rows = apply_filters( 'myplugin_clean_logs', $affected_rows );
dovrebbe passare $affected_rows
a clean_logs()
(e a qualsiasi altra funzione che hai collegato a myplugin_clean_logs
) e assegnare il valore restituito nuovamente a $affected_rows
.

votato negativamente perché questo è hacking del codice invece di sviluppare software. Se le azioni fossero solo un sottoinsieme dei filtri non ci sarebbe stato alcun bisogno di loro. Cron non può passare valori quindi non dovrebbe essere agganciato come un filtro anche se il codice problematico del core ti permette di fare questi trucchetti :)

Punto preso. Capisco l'intento delle due cose diverse, ma guardando il codice del core qui, tutta la faccenda di do_action()
non è altro che un elaborato hack di apply_filters()
:)

non è l'unico cattivo design nel core che in parte è ciò che porta alla confusione che genera domande come questa

Dobbiamo lavorare con quello che abbiamo, quindi mentre capisco il punto di vista di Mark penso ancora che questa sia una risposta legittima - a meno che ovviamente il core non cambi questo approccio in futuro, ma penso che sia improbabile a causa degli enormi problemi di retrocompatibilità che introdurrebbe.

Grazie, @TimMalone. Apprezzo l'obiezione di @mark-kaplun. La mia risposta descrive come aggirare il fatto che do_action()
non restituisce un valore piuttosto che come progettare una soluzione in linea con l'intento di do_action()
. Se qualcuno è in grado di fare ciò che chiede, quella risposta merita di essere quella accettata. La mia prima idea sarebbe di far sì che il metodo agganciato (supponendo che l'OP stia usando un design OOP per questo plugin) inserisca il suo risultato in una proprietà protetta della classe del plugin e poi scrivere un rapido getter per estrarlo in un secondo momento. Ma è solo un'idea improvvisata!

@Casper la documentazione di wordpress distingue esplicitamente tra azioni e filtri. Per quanto ho capito, un filtro è lì per filtrare effettivamente le cose ed è come tale più uno strumento che un esecutore. Forse questa è solo teoria e più una differenza di design del codice che un caso reale. All'inizio ho avuto un'idea simile di passare una variabile per riferimento (anche se non l'ho testato, per vedere se funziona), l'ho evitata per non incasinare il codice.

@TimMalone, a volte quando hai un problema di codifica confuso dovresti fermarti e chiederti se è un problema di codifica o un problema di design

@Aley, scusa in realtà avevo scritto un commento alla domanda ma apparentemente ho dimenticato di inviarlo, ma puoi capire cosa penso (devi gestirlo diversamente in entrambi i casi) dai commenti qui

Perché non usare invece una chiamata a funzione PHP, in questo modo non c'è bisogno di do_action o apply_filters. Inserisci la funzione nel file functions.php.

Questa è una domanda molto vecchia, ma per rispondere alla domanda originale "Come fare do_action e ottenere un valore di ritorno?" per chiunque stia cercando, puoi farlo utilizzando l'output buffering.
ob_start();
do_action( 'myplugin_clean_logs' );
$action_data = ob_get_clean();
In questo modo puoi memorizzare il contenuto di do_action in una variabile.

Non ho mai usato questa funzione e non l'ho testata, ma potrebbe funzionare? do_action_ref_array().
function myplugin_clean_logs_fn() {
$args = array(
'param1' => 'val1',
'param2' => 'val2',
'affected_rows' => 0,
);
do_action_ref_array( 'myplugin_clean_logs', &$args );
return $args['affected_rows'];
}
// CHIAMALA
$affected_rows = my_plugin_clean_logs();
echo $affected_rows .' rig'. ($args['affected_rows']*1===1?'a':'he') .' cancellata.';
// PROGRAMMALA
add_action('myplugin_clean_logs_call_fn', 'myplugin_clean_logs_fn');
wp_schedule_event( current_time( 'timestamp' ), 'daily', 'myplugin_clean_logs_call_fn' );
// UN FILTRO DI ESEMPIO
add_action('myplugin_clean_logs', function($args) {
// Processo di pulizia
// Per ogni log interessato, incrementa $args['affected_rows'] di conseguenza
}, 10, 3);
Se non funziona, perché non filtrare semplicemente la cosa come ha suggerito Caspar? Voglio dire, questo è lo scopo di un filtro, e in questo caso il numero di righe interessate è ciò che viene filtrato. (Mi manca il vecchio MortCore. Qualcuno ricorda come gestiva i valori di ritorno, il passaggio per riferimento e gli argomenti con una singola funzione a tre parametri?)

Questa è una risposta pessima, poiché passare e modificare valori per riferimento è una pratica davvero sconsigliata. Sinceramente, questa risposta non fornisce alcun valore nel contesto della domanda e dovrebbe probabilmente essere rimossa o trasformata in un commento. Inoltre, utilizzare funzioni anonime con gli hook è altrettanto sconsigliato, poiché le rende impossibili da scollegare.

Concordo per le stesse ragioni sopra citate, che questa non sia una strada raccomandata. Se per qualche motivo hai bisogno di ottenere un valore di ritorno da un'azione e ti serve qualcosa di rapido e sporadico, preferirei la soluzione di Caspar. Se stai sviluppando qualcosa con un ciclo di vita davanti, cercerei un modo più robusto. A pensarci bene, che ne dici degli admin notices? https://developer.wordpress.org/reference/hooks/admin_notices/
