Wie kann ich einen Dateidownload im WordPress-Backend erzwingen?

30

Ich möchte einem meiner WordPress-Plugins die Schaltfläche "Klicken zum Herunterladen" hinzufügen und bin mir nicht sicher, welchen Hook ich verwenden soll. Bisher scheint es zu funktionieren, 'admin_init' an diesen Code anzuhängen:

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

Dies scheint zu funktionieren, aber ich möchte nur sehen, ob es eine bewährte Methode gibt.

Danke, Dave

Dave Morris
quelle

Antworten:

39

Wenn ich Sie richtig verstehe, möchten Sie eine URL wie die folgende haben, deren Antwort auf den Browser der Inhalt ist, den Sie generieren, dh Ihre .CSVDatei und kein generierter Inhalt von WordPress?

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

Ich glaube du suchst den 'template_redirect'Haken. Sie können finden 'template_redirect'in /wp-includes/template-loader.phpdem eine Datei alle Wordpress - Entwickler mit vertraut werden sollte; Es ist kurz und bündig und leitet alle Seiten, die nicht von Administratoren geladen werden, weiter.

Fügen Sie einfach die folgende zu Ihrem Thema der functions.phpDatei oder in einer anderen Datei , die Sie 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();
  }
}

Notieren Sie den Test für die '/downloads/data.csv'URL, indem Sie ihn überprüfen $_SERVER['REQUEST_URI']. Beachten Sie auch das ,true,200zu Ihrem header()Anruf hinzugefügte, in dem Sie das Content-type; Dies liegt daran, dass WordPress den Statuscode 404 "Nicht gefunden" festgelegt hat, da es die URL nicht erkennt. Es ist kein Problem , obwohl , wie das truesagt header()die ersetzen 404Wordpress gesetzt hatte und die Verwendung von HTTP 200 „Okay“ statt Statuscode.

Und so sieht es in FireFox aus ( Beachten Sie, dass der Screenshot kein /downloads/virtuelles Verzeichnis enthält, da es nach dem Aufnehmen und Kommentieren des Screenshots nur eine gute Idee war, ein '/downloads/'virtuelles Verzeichnis hinzuzufügen ):

Screenshot einer Download-URL für eine CSV-Datei
(Quelle: mikeschinkel.com )

AKTUALISIEREN

Wenn Sie möchten, dass der Download über eine URL abgewickelt wird, der ein Präfix vorangestellt ist /wp-admin/, um dem Benutzer den visuellen Hinweis zu geben, dass er durch eine Anmeldung geschützt ist, können Sie dies auch tun. Es folgt die Beschreibung eines Weges.

Ich habe diesmal eine Klasse eingekapselt, die aufgerufen wird DownloadCSV, und um eine Benutzer- "Fähigkeit" zu erstellen, die 'download_csv'für die 'administrator'Rolle aufgerufen wird (siehe Rollen und Fähigkeiten hier ). Sie können die vordefinierte 'export'Rolle einfach huckepack nehmen, wenn Sie möchten, und wenn ja, nur suchen und ersetzen 'download_csv'mit 'export'und entfernen Sie den register_activation_hook()Anruf und die activate()Funktion. Die Notwendigkeit eines Aktivierungs-Hooks ist übrigens ein Grund, warum ich diesen in ein Plugin verschoben habe, anstatt ihn in der functions.phpDatei des Themas zu behalten . *

Ich habe auch eine hinzugefügt „Download CSV“ Menüoption aus dem „Extras“ Menü add_submenu_page()und verknüpft es auf die 'download_csv'Fähigkeit.

Schließlich entschied ich mich für den 'plugins_loaded'Haken, weil er der früheste geeignete Haken war, den ich verwenden konnte. Sie könnten verwenden, 'admin_init'aber dieser Hook wird viel später ausgeführt (1130. Hook-Aufruf im Vergleich zum 3. Hook-Aufruf). Warum sollte WordPress dann mehr wegwerfen als nötig? (Ich habe mein Instrument Hooks-Plugin verwendet, um herauszufinden, welcher Hook verwendet werden soll.)

