Come posso forzare un download di file nel back-end di WordPress?


30

Vorrei aggiungere un pulsante "Fai clic per scaricare" a uno dei miei plug-in di WordPress e non sono sicuro di quale hook utilizzare. Finora, l'aggancio di "admin_init" a questo codice sembra funzionare:

 header("Content-type: application/x-msdownload");
 header("Content-Disposition: attachment; filename=data.csv");
 header("Pragma: no-cache");
 header("Expires: 0");
 echo 'data';
 exit();

Questo sembra funzionare, ma voglio solo vedere se c'è una buona pratica là fuori.

Grazie, Dave

Risposte:


39

Se ti capisco correttamente vuoi avere un URL simile al seguente la cui risposta al browser sarà il contenuto che generi, cioè il tuo .CSVfile e nessun contenuto generato da WordPress?

http://example.com/download/data.csv

Penso che tu stia cercando il 'template_redirect'gancio. Puoi trovare 'template_redirect'in /wp-includes/template-loader.phpquale file è necessario familiarizzare con tutti gli sviluppatori di WordPress; è breve e dolce e indirizza tutti i caricamenti di pagine non amministrative, quindi assicurati di dare un'occhiata.

Basta aggiungere la seguente al tema del vostro functions.phpfile o in un altro file che si includein functions.php:

add_action('template_redirect','yoursite_template_redirect');
function yoursite_template_redirect() {
  if ($_SERVER['REQUEST_URI']=='/downloads/data.csv') {
    header("Content-type: application/x-msdownload",true,200);
    header("Content-Disposition: attachment; filename=data.csv");
    header("Pragma: no-cache");
    header("Expires: 0");
    echo 'data';
    exit();
  }
}

Nota il test per l' '/downloads/data.csv'URL controllando $_SERVER['REQUEST_URI']. Nota anche l'aggiunta ,true,200alla header()chiamata in cui hai impostato il Content-type; questo perché WordPress avrà impostato il codice di stato 404 "Non trovato" perché non riconosce l'URL. Non è un problema anche se, come la trueracconta header()per sostituire il 404WordPress era tramontato e di utilizzare il HTTP 200 "Okay" codice di stato, invece.

Ed ecco come appare in FireFox ( nota che lo screenshot non ha una /downloads/directory virtuale perché dopo aver preso e annotato lo screenshot sembrava una buona idea aggiungere una '/downloads/'directory virtuale):

Schermata di un URL di download per un file CSV
(fonte: mikeschinkel.com )

AGGIORNARE

Se vuoi che il download sia gestito da un URL con prefisso /wp-admin/per dare all'utente l'indicazione visiva che è protetto da un login puoi farlo anche tu; segue la descrizione di un modo.

Questa volta ho incapsulato in una classe, chiamato DownloadCSV, e per creare una "capacità" dell'utente richiesta 'download_csv'per il 'administrator'ruolo (leggi Ruoli e Funzionalità qui ) Potresti semplicemente abbandonare il 'export'ruolo predefinito se ti piace e in tal caso basta cercare e sostituire 'download_csv'con 'export'e rimuovere la register_activation_hook()chiamata e la activate()funzione. A proposito, la necessità di un hook di attivazione è uno dei motivi per cui ho spostato questo in un plug-in anziché tenerlo nel functions.phpfile del tema . *

Ho anche aggiunto un'opzione di menu "Scarica CSV" dal menu "Strumenti" usando add_submenu_page()e collegato alla 'download_csv'funzionalità.

Alla fine ho scelto l' 'plugins_loaded'uncino perché era il primo gancio appropriato che potevo usare. Potresti usare 'admin_init'ma quell'hook viene eseguito molto più tardi (1130a chiamata hook rispetto alla 3a chiamata hook) quindi perché lasciare che WordPress faccia più lavoro da buttare di quanto sia necessario? (Ho usato il mio plugin Instrument Hooks per capire quale hook usare.)

Nel gancio controllo per accertarmi che il mio URL inizi con l' /wp-admin/tools.phpispezione della $pagenowvariabile, lo verifico current_user_can('download_csv')e se ciò passa quindi test $_GET['download']per vedere se contiene data.csv; se sì, eseguiamo praticamente lo stesso codice di prima. Rimuovo anche il ,true,200dalla chiamata a header()nell'esempio precedente perché qui WordPress sa che è un buon URL, quindi non ho ancora impostato lo stato 404. Quindi ecco il tuo codice:

<?php
/*
Plugin Name: Download CSV
Author: Mike Schinkel
Author URI: http://mikeschinkel.com
 */
if (!class_exists('DownloadCSV')) {
  class DownloadCSV {
    static function on_load() {
      add_action('plugins_loaded',array(__CLASS__,'plugins_loaded'));
      add_action('admin_menu',array(__CLASS__,'admin_menu'));
      register_activation_hook(__FILE__,array(__CLASS__,'activate'));
    }
    static function activate() {
      $role = get_role('administrator');
      $role->add_cap('download_csv');
    }
    static function admin_menu() {
      add_submenu_page('tools.php',    // Parent Menu
        'Download CSV',                // Page Title
        'Download CSV',                // Menu Option Label
        'download_csv',                // Capability
        'tools.php?download=data.csv');// Option URL relative to /wp-admin/
    }
    static function plugins_loaded() {
      global $pagenow;
      if ($pagenow=='tools.php' && 
          current_user_can('download_csv') && 
          isset($_GET['download'])  && 
          $_GET['download']=='data.csv') {
        header("Content-type: application/x-msdownload");
        header("Content-Disposition: attachment; filename=data.csv");
        header("Pragma: no-cache");
        header("Expires: 0");
        echo 'data';
        exit();
      }
    }
  }
  DownloadCSV::on_load();
}

