I’m sure you woke up thinking “I wish I knew more about WordPress loading.”. Ok… maybe not (it’s just me isn’t it?). It’s just not something you deal with every day.
No, plugins and themes make up your days. That’s what you use to build your custom WordPress solutions. There’s no need to know about the internal process that starts up WordPress.
Yet you can’t ignore it once you start building complex WordPress solutions. Or if you plan on distributing a plugin or theme. That changes the dynamic of things.
Your little world with the plugins and themes you know is gone. You’re in the larger (and messier) WordPress world now. That means you have to play nice with everyone else (damn).
That’s why loading is important
A good understanding of the WordPress loading process helps you navigate these troubled waters. It’s where you can make the changes required to make your plugin play nice with others. You can also use it to detect potential issues that might affect how your plugin works.
The loading process is also the starting point to build advanced functionality into WordPress. Your plugin is preparing to change WordPress in a fundamental way. You can make global changes such as:
- Registering custom post types
- Adding rewrite rules
- Adding new query variables
- Change the order WordPress loads plugins
Your plugin becomes a little voice whispering in WordPress’s ear. Telling it that it’s now something that it didn’t use to be. It can handle situations it couldn’t before.
Let’s define the loading process
Ok, so what’s the loading process? The best way to define it is by defining its boundaries. To do that, we’ll need a starting point and an end point.
Let’s start with what triggers the WordPress loading process. WordPress begins loading whenever PHP processes one of its entry points. PHP then continues processing specific files. This sequence only varies in special situations which you’ll see later.
For the end point, we’re going to use the “wp_loaded” hook. As the name suggests, WordPress calls this hook when it completed the loading process. It’s the last hook called before WordPress setups the query used by the loop. It’s worth noting that there’s another hook later in the WordPress admin. That said, we’ll pick something that works for all situations.
What files are involved?
The files involved in the WordPress loading process tells us a lot about it. There’s core files that WordPress uses in every situation. Each file serves a singular purpose in the process.
You also have special situations that change how the process behaves. We’ll go over them as well.
Core files
Core files make up most of the loading process. WordPress always uses them regardless of the situation. They’re listed here in the order that PHP processes them.
wp-load.php
“wp-load.php” has a misleading name. You’d think that it’s about loading WordPress (I mean look at that name…). You’d be wrong though (damnit!).
It’s a small file with a single purpose. It checks for “wp-config.php” in the current directory or the one above. If it finds one, WordPress goes on its merry way. If it doesn’t, you get an error page that asks you to create one.
wp-config.php
Without question, one of the most critical files in all WordPress. “wp-config.php” contains all the configuration details for your WordPress site. We won’t cover all the configuration details here. You can find an excellent documentation on them in the codex.
“wp-config.php” is an important file for another reason. It’s the first WordPress file that you can change without “hacking core”. WordPress doesn’t touch it when you update it. This combined with how early PHP processes it creates a unique opportunity.
An opportunity to install PHP libraries
It allows you to install other PHP libraries (like Twig) in a safer manner. By being in “wp-config.php”, WordPress loads them before any plugin (or anything really). This is what makes it safer. You don’t have to worry the order WordPress would load them if they were in plugins.
This isn’t something anyone can do though. You need to have full control on your WordPress installation. That’s because you need to edit “wp-config.php” to add the libraries.
wp-settings.php
“wp-settings.php” is where the meat of the loading process takes pace. The meat here is just a long set of “require” statements. These statements signal PHP to load most of the WordPress code.
There’re two interesting things with “wp-settings.php”. First, it’s where all the hooks in the loading process are. We’ll cover them a bit later. It’s also where WordPress loads both “must-use” and active plugins.
For some plugins, the order WordPress loads them is crucial. That’s why it’s worth taking a moment to discuss how WordPress does it and how you can change it.
How WordPress loads “must-use” plugins
WordPress starts by loading all the “must-use” plugins. The use of the term plugin is deceiving here. WordPress doesn’t care if they’re plugins or not.
WordPress scans for PHP files in the root of the directory defined by “WPMU_PLUGIN_DIR” (default is “mu-plugins”). It won’t scan for folders like it does in the “plugins” folder. Once it’s done scanning, WordPress includes each file in alphabetical order. Changing the file name is the only way to change that order.
How WordPress loads active plugins
The way WordPress loads active plugins is different from “must-use” plugins. There’s no folder scanning done. Rather, WordPress relies on options to decide which plugins to load.
Those two options are “active_sitewide_plugins” and “active_plugins”. The first option defines the list of “Network Active” plugins. This option only applies to multisite installations. The second option is for your regular active plugins that you use every day.
Each option contains a serialized array of plugin names. WordPress loads each plugin in order that the array lists them. You can alter the load order by modifying the order of the plugins in the options. You can do this by using the “pre_update_site_option_active_sitewide_plugins” and/or “pre_update_option_active_plugins” hooks.
These hooks let you change the array of active plugins before WordPress saves it. Here’s a quick example to show you how to do it.
/** * Ensures that the plugin is always the first one to be loaded. * * @param array $active_plugins * * @return array */ public function ensure_loaded_first(array $active_plugins) { $basename = plugin_basename(__FILE__); $key = array_search($basename, $active_plugins); if (false !== $key) { array_splice($active_plugins, $key, 1); array_unshift($active_plugins, $basename); } return $active_plugins; } add_filter('pre_update_option_active_plugins', 'ensure_loaded_first'); add_filter('pre_update_site_option_active_sitewide_plugins', 'ensure_loaded_first');
First, you need the value that WordPress stores in “active_plugins” for your plugin. You get that value by using the “plugin_basename” function. You use “array_search” to find the array key that stores that value. If the array key isn’t false, it means that your plugin is active. You remove the value from the array using “array_splice” and the array key. You can then reinsert it at the top with “array_unshift“.
pluggable.php
Once WordPress finished loading all the “must-use” and active plugins, it loads “pluggable.php”. It contains all WordPress pluggable functions. These are functions that plugins can override.
functions.php
To clarify, we’re talking about the “functions.php” found in the current theme here. Unless the theme is a child theme. In that case, we’re talking about the parent theme’s and the child theme’s “functions.php”. That’s because the two have a special relationship.
WordPress loads the child theme’s “functions.php” before the parent theme’s. This is something to keep in mind when you code a child theme. You won’t be able to use functions from the parent theme in the child theme right away. You have to wait until WordPress finishes the theme setup.
It’s worth noting that WordPress loads “functions.php” after “pluggable.php”. A theme can’t use it to override core WordPress functions. This is how WordPress limits that ability to plugins only.
Special situations
There are some situations where WordPress needs to alter the way it loads. This impacts the files that WordPress loads and the constants it creates. It also dictates what WordPress functionality is available to you.
Multisite
WordPress weaves multisite functionality into the regular loading process. It does so by using the “is_multisite” function at specific locations. If “is_multisite” returns true, it adds more files to the loading process.
WordPress multisite files use the prefix “ms-” instead of nothing or “wp-“. The prefix is how you set them apart from their core file counterparts. For example, “ms-settings.php” takes care of most of the multisite loading like “wp-settings.php” does. Two files are outside that convention.
There’s “ms-blogs.php”. It contains functions for interacting with the new multisite database tables.
There’s also “sunrise.php”. “ms-settings.php” loads this “sunrise.php” when you define the constant “SUNRISE”. A developer uses this file to hijack the multisite blog loading process. He does so by setting the “current_site” and “current_blog” variables before WordPress sets them.
The better-known example of its use is the domain mapping plugin. The codex doesn’t have documentation on it at the moment. You can refer to the original Trac ticket for some details.
WordPress Admin
All WordPress admin pages use “wp-admin/admin.php” to begin the loading process. The file starts by defining the constant “WP_ADMIN”. This is the flag that WordPress uses to let you know if you’re in the WordPress admin.
It processes “wp-load.php” right after. This goes through the regular WordPress loading procedure that you saw earlier. Once that’s done, WordPress continues admin loading process.
There’s a lot more to this process. It extends beyond the boundaries that were set earlier. Rather than cover it now, we’ll do it with another article in the future.
AJAX
AJAX calls are a bit of a unique snowflake. Everything happens in “admin-ajax.php”. That’s the dedicated AJAX entry point.
Not only is the entry point the same for both logged-in users and logged-out users. It’s the same for both the WordPress admin and frontend as well. This is what makes AJAX so particular. It needs to do a variety things to cover everyone’s needs.
It starts by defining the “WP_ADMIN” constant to cover AJAX calls to the admin. It also defines its own “DOING_AJAX” constant. This is the flag that WordPress uses to let others know it’s in an AJAX process.
WordPress defines the “WP_ADMIN” constant but doesn’t go through the standard admin loading process. Instead, it uses “wp-load.php” as it would on the frontend. WordPress then loads the admin APIs through “wp-admin/includes/admin.php” as an extra step.
The final step is to add all the AJAX specific hooks. They’re all found in “ajax-actions.php”. This is a file that WordPress only loads for AJAX calls.
Hooks
Hooks are the other important aspect of the WordPress loading process. It’s where you can come in and make changes to the core of WordPress. Each hook you’ll see represents a specific step in that process.
They tend to have self-explanatory names. This makes it easy to understand their purpose. The tricky part is knowing what parts of WordPress are available when they’re called.
We’ll cover each hook in the order that they show up in “wp-settings.php”. That’s where you can find them all.
muplugins_loaded
Did you ever wonder what’s the first hook in all WordPress was? Well, here is the answer. This is the one! It’s also the hook with the most limitations.
Most plugins can’t use that hook. It’s called before WordPress loads them. The only plugins loaded at that point are “must-use” and “Network Active” plugins. That means that the hook is only available to them.
This is why the hook has limited uses. It requires a specific situation. One that needs you to make changes to those plugins before WordPress loads the others. Otherwise, you can just use the next hook.
plugins_loaded
Another self-explanatory hook. If we ignore other plugin hooks, this is the first hook that every plugin has access to. It’s a great hook to use when you want to do some extra configuration.
You can use to do dynamic changes to your plugin. Do you have a custom integration with WooCommerce? You can check if the plugin is active and add the custom integration as needed.
sanitize_comment_cookies
You won’t see this hook used that often. It’s only used by the WordPress function with the same name. That’s because it’s right next to the popular “plugins_loaded” hook.
There are only two small differences between the two hooks. WordPress loaded a few more conditional constants. It also did a pass to standardize all PHP superglobals. That’s it.
setup_theme
WordPress fires this hook right before it begins setting up the current theme. You use this hook when you want to change the current theme in a fundamental way. It’s used in specific circumstances.
One of those is the WordPress customizer. It uses the hook to detect when you’re previewing the site. If that’s the case, it adds extra filters to change your current theme. This makes it ready for preview.
after_setup_theme
This is the first WordPress hook themes get access to. It’s also the first hook (outside theme specific hooks) available after WordPress loaded the current theme. You can use the parent and child theme “functions.php” now.
This makes it an ideal location for making a dynamic change to a theme. Let’s say you want to add a theme feature with “add_theme_support“. This is the preferred hook to do so. That’s because you can only activate some feature (e.g. post thumbnails) on this hook.
init
At this point, you’re probably telling yourself:
Man, this is a lot of hooks to remember. Couldn’t there be one hook that covers 90% of my needs?
Well, look no further! This is the hook you need (but maybe not the hook you deserve?). Most plugins use the “init” hook to interact with the WordPress loading process.
It’s useful because you don’t have to worry about a lot of things anymore. All WordPress functions are available. It authenticated the user. It hasn’t sent any headers back so you can still change them. You’re in a safe spot to make your changes.
That said, before you go and use “init” hooks everywhere. You should take a look at this next hook.
wp_loaded
This and the “init” hook share almost the same timing. There’s only one minor difference. If you’re using multisite, it checks the status of the blog. If the blog fails the check, WordPress terminates.
This small difference makes it preferable to the all mighty “init” hook. You don’t want your code running on invalid subsites (or do you…). Using this hook instead of the “init” hook makes this a no-brainer for you.
And that’s it!
Whew! That was quite a bit to digest.
Whether it’s your favorite WordPress feature or your favorite plugin. Most of them leverage the WordPress loading process in some way. There’s just no way around it once you start building advanced WordPress solutions.
Don’t let that hold you back though. Use this as a reference for your future endeavors.