Jak mogę wymusić pobranie pliku w backendie WordPress?

30

Chciałbym dodać przycisk „Kliknij, aby pobrać” do jednej z moich wtyczek WordPress i nie jestem pewien, którego haka użyć. Do tej pory wydaje się, że podpięcie „admin_init” do tego kodu działa:

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

Wydaje się, że to działa, ale chcę tylko sprawdzić, czy istnieje najlepsza praktyka.

Dzięki, Dave

Dave Morris
źródło

Odpowiedzi:

39

Jeśli dobrze cię rozumiem, chcesz mieć adres URL podobny do następującego, którego odpowiedzią dla przeglądarki będzie treść, którą generujesz, tj. .CSVPlik i żadna treść generowana z WordPress?

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

Myślę, że szukasz 'template_redirect'haka. Można znaleźć 'template_redirect'w /wp-includes/template-loader.phpktórym jest plik wszyscy deweloperzy WordPress powinien zapoznać się z; jest krótki i słodki i kieruje każdą ładowaniem stron innych niż administrator, więc koniecznie spójrz na to.

Po prostu dodaj następujące elementy do functions.phppliku motywu lub w innym pliku, includew którym się znajdujesz 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();
  }
}

Zanotuj test '/downloads/data.csv'adresu URL, sprawdzając $_SERVER['REQUEST_URI']. Zwróć także uwagę na dodane ,true,200do header()połączenia, gdzie ustawiłeś Content-type; dzieje się tak, ponieważ WordPress ustawi kod statusu 404 „Nie znaleziono”, ponieważ nie rozpoznaje adresu URL. Nie stanowi to jednak problemu, ponieważ truenakazuje header()zastąpienie 404WordPressa ustawieniem i użycie zamiast tego kodu stanu HTTP 200 „OK” .

A oto, jak to wygląda w FireFox ( zwróć uwagę, że zrzut ekranu nie ma /downloads/katalogu wirtualnego, ponieważ po zrobieniu zrzutu ekranu i opatrzeniu go adnotacją po prostu wydawało się dobrym pomysłem dodanie '/downloads/'katalogu wirtualnego):

Zrzut ekranu z adresem URL pobierania pliku CSV
(źródło: mikeschinkel.com )

AKTUALIZACJA

Jeśli chcesz, aby pobieranie odbywało się na podstawie adresu URL z prefiksem, /wp-admin/aby dać użytkownikowi wizualne wskazanie, że jest chroniony przez login, możesz to również zrobić; opis jednego ze sposobów jest następujący.

I obudowane w klasie, tym razem o nazwie DownloadCSV, a także tworzone przez użytkownika „zdolności” o nazwie 'download_csv'dla 'administrator'roli (czytaj o roli i kompetencji tutaj ) Możesz po prostu na barana off predefiniowanej 'export'roli, jeśli lubisz, a jeśli tak, wystarczy wyszukać i zamienić 'download_csv'z 'export'i usuń register_activation_hook()połączenie oraz activate()funkcję. Nawiasem mówiąc, potrzeba haka aktywacyjnego jest jednym z powodów, dla których przeniosłem go do wtyczki zamiast przechowywać w functions.phppliku motywu . *

Dodałem także opcję menu „Pobierz CSV” z menu „Narzędzia”, używając add_submenu_page()i powiązałem ją z 'download_csv'funkcją.

Wreszcie wybrałem 'plugins_loaded'hak, ponieważ był to najwcześniejszy odpowiedni hak, którego mogłem użyć. Możesz użyć, 'admin_init'ale ten hak jest uruchamiany znacznie później (1130. połączenie hakowe vs. 3. połączenie hakowe), więc po co pozwolić WordPressowi wykonywać więcej zadań wyrzucania, niż to konieczne? (Użyłem wtyczki Instrument Hooks, aby dowiedzieć się, którego haka użyć).

