Làm cách nào tôi có thể buộc tải xuống tệp trong phần phụ trợ WordPress?


30

Tôi muốn thêm nút "Nhấp để tải xuống" vào một trong các plugin WordPress của mình và tôi không chắc chắn nên sử dụng hook nào. Cho đến nay, việc nối 'admin_init' vào mã này dường như hoạt động:

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

Điều này có vẻ hiệu quả, nhưng tôi chỉ muốn xem liệu có một thực hành tốt nhất ngoài đó.

Cảm ơn, Dave

Câu trả lời:


39

Nếu tôi hiểu bạn một cách chính xác, bạn muốn có một URL giống như sau đây mà phản hồi của bạn đối với trình duyệt sẽ là nội dung bạn tạo, tức là .CSVtệp của bạn và không có nội dung được tạo từ WordPress?

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

Tôi nghĩ rằng bạn đang tìm kiếm 'template_redirect'hook. Bạn có thể tìm thấy 'template_redirect'trong /wp-includes/template-loader.phpđó một tệp mà tất cả các nhà phát triển WordPress nên làm quen với; nó ngắn và ngọt ngào và định tuyến cho mỗi lần tải trang không phải của quản trị viên, vì vậy hãy chắc chắn xem qua nó.

Chỉ cần thêm phần sau vào functions.phptệp của chủ đề của bạn hoặc trong tệp khác mà bạn includetham gia 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();
  }
}

Lưu ý kiểm tra '/downloads/data.csv'URL bằng cách kiểm tra $_SERVER['REQUEST_URI']. Cũng lưu ý thêm vào cuộc gọi ,true,200của bạn header(), nơi bạn đặt Content-type; điều này là do WordPress sẽ đặt mã trạng thái 404 "Không tìm thấy" vì nó không nhận ra URL. Mặc dù vậy, không có vấn đề gì khi truenói header()thay thế 404WordPress đã đặt và sử dụng mã trạng thái 200 "Okay" HTTP thay thế.

Và đây là giao diện của FireFox ( Lưu ý ảnh chụp màn hình không có /downloads/thư mục ảo vì sau khi chụp và chú thích ảnh chụp màn hình, có vẻ như đó là một ý tưởng hay để thêm '/downloads/'thư mục ảo):

Ảnh chụp màn hình của URL tải xuống cho tệp CSV
(nguồn: mikechinkel.com )

CẬP NHẬT

Nếu bạn muốn tải xuống được xử lý từ một URL có tiền tố /wp-admin/để cung cấp cho người dùng dấu hiệu trực quan rằng nó được bảo vệ bởi thông tin đăng nhập, bạn cũng có thể làm điều đó; mô tả về một cách sau.

Lần này tôi đã gói gọn vào một lớp, được gọi DownloadCSVvà để tạo ra "khả năng" của người dùng được gọi 'download_csv'cho 'administrator'vai trò (đọc về Vai trò và Khả năng ở đây ) Bạn có thể cõng 'export'vai trò được xác định trước nếu muốn và nếu vậy chỉ cần tìm kiếm & thay thế 'download_csv'bằng 'export'và loại bỏ register_activation_hook()cuộc gọi và activate()chức năng. Nhân tiện, nhu cầu về móc kích hoạt là một lý do khiến tôi chuyển cái này sang plugin thay vì giữ trong functions.phptệp của chủ đề . *

Tôi cũng đã thêm tùy chọn menu "Tải xuống CSV" khỏi menu "Công cụ" bằng cách sử dụng add_submenu_page()và liên kết nó với 'download_csv'khả năng.

Cuối cùng tôi đã chọn 'plugins_loaded'móc vì đó là móc thích hợp sớm nhất tôi có thể sử dụng. Bạn có thể sử dụng 'admin_init'nhưng hook đó được chạy muộn hơn nhiều (cuộc gọi hook thứ 1130 so với cuộc gọi hook thứ 3) vậy tại sao lại để WordPress thực hiện nhiều công việc vứt bỏ hơn mức cần thiết? (Tôi đã sử dụng plugin Cụ móc của mình để tìm ra cách sử dụng móc nào.)

