Как я могу принудительно загрузить файл в бэкэнд WordPress?

30

Я хотел бы добавить кнопку «Нажмите для загрузки» в один из моих плагинов WordPress, и я не уверен, какой хук использовать. До сих пор подключение 'admin_init' к этому коду похоже работает:

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

Кажется, это работает, но я просто хочу посмотреть, есть ли лучшая практика там.

Спасибо дэйв

Дейв Моррис
источник

Ответы:

39

Если я вас правильно понимаю, вы хотите иметь URL-адрес, подобный следующему, чей ответ браузеру будет сгенерированным вами контентом, т.е. вашим .CSVфайлом, а не сгенерированным контентом из WordPress?

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

Я думаю, что вы ищете 'template_redirect'крючок. Вы можете найти, 'template_redirect'в /wp-includes/template-loader.phpкаком файле должны быть знакомы все разработчики WordPress; он короткий и приятный и направляет каждую загрузку страницы без прав администратора, поэтому обязательно посмотрите на нее.

Просто добавьте следующую строку вашей темы functions.phpфайла или в другом файле , который вы includeв 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();
  }
}

Обратите внимание на тест для '/downloads/data.csv'URL, проверяя $_SERVER['REQUEST_URI']. Также обратите внимание на добавленный ,true,200к вашему header()звонку, где вы установите Content-type; Это связано с тем, что WordPress установит код состояния 404 «Не найдено», потому что он не распознает URL. Это не проблема, поскольку, как trueговорится, header()заменить установленный 404WordPress и использовать вместо этого HTTP- код состояния 200 «Хорошо» .

А вот как это выглядит в FireFox ( обратите внимание, что на скриншоте нет /downloads/виртуального каталога, потому что после создания и добавления аннотации на скриншот это просто хорошая идея добавить '/downloads/'виртуальный каталог):

Снимок экрана: URL для загрузки файла CSV
(источник: mikeschinkel.com )

ОБНОВИТЬ

Если вы хотите, чтобы загрузка осуществлялась с URL-адреса с префиксом, /wp-admin/чтобы дать пользователю визуальную индикацию того, что он защищен логином, вы также можете сделать это; описание одного пути следует.

На этот раз я инкапсулировал в класс, который вызывается DownloadCSV, и для создания пользовательской «возможности», вызываемой 'download_csv'для 'administrator'роли (читайте о ролях и возможностях здесь ). Вы можете просто перенести предопределенную 'export'роль, если хотите, и если это так, просто искать и заменять 'download_csv'на 'export'и удалите register_activation_hook()вызов и activate()функцию. Кстати, необходимость в ловушке активации - одна из причин, по которой я переместил это в плагин вместо того, чтобы хранить его в functions.phpфайле темы . *

Я также добавил «Скачать CSV» вариант меню от «Сервис» меню , используя add_submenu_page()и связал ее с 'download_csv'возможностями.

Наконец, я выбрал 'plugins_loaded'крючок, потому что это был самый ранний подходящий крючок, который я мог использовать. Вы можете использовать, 'admin_init'но эта ловушка запускается намного позже (1130-й вызов ловушки против 3-го вызова ловушки), так почему же WordPress выполняет больше одноразовой работы, чем нужно? (Я использовал свой плагин Instrument Hooks, чтобы выяснить, какой хук использовать.)

В хуке, который я проверяю, чтобы убедиться, что мой URL начинается с /wp-admin/tools.phpпроверки $pagenowпеременной, я проверяю это, current_user_can('download_csv')и если это проходит, то я проверяю, $_GET['download']содержит ли он data.csv; если да, мы запускаем практически тот же код, что и раньше. Я также убрал ,true,200из вызова header()в предыдущем примере, потому что здесь WordPress знает, что это хороший URL, поэтому еще не установил статус 404. Итак, вот ваш код:

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

И вот скриншот активированного плагина: (источник: mikeschinkel.com )Скриншот страницы плагинов, показывающий активированный плагин

И, наконец, вот скриншот запуска загрузки (источник: mikeschinkel.com )Снимок экрана: загрузка файла по URL-адресу из меню «Инструменты» администратора WordPress

MikeSchinkel
источник
Майк, спасибо за твою помощь. Единственный недостаток этой функции заключается в том, что я хотел бы, чтобы файл был загружен из серверной части. Похоже, что template_redirect не работает на бэкэнде, и если я не должен использовать admin_init, мне интересно, что я должен использовать вместо этого. admin_init, кажется, работает для меня сейчас, я мог бы придерживаться этого по крайней мере в краткосрочной перспективе. Это небольшая функция, которую собираются использовать только несколько человек.
Дейв Моррис
@ Дейв Моррис - Можете ли вы определить, что вы подразумеваете под «бэк- эндом » ? Вы имеете в виду на сервере? Если да, то 'template_redirect'наиболее определенно работает на сервере. Если нет, я бы полностью запутался; Вы можете уточнить проблему? Заранее спасибо.
MikeSchinkel
@Dave: Если вы имеете в виду административную область под «бэкендом», это все равно будет работать. URL-адрес загрузки начинается с /downloads/data.csvнесуществующего файла, поэтому «внешний интерфейс» WordPress обработает этот запрос и в конечном итоге достигнет template-redirect. Вы просто создаете ссылку в административной области, которая указывает на этот внешний URL-адрес. (Надо сказать, что таким образом вы не получаете защиту входа администратора бесплатно - любой, кто знает URL, может скачать файл, но, может быть, есть простой способ это исправить?)
Ян Фабри
@ Ян Фабри - А, теперь я понимаю. Под «бэкендом» он имел в виду администратора, верно? Он может использовать функцию current_user_can()с приведенным выше кодом или использовать другой подход. После этого комментария я добавлю обновление к своему ответу.
MikeSchinkel
Да, я прошу прощения, я не получаю оповещения по электронной почте с этого сайта, поэтому это объясняет мою задержку с ответом. Я действительно имел в виду админку WordPress, когда сказал «бэкэнд». Прости за это. Я попробую использовать template_redirect и посмотрю, что произойдет. Благодарность! ~ Дэйв
Дейв Моррис
3

Еще один полезный плагин для экспорта в CSV. может быть полезным для кого-то

    <?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 или load- (page) Hook, кажется, работает, WordPress не был установлен заголовок в этом состоянии. Я использую load- (page) Hook, потому что он запускается при загрузке страницы меню администрирования. Вы можете загрузить свой скрипт для конкретной страницы.

Вы можете проверить загрузку (страницы) Крюк на WordPress Codex

Если вы используете admin_init Hook, убедитесь, что вы проверяли одноразовый номер, используя check_admin_referer или другой сценарий, и, возможно, пропустите условие, и вы получите файл загрузки.

Джоко Вандиро
источник