Ed ecco uno screenshot del plugin attivato: (fonte: mikeschinkel.com )Schermata della pagina dei plug-in che mostra un plug-in attivato

E finalmente ecco uno screenshot per innescare il download: (fonte: mikeschinkel.com )Schermata di Download di un file tramite URL da un'opzione del menu Strumenti dell'amministratore di WordPress


Mike, grazie per il tuo aiuto. L'unico problema con questa funzione è che vorrei che il file fosse scaricato dal backend. Sembra che template_redirect non funzioni sul back-end e, se non dovessi usare admin_init, mi chiedo cosa dovrei usare invece. admin_init sembra funzionare per me ora, potrei restare con esso almeno a breve termine. È una caratteristica minore che solo poche persone useranno.
Dave Morris,

@Dave Morris - Puoi definire cosa intendi per "back-end" ? Intendi sul server? Se sì, 'template_redirect'sicuramente funziona sul server. Altrimenti, sarei totalmente confuso; puoi chiarire la preoccupazione? Grazie in anticipo.
MikeSchinkel,

@Dave: se si intende l'area di amministrazione per "back-end", funzionerà comunque. L'URL di download inizia con /downloads/data.csv, che è un file inesistente, quindi il "front-end" di WordPress gestirà questa richiesta e alla fine raggiungerà template-redirect. È sufficiente creare un collegamento nell'area di amministrazione che punti a questo URL frontale. (Va detto che in questo modo, non si ottiene la protezione dell'accesso admin gratuitamente - chiunque conosca l'URL può scaricare il file, ma forse c'è un modo semplice per risolverlo?)
Jan Fabry,

@ Jan Fabry - Ah, adesso capisco. Con "back-end" intendeva all'interno dell'amministratore, giusto? Può usare la funzione current_user_can()con il codice sopra o adottare un altro approccio. Dopo questo commento aggiungerò un aggiornamento alla mia risposta.
MikeSchinkel,

Sì, mi scuso, non ricevo avvisi e-mail da questo sito, il che spiega il mio ritardo nella risposta. Mi riferivo davvero all'area di amministrazione di WordPress quando ho detto "backend". Mi dispiace per quello. Proverò ad usare template_redirect e vedrò cosa succede. Grazie! ~ Dave
Dave Morris,

3

un altro plug-in utile per l'esportazione in CSV. può essere utile a qualcuno

    <?php

class CSVExport
{
/**
* Constructor
*/
public function __construct()
{
if(isset($_GET['download_report']))
{
$csv = $this->generate_csv();

header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false);
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"report.csv\";" );
header("Content-Transfer-Encoding: binary");

echo $csv;
exit;
}

// Add extra menu items for admins
add_action('admin_menu', array($this, 'admin_menu'));

// Create end-points
add_filter('query_vars', array($this, 'query_vars'));
add_action('parse_request', array($this, 'parse_request'));
}

/**
* Add extra menu items for admins
*/
public function admin_menu()
{
add_menu_page('Download Report', 'Download Report', 'manage_options', 'download_report', array($this, 'download_report'));
}

/**
* Allow for custom query variables
*/
public function query_vars($query_vars)
{
$query_vars[] = 'download_report';
return $query_vars;
}

/**
* Parse the request
*/
public function parse_request(&$wp)
{
if(array_key_exists('download_report', $wp->query_vars))
{
$this->download_report();
exit;
}
}

/**
* Download report
*/
public function download_report()
{
echo '<div class="wrap">';
echo '<div id="icon-tools" class="icon32">
</div>';
echo '<h2>Download Report</h2>';
//$url = site_url();

echo '<p>Export the Users';
}

/**
* Converting data to CSV
*/
public function generate_csv()
{
$csv_output = '';
$table = 'users';

$result = mysql_query("SHOW COLUMNS FROM ".$table."");

$i = 0;
if (mysql_num_rows($result) > 0) {
while ($row = mysql_fetch_assoc($result)) {
$csv_output = $csv_output . $row['Field'].",";
$i++;
}
}
$csv_output .= "\n";

$values = mysql_query("SELECT * FROM ".$table."");
while ($rowr = mysql_fetch_row($values)) {
for ($j=0;$j<$i;$j++) {
$csv_output .= $rowr[$j].",";
}
$csv_output .= "\n";
}

return $csv_output;
}
}

// Instantiate a singleton of this plugin
$csvExport = new CSVExport();

2

admin_init Hook o load- (pagina) Hook sembra funzionare, WordPress non è stato impostato in questo stato. Sto usando load- (page) Hook perché funziona quando viene caricata una pagina del menu di amministrazione. Puoi caricare il tuo script per una pagina specifica.

Puoi controllare load- (page) Hook su WordPress Codex

Se stai usando admin_init Hook assicurati di verificare nonce usando check_admin_referer o altri script che potrebbero passare la condizione otterrà l'output del tuo file di download.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.