Welcome to the WordPress jungle.

WordPress: admin-header

Let’s continue our descent into the murky depths of the WordPress jungle. We have arrived at wp-admin/admin-header.php
This is called on pretty much every admin page in WordPress. That’s why I promised to go over it in my previous WP Jungle article.


First, it sets the http header. It uses the options (html_type and blog_charset) that are set in the database (in wp-options.php). In case you wondered how these values got there, WordPress inserts them during the install procedure. You can check wp-admin/includes/schema.php for the complete SQL.


Next, WordPress checks if the constant WP_ADMIN has been set. If not, the bootstrap for admin sections is loaded.

If admin-header.php is being included from within a function, the variables defined in the loading process ($hook_suffix etc…) are not available. That’s why the global variables are explicitly referenced.

Another check follows, to see if $current_screen has been populated.


Most times, $title will have been populated (by the admin bootstrap) and nothing will happen in get_admin_page_title().
After this last check, $admin_title is built, followed by the filter ‘admin_title’, which gives you the opportunity to change it.


In the previous article, we covered screen options (how many pages to display, which columns in the …). They are stored in the wp_usermeta table. One special entry in wp_user_meta is wp_user-settings. These are options that are persistent across the whole admin interface.

For instance, say I chose to use the tradional media uploader in Media. Afterwards, I collapse the Admin sidebar. WordPress will save these settungs in wp_user_meta as:

  • user_id = current user’s id
  • meta_key = wp_user-settings
  • meta_value = a url string of all options

(Click the image for a larger version)

To avoid another call to the database on every admin page, this query string is also stored in a cookie. The wp_user_settings() function (located in option.php), checks if the cookie needs to be renewed.


This is a pretty simple function. It outputs

  • the doctype
  • the html opening tag
  • the head tag
  • a meta tag for Content-Type

It has two extra’s: a conditional comment for IE8 and a hook to output the XML namespace (if you should need it).


Next, you see two styles (colors and ie) and two scripts (utils and svg-painter) being enqueued. The fact that these are enqueued without a URL, means that WordPress already knows what files to load. The styles (or scripts) are already registered. If you do a dump of $wp_styles (make sure you refer the global), you indeed see that there is an object with the references to the styles.

Whenever you try to enqueue or register a new style, WordPress checks if a WP_Styles object already exists. If it doesn’t find one, it creates one.

In it’s __construct(), the WP_Styles class has a hook called wp_default_styles — It is hooked from wp-includes/default-filters.php. The function it references (wp_default_styles) is located in wp-includes/script-loader.php

It then uses the add method (Wp_Styles extends WP_Dependencies) To correctly add the default styles to the global $wp_styles object.

On most admin pages, colors is not the first enqueued style. _wp_admin_bar_init (in wp-includes/admin-bar.php) enqueues the styles for the admin bar. This is hooked on admin_init and will (most of the times) be the function that builds the WP_Styles object.

Note that colors is also a special case. In wp_style_loader_src, WordPress checks if the user has a specific color scheme (stored in a user option). If so, an extra CSS file is loaded.

The IE stylesheet has (as one would expect) some fixes for IE7 (yay backwards compatibility!). As for the scripts:

The next step is calculating the admin_body_class. This is done based on the $hook_suffix (see previous article).


WordPress then provides a sort of standardized way to load functions when your page has is loaded. You can pass a function into it: addLoadEvent(my_function); WordPress will then first try to use jQuery(document).ready. Failing so, it creates it’s own wpOnload function (or your function is added to an existing wpOnload).


WordPress now prints out a series of global variables (that were already available in PHP) for JavaScript. This includes the Ajax URL (which always should go through wp-admin).


Next, you’ll see a series of hooks to load custom stylesheets and scripts (from plugins and themes).

  • admin_enqueue_scripts (used to load your scripts/stylesheets on every admin page)
  • admin_print_styles-$hook_suffix (this fires when the styles for a specific admin page are actually printed (written tohtml). It doesn’t fit into the normal enqeueing, so it shouldn’t be used to add your own scripts and styles).
  • admin_print_styles (same as the above one, but fires on every admin page)
  • admin_print_scripts-$hook_suffix (same as the one for styles — note there is also an action in admin-footer.php for scripts that are enqueued to the bottom).
  • admin_print_scripts (same as the one for styles — note there is also an action in admin-footer.php for scripts that are enqueued to the bottom)


Almost at the body element now! First, there are two admin_head hooks. One specific to the page type (based on $hook_suffix), followed by a global one.

WordPress now adds a load of HTML classes to a variable ($admin_body_class). They include user options (menu folded), if the writing direction is RTL, the WordPress version…

Afterwards, you get a filter (admin_body_class) to add your own classes.

Both are added to the body element. WordPress also adds a no-js class which is is immediately removed with an inline script (actually the first thing in the body).


The customizer needs to have this class set to customize as early as possible to prevent Flash of Unstyled content.


WordPress now adds a tab index (for accessibility).

This is followed by requiring a file (wp-admin/menu-header.php) that is responsible for displaying the (sidebar) menu for the admin. (Remember the menu was built in wp-admin/menu.php, which was called from wp-admin/admin.php).

The first hook (at the start of the admin content) is in_admin_header. It is used to load the admin bar.

After the admin bar is loaded, WordPress deletes some variables that were used in the admin bar.


Each admin page determines a parent, even if it is a top level page (in the menu). A string (without the .php extension and without query variables is saved to the Screen object).


The Screen object then loads a method for old plugins that use deprecated ways of manipulating the help menu.

You now get a few hooks to add admin notices (when publishing a post etc…)