问题描述

我想添加一个 「点击下载」 按钮到我的一个 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();

这似乎是有效的,但我只想看看是否有最佳实践。

谢谢,戴夫

最佳解决方案

如果我正确理解您的意图,您希望拥有一个如下所示的 URL,那么对浏览器的响应将是您生成的内容,即您的.CSV 文件,并且没有从 WordPress 生成的内容?

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

我想你正在寻找'template_redirect'钩。您可以在/wp-includes/template-loader.php 中找到'template_redirect',这是所有 WordPress 开发人员应该熟悉的文件; 它是短暂和甜蜜,路线每一个 non-admin 页面加载,所以一定要看看它。

只需将以下内容添加到主题的 functions.php 文件或 includefunctions.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();
  }
}

通过检查 $_SERVER['REQUEST_URI']来注意'/downloads/data.csv' URL 的测试。另请注意添加,true,200 到您的 header()调用,您设置 Content-type; 这是因为 WordPress 会设置 404 “Not Found” 状态代码,因为它不能识别该 URL 。这是没有问题的,因为 true 告诉 header()替换 404 WordPress 已经设置并使用 HTTP 200 “Okay” 状态代码。

FireFox 这是什么样子 (请注意,屏幕截图没有/downloads/虚拟目录,因为在拍摄和注释屏幕截图后,似乎最好添加一个'/downloads/'虚拟目录):

UPDATE

如果您希望从一个前缀为/wp-admin/的 URL 处理下载,以向用户提供受到登录保护的可视指示,那么您也可以这样做:下面描述一种方法。

这次我封装成一个类,称为 DownloadCSV,并为 「管理员」 角色创建了一个名为 「download_csv」 的用户 「功能」(请阅读此处的角色和功能) 您可以搭载预定义的 「导出」 角色,如果你喜欢,如果是这样搜索& 用’export’ 替换’download_csv’,并删除 register_activation_hook() 调用和 activate() 函数。顺便说一句,需要一个激活钩子是我把这个移植到插件而不是保留在主题的 functions.php 文件中的一个原因。*

我还使用 add_submenu_page()从”Tools” 菜单中添加了”Download CSV” 菜单选项,并将其链接到'download_csv'功能。

最后我选择了'plugins_loaded'钩子,因为它是我可以使用的最早的适当钩子。你可以使用'admin_init',但这个钩子运行得比较晚 (第 1130 次钩子调用和第 3 个钩子调用),所以为什么让 WordPress 做更多的 throw-away 工作呢? (我用我的 Instrument Hooks plugin 找出要使用的钩子。)

在钩子中,我检查以确保我的 URL 从/wp-admin/tools.php 通过检查 $ pagenow 变量开始,我验证 current_user_can(‘download_csv’),如果通过,我测试 $ _GET [‘download’] 看它是否包含数据。 CSV; 如果是,我们几乎运行与之前相同的代码。我也删除了前面的例子中的来自 header() 的 200 的 true,因为这里 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();
}

这里是激活的插件的屏幕截图:

最后这是一个触发下载的屏幕截图:

次佳解决方案

一个更有用的插件,用于导出到 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();

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。