Redirecting from Custom Admin Page Produces “Headers already sent”

I’ve registered a custom Admin page in my plugin through add_submenu_page. In the callback function (the one that generates the contents of the admin page), I have the following code:

wp_redirect('http://google.com');
exit;

However, when I visit the admin page I get an error:

Warning: Cannot modify header information - headers already sent by (output started at ..wp-adminincludestemplate.php:1637) in ..wp-includespluggable.php on line 878

Related posts

Leave a Reply

1 comment

  1. The callback from add_submenu_page happens too late (after the admin sidebar and header are rendered), this is why the location header can not be sent anymore.

    To accomplish this, we need to hook a function a bit earlier in the WordPress admin area, before the headers are sent (e.g. admin_init).

    A good way:

    function myplugin_preprocess_pages($value){
        global $pagenow;
        $page = (isset($_REQUEST['page']) ? $_REQUEST['page'] : false);
        if($pagenow=='admin.php' && $page=='myplugin-custom-page-slug'){
            wp_redirect('http://google.com');
            exit;
        }
    }
    add_action('admin_init', 'myplugin_preprocess_pages');
    

    The above code will redirect you to Google whenever you try to view wp-admin/admin.php?page=myplugin-custom-page-slug.

    In my case, I’ve attached the custom page via add_submenu_page to the default (admin.php) parent in the Admin area and I’ve set the custom page’s slug to myplugin-custom-page-slug. Feel free to replace the values in the code above or even add a PHP switch if you have a lot of custom admin pages.

    This way we have hooked early enough to do a redirection whenever our custom admin page is viewed.

    Update: (A different approach)

    Thanks to this post, I’ve learned that WordPress creates a unique action that you can hook to for each custom admin page (load-{parent_page_slug}_page_{plugin_subpage_slug}). For example, if you’ve added a custom admin page with parent admin.php and slug myplugin-custom-page, you can hook to its “load” action in the following manner:

    add_action( 'load-admin_page_myplugin-custom-page', 'myplugin_custom_page_redirect' );
    function myplugin_custom_page_redirect() {
        if ( 'myplugin-custom-page' == filter_input( INPUT_GET, 'page' ) ) {
            wp_redirect( 'http://google.com' );
            exit;
        }
    }
    

    Note that the action name has some things to consider. It’s a mixture of underscores and dashes and make sure you only include the parent page’s name without the extension (so “admin” instead of “admin.php”)