W haka I sprawdzić, moje starty URL z /wp-admin/tools.phpsprawdzając $pagenowzmiennej I zweryfikować, current_user_can('download_csv')a jeśli to przechodzi następnie przetestować $_GET['download'], aby sprawdzić, czy zawiera on data.csv; jeśli tak, uruchamiamy praktycznie ten sam kod jak poprzednio. Usuwam również ,true,200wezwanie do header()w poprzednim przykładzie, ponieważ tutaj WordPress wie, że to dobry adres URL, więc nie ustawiłem jeszcze statusu 404. Oto twój kod:

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

A oto zrzut ekranu aktywowanej wtyczki: (źródło: mikeschinkel.com )Zrzut ekranu przedstawiający aktywowaną wtyczkę

I wreszcie zrzut ekranu z pobieraniem: (źródło: mikeschinkel.com )Zrzut ekranu pobierania pliku według adresu URL z opcji menu Narzędzia administratora WordPress

MikeSchinkel
źródło
Mike, dziękuję za twoją pomoc. Jedynym mankamentem tej funkcji jest to, że chciałbym, aby plik został pobrany z backendu. Wygląda na to, że szablon_redirect nie działa na backendie, a jeśli nie powinienem używać admin_init, zastanawiam się, co powinienem zamiast tego użyć. Wygląda na to, że admin_init działa teraz dla mnie, mogę się z tym trzymać przynajmniej na krótki czas. Jest to drobna funkcja, z której będzie korzystać tylko kilka osób.
Dave Morris,
@Dave Morris - Czy możesz zdefiniować, co rozumiesz przez „zaplecze” ? Masz na myśli na serwerze? Jeśli tak, 'template_redirect'to zdecydowanie działa na serwerze. Jeśli nie, byłbym całkowicie zdezorientowany; czy możesz wyjaśnić problem? Z góry dziękuję.
MikeSchinkel,
@Dave: Jeśli masz na myśli obszar administracyjny przez „zaplecze”, to nadal będzie działać. URL pobierania zaczyna się od /downloads/data.csv, który nie istnieje, więc „interfejs użytkownika” WordPressa obsłuży to żądanie i ostatecznie osiągnie template-redirect. Wystarczy utworzyć link w obszarze administracyjnym, który wskazuje ten frontowy adres URL. (Trzeba powiedzieć, że w ten sposób nie otrzymujesz ochrony logowania administratora za darmo - każdy, kto zna adres URL, może pobrać plik, ale może istnieje łatwy sposób, aby to naprawić?)
Jan Fabry
@Jan Fabry - Ach, rozumiem teraz. Przez „back end” miał na myśli z poziomu administratora, prawda? Może użyć funkcji current_user_can()z powyższym kodem lub zastosować inne podejście. Po tym komentarzu dodam aktualizację do mojej odpowiedzi.
MikeSchinkel,
Tak, przepraszam, nie otrzymuję powiadomień e-mail z tej witryny, co tłumaczy moje opóźnienie w odpowiedzi. Rzeczywiście miałem na myśli obszar administracyjny WordPress, kiedy powiedziałem „backend”. Przepraszam za to. Spróbuję użyć template_redirect i zobaczę, co się stanie. Dzięki! ~ Dave
Dave Morris
3

jeszcze jedna przydatna wtyczka do eksportu do CSV. może być przydatny dla kogoś

    <?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();
Deweloper
źródło
2

admin_init Zaczep lub ładowanie (strona) Zaczep wydaje się działać, WordPress nie ma ustawionego nagłówka w tym stanie. Używam haka load- (page), ponieważ działa, gdy załadowana jest strona menu administracyjnego. Możesz załadować skrypt dla określonej strony.

Możesz sprawdzić load- (page) Hook na WordPress Codex

Jeśli używasz admin_init Hook, upewnij się, że zweryfikowałeś nonce za pomocą check_admin_referer lub innego skryptu, może się zda, że ​​warunek uzyska wynik pobierania pliku.

Joko Wandiro
źródło