In dem Haken, den ich überprüfe, um sicherzustellen, dass meine URL beginnt, /wp-admin/tools.phpindem $pagenowich die Variable überprüfe, überprüfe ich das current_user_can('download_csv')und wenn das bestanden wird, teste ich $_GET['download'], ob es enthält data.csv; Wenn ja, führen wir praktisch den gleichen Code wie zuvor aus. Ich entferne auch das ,true,200aus dem Aufruf von header()im vorherigen Beispiel, weil hier WordPress weiß, dass es eine gute URL ist, also den 404-Status noch nicht gesetzt hat. Also hier ist dein Code:

<?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();
}

Und hier ist ein Screenshot des aktivierten Plugins: (Quelle: mikeschinkel.com )Screenshot der Plugin-Seite mit einem aktivierten Plugin

Und zum Schluss hier noch ein Screenshot zum Auslösen des Downloads: (Quelle: mikeschinkel.com )Screenshot des Herunterladens einer Datei per URL aus einer Option des Tools-Menüs des WordPress-Administrators

MikeSchinkel
quelle
Mike, danke für deine Hilfe. Der einzige Haken bei dieser Funktion ist, dass ich möchte, dass die Datei vom Backend heruntergeladen wird. Es sieht so aus, als ob template_redirect im Backend nicht funktioniert. Wenn ich admin_init nicht verwenden soll, frage ich mich, was ich stattdessen verwenden soll. admin_init scheint jetzt für mich zu funktionieren, ich könnte mich zumindest kurzfristig daran halten. Es ist eine untergeordnete Funktion, die nur von wenigen Personen verwendet wird.
Dave Morris
@ Dave Morris - Kannst du definieren, was du mit "Back-End" meinst ? Meinst du auf dem Server? Wenn ja, 'template_redirect'läuft definitiv auf dem Server. Wenn nicht, würde ich total verwirrt sein; Können Sie die Besorgnis klären? Danke im Voraus.
MikeSchinkel
@ Dave: Wenn du den Admin-Bereich mit "Back-End" meinst, wird dies immer noch funktionieren. Die Download-URL beginnt mit /downloads/data.csv, was eine nicht vorhandene Datei ist, so dass das WordPress- "Front-End" diese Anfrage bearbeitet und schließlich erreicht template-redirect. Sie erstellen einfach einen Link im Admin-Bereich, der auf diese Frontside-URL verweist. (Es muss gesagt werden, dass Sie auf diese Weise den Anmeldeschutz für Administratoren nicht kostenlos erhalten - jeder, der die URL kennt, kann die Datei herunterladen, aber vielleicht gibt es einen einfachen Weg, dies zu beheben?)
Jan Fabry
@ Jan Fabry - Ah, ich verstehe jetzt. Mit "Backend" meinte er aus dem Admin heraus, oder? Er kann die Funktion current_user_can()mit dem obigen Code verwenden oder einen anderen Ansatz wählen. Nach diesem Kommentar werde ich meiner Antwort ein Update hinzufügen.
MikeSchinkel
Ja, ich bitte um Entschuldigung, ich erhalte keine E-Mail-Benachrichtigungen von dieser Website, sodass meine Verzögerung bei der Beantwortung der Fragen erklärt wird. Ich habe mich in der Tat auf den Admin-Bereich von WordPress bezogen, als ich "Backend" sagte. Das tut mir leid. Ich werde versuchen, template_redirect zu verwenden und sehen, was passiert. Vielen Dank! ~ Dave
Dave Morris
3

ein weiteres nützliches Plugin für den Export in CSV. kann für jemanden nützlich sein

    <?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();
Entwickler
quelle
2

admin_init Hook oder load- (page) Hook scheint zu funktionieren, WordPress wurde in diesem Status nicht als Header gesetzt. Ich verwende load- (page) Hook, weil es ausgeführt wird, wenn eine Administrationsmenüseite geladen wird. Sie können Ihr Skript für eine bestimmte Seite laden.

Sie können den Lade- (Seiten-) Haken in WordPress Codex überprüfen

Wenn Sie mit admin_init Haken stellen Sie sicher, nonce überprüfen mit check_admin_referer oder andere Skript vielleicht die Bedingung passieren Ausgabe der Download - Datei.

Joko Wandiro
quelle