Cum pot forța descărcarea unui fișier în interfața de administrare WordPress?

31 oct. 2010, 18:29:28
Vizualizări: 59.3K
Voturi: 34

Aș dori să adaug un buton "Click pentru descărcare" într-unul dintre plugin-urile mele WordPress și nu sunt sigur ce hook să folosesc. Până acum, folosirea hook-ului 'admin_init' cu acest cod pare să funcționeze:

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

Acest lucru pare să funcționeze, dar vreau să văd dacă există o practică recomandată pentru această situație.

Mulțumesc, Dave

0
Toate răspunsurile la întrebare 3
8
46

Dacă te înțeleg corect, vrei să ai un URL similar cu următorul al cărui răspuns către browser va fi conținutul pe care îl generezi, adică fișierul tău .CSV și nu conținut generat de WordPress?

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

Cred că cauți hook-ul 'template_redirect'. Poți găsi 'template_redirect' în /wp-includes/template-loader.php, un fișier pe care toți dezvoltatorii WordPress ar trebui să-l cunoască; este scurt și la obiect și direcționează fiecare încărcare de pagină care nu este în admin, așa că asigură-te să arunci o privire.

Doar adaugă următoarele în fișierul functions.php al temei tale sau într-un alt fișier pe care îl include în 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();
  }
}

Observă testul pentru URL-ul '/downloads/data.csv' prin inspectarea $_SERVER['REQUEST_URI']. De asemenea, observă adăugarea ,true,200 la apelul tău header() unde setezi Content-type; acest lucru se datorează faptului că WordPress va fi setat codul de stare 404 "Not Found" pentru că nu recunoaște URL-ul. Nu este o problemă, deoarece true îi spune lui header() să înlocuiască 404 setat de WordPress și să folosească în schimb codul de stare HTTP 200 "Okay".

Și iată cum arată în FireFox (Notă captura de ecran nu are un director virtual /downloads/ pentru că după ce am făcut și adnotat captura de ecran, a părut o idee bună să adaug un director virtual '/downloads/'):

Captură de ecran a unui URL de descărcare pentru un fișier CSV
(sursa: mikeschinkel.com)

ACTUALIZARE

Dacă dorești ca descărcarea să fie gestionată dintr-un URL prefixat cu /wp-admin/ pentru a oferi utilizatorului o indicație vizuală că este protejată de un login, poți face și asta; descrierea unei modalități urmează.

Am încapsulat de data aceasta într-o clasă, numită DownloadCSV, și am creat o "capabilitate" de utilizator numită 'download_csv' pentru rolul 'administrator' (citește despre Roluri și Capabilități aici) Ai putea pur și simplu să te bazezi pe rolul predefinit 'export' dacă dorești și, în acest caz, doar caută și înlocuiește 'download_csv' cu 'export' și elimină apelul register_activation_hook() și funcția activate(). Apropo, nevoia unui hook de activare este un motiv pentru care am mutat acest lucru într-un plugin în loc să-l păstrez în fișierul functions.php al temei.*

Am adăugat și o opțiune de meniu "Descarcă CSV" sub meniul "Unelte" folosind add_submenu_page() și am legat-o de capabilitatea 'download_csv'.

În final, am ales hook-ul 'plugins_loaded' pentru că a fost cel mai timpuriu hook adecvat pe care l-am putut folosi. Ai putea folosi 'admin_init', dar acel hook este rulat mult mai târziu (al 1130-lea apel de hook față de al 3-lea apel de hook), așa că de ce să lași WordPress să facă mai multă muncă inutilă decât este necesar? (Am folosit plugin-ul meu Instrument Hooks pentru a afla ce hook să folosesc.)

În hook, verific să mă asigur că URL-ul meu începe cu /wp-admin/tools.php prin inspectarea variabilei $pagenow, verific dacă current_user_can('download_csv') și, dacă acest lucru trece, atunci testez $_GET['download'] pentru a vedea dacă conține data.csv; dacă da, rulăm practic același cod ca înainte. Am eliminat și ,true,200 din apelul către header() din exemplul anterior pentru că aici WordPress știe că este un URL valid, așa că nu a setat încă statusul 404. Deci, iată codul tău:

