Posts tagged with: WordPress

← Back to all tags

A handy note for future-me or any other WordPress plugin developers:

If you need a plugin admin link that performs a download (e.g. a CSV file), you will need to use a hook that is called earlier in the process, before WP sends HTTP headers/content to the browser.

With a typical plugin admin page that displays content, I would use:

add_action( 'admin_menu', 'foo_add_menu' );

Then in function foo_add_menu(), I would use add_menu_page like:

// my example is OO, so $this points to the object and calls the index() method
add_menu_page(
    'Plugin Page Title', 
    'Plugin Menu Title', 
    'edit_posts', 
    $this->plugin_name . '_index', 
    [$this, 'index'], 
    ''
);

If you try to do this with a method that starts a download, you will get errors like “Cannot modify header information.” This StackOverflow answer pointed me in the direction of the load-page hook to solve that.

That documentation is a bit slim, but what I figured out was add_menu_page() returns a hook name. You can take that hook name, prefix “load-”, and use the resulting string as the hook name in an add_action().

In my example above, let’s say the plugin name is “foo_plugin” and replace “index” with “download”. The resulting hook name would be:

load-admin_page_foo_plugin_download

Then I can use:

add_action( 'load-admin_page_foo_plugin_download', 'download' );

(Be careful with the hyphen vs underscores in that)

Finally, within the download() class method, I can safely modify HTTP headers to start a download:

header('Content-type: text/csv; charset=utf8');
// other headers and content...


Screenshot of Matt Mullenweg's Wikipedia page with 'trademark infringement' added after the word 'WordPress', in the style of the 'citation needed' template

Just making some small Wikipedia edits today.

(Not really, it’s just a browser preview 😂)