WordPressバックエンドでファイルを強制的にダウンロードするにはどうすればよいですか?


30

WordPressプラグインの1つに「クリックしてダウンロード」ボタンを追加したいのですが、使用するフックがわかりません。これまでのところ、「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

私があなたを正しく理解しているならあなたはブラウザへの応答があなたが生成するコンテンツ、つまりあなたの.CSVファイルであり、WordPressから生成されたコンテンツではない次のようなURLを持ちたいですか?

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れていることに注意してください。これは、WordPressがURLを認識しないため、「Not Found」ステータスコードを設定するためです。ただし、WordPressの設定を置き換え、HTTPの「OK」ステータスコードを代わりに使用するように指示されているため、問題はありません。header()Content-type404 trueheader()404200

FireFoxでの表示は次のとおりです(スクリーンショットに仮想ディレクトリが含まれていないことに注意してください。スクリーンショット/downloads/を作成して注釈を付けた後、'/downloads/'仮想ディレクトリを追加することをお勧めします)。

CSVファイルのダウンロードURLのスクリーンショット
(ソース:mikeschinkel.com

更新

/wp-admin/ログインによって保護されていることをユーザーに視覚的に示すために接頭辞が付いたURLからダウンロードを処理する場合は、同様に行うことができます。1つの方法の説明が続きます。

私はと呼ばれる、クラスにこの時間をカプセル化DownloadCSVし、作成したユーザーに「機能」と呼ばれる'download_csv'ために'administrator'役割(役割と機能について読んこちら あなただけの定義済みのオフ背負う可能性があり'export'、単に検索と置換あなたのようなので、もしあれば役割'download_csv'を呼び出しと関数'export'を削除しregister_activation_hook()ますactivate()。ところで、アクティベーションフックの必要性は、テーマのfunctions.phpファイルを保持するのではなく、これをプラグインに移動した理由の1つです。*

私はまた、追加、「ダウンロードCSV」オフメニューオプションを「ツール」使用してメニューadd_submenu_page()とそれをリンク'download_csv'機能。

最後に、'plugins_loaded'私が使用できる最も早い適切なフックであるため、フックを選択しました。使用できます'admin_init'が、そのフックはかなり後で実行されます(1130回目のフック呼び出しと3回目のフック呼び出し)。(使用するフックを特定するために、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.comWordPress管理者の[ツール]メニューのオプションからURLでファイルをダウンロードするスクリーンショット


マイク、助けてくれてありがとう。この機能の唯一の問題は、ファイルをバックエンドからダウンロードしたいということです。template_redirectがバックエンドで機能しないように見えます。admin_initを使用することになっていない場合、代わりに何を使用すべきか疑問に思います。admin_initは今はうまく機能しているように見えますが、少なくとも短期的にはそれを使い続けるでしょう。これはごく少数の人しか使用しないマイナーな機能です。
デイブ・モリス

@Dave Morris- 「バックエンド」の意味を定義できますか?サーバー上での意味ですか?はいの場合、'template_redirect'ほとんどの場合、サーバー上で実行されます。そうでない場合、私は完全に混乱したでしょう。懸念を明確にできますか?前もって感謝します。
MikeSchinkel

@Dave:「バックエンド」によって管理領域を意味する場合、これはまだ機能します。ダウンロードURLは/downloads/data.csv存在しないファイルで始まるため、WordPressの「フロントエンド」はこのリクエストを処理し、最終的にに到達しtemplate-redirectます。このフロントサイドURLを指すリンクを管理領域に作成するだけです。(この方法では、管理者ログイン保護を無料で取得できないと言わなければなりません。URLを知っている人なら誰でもファイルをダウンロードできますが、おそらくそれを修正する簡単な方法はありますか?)
Jan Fabry

@Jan Fabry-ああ、私は今理解しています。「バックエンド」と彼は右、管理者の中から意味しますか?彼current_user_can()は上記のコードで関数を使用するか、別のアプローチを取ることができます。このコメントの後、回答に更新を追加します。
MikeSchinkel

はい、申し訳ありませんが、このサイトから電子メールアラートを受信して​​いないため、返事の遅れを説明しています。「バックエンド」と言ったとき、私は確かにWordPressの管理領域に言及していました。ごめんなさい template_redirectを使用して、何が起こるか見てみましょう。ありがとう!〜デイブ
デイブ・モリス

3

CSVにエクスポートするためのもう1つの便利なプラグイン。誰かに役立つかもしれません

    <?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フックまたはload-(page)フックは機能しているようです。WordPressはこの状態でヘッダーを設定していません。管理メニューページが読み込まれたときに実行されるため、load-(page) Hook を使用しています。特定のページのスクリプトをロードできます。

WordPress Codexのload-(page)フックを確認できます

admin_initフックを使用している場合は、check_admin_refererまたは他のスクリプトを使用してnonceを確認してください。ダウンロードファイルを出力する条件が満たされる可能性があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.