Trong hook tôi kiểm tra để đảm bảo URL của tôi bắt đầu bằng /wp-admin/tools.phpcách kiểm tra $pagenowbiến, tôi xác minh điều đó current_user_can('download_csv')và nếu điều đó vượt qua thì tôi sẽ kiểm tra $_GET['download']xem nó có chứa hay không data.csv; nếu có, chúng tôi thực tế chạy mã giống như trước đây. Tôi cũng xóa ,true,200từ cuộc gọi đến header()trong ví dụ trước vì ở đây WordPress biết đó là một URL tốt nên chưa đặt trạng thái 404. Vì vậy, đây là mã của bạn:

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

Và đây là một ảnh chụp màn hình của plugin được kích hoạt: (nguồn: mikechinkel.com )Ảnh chụp màn hình của Trang Plugin hiển thị một plugin được kích hoạt

Và cuối cùng đây là một ảnh chụp màn hình kích hoạt tải xuống: (nguồn: mikechinkel.com )Ảnh chụp màn hình Tải xuống tệp bằng URL từ một tùy chọn trong menu Công cụ của quản trị viên WordPress


Mike, cảm ơn sự giúp đỡ của bạn. Điều hấp dẫn duy nhất với tính năng này là tôi muốn tệp được tải xuống từ phụ trợ. Có vẻ như template_redirect không hoạt động trong phần phụ trợ và nếu tôi không nên sử dụng admin_init, tôi tự hỏi tôi nên sử dụng cái gì thay thế. admin_init dường như làm việc với tôi bây giờ, tôi có thể gắn bó với nó ít nhất là trong thời gian ngắn. Đây là một tính năng nhỏ mà chỉ một vài người sẽ sử dụng.
Dave Morris

@Dave Morris - Bạn có thể định nghĩa những gì bạn có nghĩa là "back end" không? Bạn có nghĩa là trên máy chủ? Nếu có, 'template_redirect'chắc chắn nhất là chạy trên máy chủ. Nếu không, tôi hoàn toàn bối rối; bạn có thể làm rõ mối quan tâm? Cảm ơn trước.
MikeSchinkel

@Dave: Nếu bạn có nghĩa là khu vực quản trị theo "back end", điều này sẽ vẫn hoạt động. URL tải xuống bắt đầu bằng /downloads/data.csv, đây là một tệp không tồn tại, do đó, "giao diện người dùng" của WordPress sẽ xử lý yêu cầu này và cuối cùng đạt được template-redirect. Bạn chỉ cần tạo một liên kết trong khu vực quản trị trỏ đến URL mặt trước này. (Phải nói rằng theo cách này, bạn không được bảo vệ đăng nhập quản trị viên miễn phí - bất kỳ ai biết URL đều có thể tải xuống tệp, nhưng có thể có một cách dễ dàng để khắc phục điều đó?)
Jan Fabry

@Jan Fabry - À, giờ thì tôi đã hiểu. Bằng cách "trở lại kết thúc" , ông có nghĩa là từ bên trong admin, phải không? Anh ta có thể sử dụng hàm current_user_can()với mã trên hoặc thực hiện một cách tiếp cận khác. Sau bình luận này tôi sẽ thêm một bản cập nhật cho câu trả lời của tôi.
MikeSchinkel

Có, tôi xin lỗi, tôi không nhận được thông báo qua email từ trang web này, vì vậy điều đó giải thích cho sự chậm trễ của tôi khi trả lời lại. Tôi thực sự đã đề cập đến khu vực quản trị của WordPress khi tôi nói "phụ trợ". Xin lỗi vì điều đó. Tôi sẽ thử sử dụng template_redirect và xem điều gì sẽ xảy ra. Cảm ơn! ~ Dave
Dave Morris

3

thêm một plugin hữu ích để xuất sang CSV. có thể hữu ích cho một số

    <?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 hoặc load- (page) Hook dường như hoạt động, WordPress chưa được đặt tiêu đề ở trạng thái này. Tôi đang sử dụng hook- (trang) Hook vì nó chạy khi trang menu quản trị được tải. Bạn có thể tải tập lệnh của bạn cho trang cụ thể.

Bạn có thể kiểm tra tải- (trang) Hook trên WordPress Codex

Nếu bạn đang sử dụng admin_init Hook, hãy đảm bảo xác minh nonce bằng check_admin_Vferer hoặc tập lệnh khác có thể vượt qua điều kiện sẽ nhận được đầu ra tệp tải xuống của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.