While developing a WordPress plugin I stumbled upon the following annoying problem:
My plugin consists of several interlinked pages with forms on them, like a wizzard. They’re integrated into the WordPress admin environment by means of the handy add_menu_page
and add_submenu_page
-functions. I want to check the result of the forms and advance the user to the next page using wp_redirect
whenever I have sufficient input. Pretty easy for a standalone php webpage: check the $_POST
-array, do whatever you have to do and redirect the browser to the next page when you’re satisfied before outputting any html (not even a space or carriage return).
However, my pages are never called directly. They exist inside WordPress’ admin.php
page, and admin.php
outputs the top part of the page before my code is even called. This means that the HTTP-redirect will always fail. You simply cannot send HTTP-Headers somewhere in the middle of the HTTP-body (i.e. the actual html).
Thinking about it, I thought I had two options:
- hook into WordPress’
init
orsend_headers
hooks. These are called before any html-output. - call my php-files directly in the forms
action
and replicate alladmin.php
-code inside them.
I didn’t like the first option ’cause init
or send_headers
are called for every pageview, and I’d have to find out whether the request originated from one of my forms. Plus I’d have to seperate all application logic in one central place, away from the actual pages. I didn’t like the second option ’cause I’d have to track the WordPress core pretty tightly to make sure none of my replicated code contained any newfound WordPress bugs. However, upon inspecting admin.php
, I found a third option.
admin.php
won’t output anything if you call your plugin page with an optional &noheader
GET argument, but it will setup the whole WordPress environment for you. I’m quite happy: all I have to do is change my forms action
from this
<form method="post" action="admin.php?page=your_plugin_page.php">
to this
<form method="post" action="admin.php?page=your_plugin_page.php&noheader">
and I can redirect to my hearts content. You can make it draw the menu with this bit of code:
/* this strange thing makes WordPress output the admin header whenever we need it we turn the header off with "&noheader" so we can redirect with WP_Redirect */ if (isset($_GET['noheader'])) require_once(ABSPATH . 'wp-admin/admin-header.php');
after you’ve done your validation and possible redirection.