WordPress admin_init hook and the elusive typenow

This post is more than 11 years old.

In my quest to bring an object oriented separation of concerns to my WordPress plugins, I tend to separate the administration of each custom post type into its own class. I do this by looking at the global variable $typenow after the admin_init action is fired. But $typenow isn’t always set after admin_init, so I have to improvise a little.

$typenow is supposed to hold the post type of the current post being actioned. When listing posts, creating a new post, or trashing / deleting a post, I can access $typenow to find out whether to handle the action. Of course, it won’t have a value when the WordPress admin isn’t dealing with a post, but I’ve found two circumstances when it doesn’t have a value when I think it should:

  • editing a post
  • saving a quick edit to a post

In both those situations, admin_init is called without $typenow being set. Luckily, the ID of the post being edited can be used to find out the post’s type. I have to give credit for this idea to WooCommerce, who showed me the way (reading other people’s source code can be very insightful!)

Here’s an excerpt for the class that manages the admin side of a winery data plugin I’ve co-written with Michael Major Media. The full class is about 720 lines long at present, so I’ve clipped it to just the bits about getting $typenow in the admin_init hook.

class WpWinePagesAdmin {

    public function __construct() {
        // handle admin init action
        add_action('admin_init', array($this, 'actionAdminInit'));

        // and the rest...
    }

    /**
    * handle admin init action
    */
    public function actionAdminInit() {
        global $typenow;

        // when editing pages, $typenow isn't set until later!
        if (empty($typenow)) {
            // try to pick it up from the query string
            if (!empty($_GET['post'])) {
                $post = get_post($_GET['post']);
                $typenow = $post->post_type;
            }
            // try to pick it up from the quick edit AJAX post
            elseif (!empty($_POST['post_ID'])) {
                $post = get_post($_POST['post_ID']);
                $typenow = $post->post_type;
            }
        }

        // check for one of our custom post types,
        // and start admin handling for that type
        switch ($typenow) {
            case WP_WINE_PAGES_TYPE_DIST:
                new WpWinePagesDistributorAdmin();
                break;

            case WP_WINE_PAGES_TYPE_RANGE:
                new WpWinePagesProductRangeAdmin();
                break;

            case WP_WINE_PAGES_TYPE_PRODUCT:
                new WpWinePagesProductAdmin();
                break;

            case WP_WINE_PAGES_TYPE_AWARD:
                new WpWinePagesAwardAdmin();
                break;

            case WP_WINE_PAGES_TYPE_REVIEW:
                new WpWinePagesReviewAdmin();
                break;
        }
    }

    // and the rest ...
}

And job is done, even when WordPress’ job isn’t quite done.