Come gestire al meglio le azioni delle pagine dei plugin personalizzati?
Mi imbatto costantemente nello stesso fastidio, quindi ho pensato di vedere se ci sono idee o esperienze a riguardo...
Ho creato un plugin che utilizza la sua pagina di amministrazione. È necessario. Ora che ho sistemato la questione di WP_List_Table(), devo dire che è fantastico... ma...
Le pagine dei plugin personalizzati vengono sempre caricate come admin.php?page=...
a meno che non voglia caricarle direttamente dalla directory del plugin, cosa che non voglio. Ora, se eseguo un'azione da quella pagina, devo elaborarla in qualche modo e poi reindirizzare alla pagina senza il parametro dell'azione. Non importa se uso GET o POST.
Su tutte le sue pagine interne, WordPress fa questo sulla stessa pagina: controlla se c'è un'azione, in caso affermativo la elabora e poi reindirizza a se stesso senza l'azione. Questo è possibile perché su queste pagine l'admin-header
non è stato ancora caricato.
Se provi a farlo sulla tua pagina personalizzata, però, metà dell'interfaccia di amministrazione è già stata inviata al browser, quindi un redirect non è più possibile. Chiaramente, la soluzione è fare POST/GET direttamente su un'altra pagina, caricare il framework WP su quella, eseguire l'elaborazione e poi reindirizzare alla pagina originale... ma... è un po' fastidioso, perché... la mia pagina originale viene caricata tramite una callback, quindi viene eseguita all'interno di un metodo della mia classe. Questo è bellissimo.
Se carico una pagina separata, devo includere manualmente wp-load.php
e mi trovo fuori dalla mia classe, il che è fastidioso, e nel mio caso particolare mi infastidisce particolarmente, perché sto istanziando la mia classe del plugin in modo anonimo in modo che nessuno possa accedervi dall'esterno.
Quindi dopo questa lunga storia... qualcuno ha trovato una buona soluzione per caricare un'altra pagina tramite callback senza avere già configurata l'intera interfaccia di amministrazione intorno ad essa?
(Conosco una soluzione alternativa... posso agganciare una funzione a load-....
che controlla il parametro dell'azione ed esegue l'elaborazione e il redirect. Ma mi chiedo se esiste un modo migliore.)
Grazie.

Come regola generale, dovresti utilizzare una richiesta POST per la maggior parte delle azioni, per assicurarti che non vengano eseguite accidentalmente. È anche una buona pratica reindirizzare a una pagina normale dopo una richiesta POST, per evitare esecuzioni duplicate quando l'utente aggiorna la pagina.
Quindi il flusso è il seguente:
- La pagina del tuo plugin con un modulo POST, che invia a
- Una pagina che gestisce la richiesta, che reindirizza a
- La pagina del tuo plugin, che mostra il risultato dell'azione
La pagina intermedia non deve essere necessariamente quella del tuo plugin. Ciò significa che puoi utilizzare il "gestore POST generico" incluso tre anni fa, l'hook 'admin_action_' . $_REQUEST['action']
in admin.php
.
Un esempio di utilizzo è il plugin Akismet. Se vuoi usarlo in modo affidabile, devi inviare direttamente a admin.php
, non a un'altra pagina che include casualmente admin.php
.
Ecco un esempio molto basilare di come utilizzarlo:
add_action( 'admin_action_wpse10500', 'wpse10500_admin_action' );
function wpse10500_admin_action()
{
// Fai le tue operazioni qui
wp_redirect( $_SERVER['HTTP_REFERER'] );
exit();
}
add_action( 'admin_menu', 'wpse10500_admin_menu' );
function wpse10500_admin_menu()
{
add_management_page( 'WPSE 10500 Test page', 'WPSE 10500 Test page', 'administrator', 'wpse10500', 'wpse10500_do_page' );
}
function wpse10500_do_page()
{
?>
<form method="POST" action="<?php echo admin_url( 'admin.php' ); ?>">
<input type="hidden" name="action" value="wpse10500" />
<input type="submit" value="Esegui!" />
</form>
<?php
}

Ehi, guarderò di nuovo il codice, ovviamente non l'avevo notato, ma solo per confermare...quindi quello che stai dicendo è che se chiamo admin.php direttamente senza un parametro page, salta tutto il caricamento della pagina e fa solo qualche inizializzazione e esegue l'hook? Sarebbe fantastico... più o meno (ancora non capisco perché non hanno messo l'hook prima del caricamento della pagina).

@wyrfel: Sì, chiamare admin.php
direttamente è il "trucco" che mi ha insegnato il codice sorgente di Akismet. Hai ragione quando stai visualizzando un form e vuoi visualizzarlo di nuovo in caso di errori: allora sarebbe facile se la destinazione è la tua pagina del plugin ma l'hook è da qualche parte all'inizio (così potresti reindirizzare se ha successo, o visualizzare di nuovo il form con i messaggi di errore se no). Magari suggeriscilo in un ticket Trac?

Aprirò un ticket. Come soluzione alternativa, ho scoperto che l'hook 'load-<pagehook>'
funziona...viene chiamato prima che la pagina venga caricata...ma il concetto di admin_action_...
sembra molto più carino e specifico. Inoltre, nota a margine, i messaggi di errore sono ancora problematici se fai POST e non vuoi ripostare al ricaricamento, ma questo è un altro argomento.

@wyrfel: Perché i messaggi di errore sarebbero ancora problematici? Se c'è un messaggio di errore, rimani sulla pagina e mostra nuovamente il modulo con i messaggi (ovviamente un refresh qui non avrebbe molto senso - ma non farebbe nemmeno male, perché gli errori sarebbero ancora presenti e nessuna azione verrà eseguita). Se non ci sono errori, esegui l'azione e reindirizza a una pagina di panoramica "sicura". Questo funzionerebbe - se l'hook admin_action_
fosse spostato prima del caricatore della pagina del plugin.

Ho esteso questo post e abilitato questi stessi metodi 'admin-action' per essere chiamati da URL 'post-row-action'. La soluzione utilizza Jquery per mappare un URL GET alla richiesta POST del FORM che questa risposta affronta. http://wordpress.stackexchange.com/questions/82761/how-can-i-link-post-row-actions-with-a-custom-action-function

Ho affrontato questo in modo leggermente diverso aggiungendo semplicemente noheader=true all'URL dell'azione nella pagina dove l'utente invia l'azione.
Il mio gestore esegue quindi l'azione (ad esempio tipicamente un'aggiunta, un aggiornamento o un'eliminazione) e termina con un wp_redirect() alla successiva azione della pagina (es. pagina di aggiunta -> pagina di modifica, pagina di eliminazione -> pagina di elenco, pagina di modifica -> pagina di modifica). Inoltre passo un messaggio nell'URL così da poter visualizzare uno stato come aggiornamento riuscito o fallito.
Questo approccio mantiene tutte le azioni: elenco, aggiunta, modifica, eliminazione, eliminazione multipla, ecc. nella stessa classe e con lo stesso slug di amministrazione, rendendolo abbastanza facile da mantenere e da comprendere.