<?php
/*
Plugin Name: Descarcă 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',    // Meniul Părinte
        'Descarcă CSV',                // Titlul Paginii
        'Descarcă CSV',                // Eticheta Opțiunii de Meniu
        'download_csv',                // Capabilitate
        'tools.php?download=data.csv');// URL-ul Opțiunii relativ la /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();
}

Și iată o captură de ecran a plugin-ului activat: Captură de ecran a Paginii de Plugin-uri care arată un plugin activat
(sursa: mikeschinkel.com)

Și în final, iată o captură de ecran a declanșării descărcării: Captură de ecran a Descărcării unui fișier prin URL dintr-o opțiune a meniului Unelte din admin-ul WordPress
(sursa: mikeschinkel.com)

1 nov. 2010 13:09:54
Comentarii

Mike, mulțumesc pentru ajutor. Singura problemă cu această funcționalitate este că aș dori ca fișierul să fie descărcat din backend. Se pare că template_redirect nu funcționează pe backend, iar dacă nu ar trebui să folosesc admin_init, mă întreb ce ar trebui să folosesc în schimb. admin_init pare să funcționeze pentru mine acum, așa că s-ar putea să rămân la el cel puțin pe termen scurt. Este o funcționalitate minoră pe care doar câțiva oameni o vor folosi.

Dave Morris Dave Morris
3 nov. 2010 04:37:54

@Dave Morris - Poți să definești ce înțelegi prin "back end"? Te referi la server? Dacă da, 'template_redirect' cu siguranță rulează pe server. Dacă nu, sunt total confuz; poți să clarifici problema? Mulțumesc anticipat.

MikeSchinkel MikeSchinkel
3 nov. 2010 14:00:24

@Dave: Dacă prin "back end" te referi la zona de administrare, acest lucru va funcționa în continuare. URL-ul de descărcare începe cu /downloads/data.csv, care este un fișier inexistent, așa că "front end"-ul WordPress va gestiona această solicitare și va ajunge în cele din urmă la template-redirect. Pur și simplu creezi un link în zona de administrare care trimite către acest URL din partea frontală. (Trebuie menționat că în acest fel, nu beneficiezi de protecția de login a administratorului gratuit - oricine cunoaște URL-ul poate descărca fișierul, dar poate există o modalitate ușoară de a remedia acest lucru?)

Jan Fabry Jan Fabry
3 nov. 2010 22:41:37

@Jan Fabry - Ah, acum am înțeles. Prin "back end" se referea la zona de administrare, corect? Poate folosi funcția current_user_can() cu codul de mai sus sau poate încerca o altă abordare. După acest comentariu voi actualiza răspunsul meu.

MikeSchinkel MikeSchinkel
4 nov. 2010 11:55:45

Da, îmi cer scuze, nu primesc notificări prin email de pe acest site, așa că asta explică întârzierea mea în a răspunde. Mă refeream într-adevăr la zona de administrare WordPress când am spus "backend". Îmi pare rău pentru asta. Voi încerca să folosesc template_redirect și voi vedea ce se întâmplă. Mulțumesc! ~Dave

Dave Morris Dave Morris
6 nov. 2010 00:47:30

@Dave Morris - template_redirect este mai mult pentru accesul extern. Încearcă cel de-al doilea exemplu pe care l-am postat.

MikeSchinkel MikeSchinkel
6 nov. 2010 01:05:30

Acest lucru este excelent. Mi-ai economisit mult timp. Vreau doar să clarific pentru alții care s-ar putea să nu aibă nevoie de pagina de submeniu că tot ce trebuie să faci este să conectezi metoda clasei DownloadCSV admin_menu la cârligul de acțiune cu apelul către add_action('admin_menu',array(__CLASS__,'admin_menu')); și să adaugi codul tău pentru a forța descărcarea în codul metodei.

racl101 racl101
30 ian. 2014 07:16:17

Dacă vrei să folosești WP_Query pentru a obține datele pentru a crea fișierul descărcabil, folosește cârligul 'admin_init' în loc de 'plugins_loaded'. Dacă nu, vei primi "Eroare fatală: Apel către o funcție membru get_queried_object_id()".

Gustavo Daniel Gustavo Daniel
15 iul. 2016 01:42:48
Arată celelalte 3 comentarii
0

încă un plugin util pentru exportarea în format CSV. poate fi util pentru cineva

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

        // Adaugă elemente extra în meniu pentru administratori
        add_action('admin_menu', array($this, 'admin_menu'));

        // Creează end-point-uri
        add_filter('query_vars', array($this, 'query_vars'));
        add_action('parse_request', array($this, 'parse_request'));
    }

    /**
    * Adaugă elemente extra în meniu pentru administratori
    */
    public function admin_menu()
    {
        add_menu_page('Descarcă Raport', 'Descarcă Raport', 'manage_options', 'download_report', array($this, 'download_report'));
    }

    /**
    * Permite variabile personalizate în interogări
    */
    public function query_vars($query_vars)
    {
        $query_vars[] = 'download_report';
        return $query_vars;
    }

    /**
    * Procesează cererea
    */
    public function parse_request(&$wp)
    {
        if(array_key_exists('download_report', $wp->query_vars))
        {
            $this->download_report();
            exit;
        }
    }

    /**
    * Descarcă raportul
    */
    public function download_report()
    {
        echo '<div class="wrap">';
        echo '<div id="icon-tools" class="icon32">
        </div>';
        echo '<h2>Descarcă Raport</h2>';
        //$url = site_url();

        echo '<p>Exportă Utilizatorii';
    }

    /**
    * Convertirea datelor în 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;
    }
}

// Instanțiază un singleton al acestui plugin
$csvExport = new CSVExport();
4 ian. 2013 18:26:38
0

Cârligul admin_init sau cârligul load-(page) pare să funcționeze, WordPress nu a setat header-ul în această stare. Folosesc cârligul load-(page) pentru că rulează atunci când o pagină din meniul de administrare este încărcată. Poți încărca scriptul tău pentru o anumită pagină.

Poți verifica cârligul load-(page) în WordPress Codex

Dacă folosești cârligul admin_init, asigură-te că verifici nonce-ul folosind check_admin_referer sau alt script care poate trece condiția va obține fișierul tău de descărcare ca output.

24 dec. 2014 09:54:38