How to serve file downloads from WordPress plugin

Every once in a while plugins you develop will have to serve dynamically generated files. Eg. you have some data and you want the user to be able to download it in CSV format. Generally speaking that is not such a hard task, you figure out what headers you need to send and after that you serve the file content. However, due to the wordpress actions/hooks system you’ll have to hook somewhere before other headers are sent.

  1. Where to hook your code
  2. Design your actual solution

Where to hook your code

The most appropriate place to hook your code is the init hook. Most of WordPress is loaded at that stage and if you run your function with priority 1 and place an `exit` at the end of it you should achieve returning the file and stopping any other execution for that particular request.

Design your actual solution

The solution is not very complicated so I’ll just paste it below:

//functions.php
add_action('init', function(){
    if ((bool) $_GET['export'] == true && ($_GET['type'] == 'dummydata1' || $_GET['type'] == 'dummydata2') && is_admin()) {
            header('Content-Type: text/csv; charset=utf-8');
            header('Content-Disposition: attachment; filename='.uniqid().'.csv');
            header('Pragma: no-cache');
            header('Expires: 0');

            $output = fopen('php://output', 'w');
            fputcsv($output, ['URL', 'Hits']);
            
            if ($_GET['type'] == 'dummydata1') {
                    //...
                    //Some business logic here
                    return ['test.net' => (object)['hits' => 131];
                };
            }
            if ($_GET['type'] == 'dummydata2') {
                    //...
                    //Some business logic here
                    return ['test1.net' => (object)['hits' => 142];
                };
            }

            foreach ($transformSubmissions() as $url => $goal) {
                fputcsv($output, [$this->punnycoder->decode($url), $goal->hits]);
            }
            exit;
        }
}, 1);

What this does is return a CSV based on the type $_GET[‘parameter’], obviously I’m missing the most of the business logic, but the principle is there.

You can download the code for this how-to in
About Pavel Petrov 2 Articles |  21 How-tos
Pavel is a senior developer for the last 7 years, with extended interest in Linux administration, WordPress and Symfony.

Be the first to comment

Leave a Reply

Your email address will not be published.


*