Chrome for Android fix.

Demystifying The WordPress Bootstrap Process

Alain Schlesser
Software Engineer & WordPress Consultant

Photo by @praetorim

Alexandre Gustave Eiffel

Commemorative stone
in Marmagen, Germany

Photo by @praetorim

Journey Into The Unknown

Do you dare to join?

Beware!

Enter the Dungeons of Moria Bootstrap at your own risk!

General Overview

What is "Bootstrapping"? (1/3)

  • Code to prepare the environment

  • Not part of the actual logic that solves a problem

  • Often used to abstract away differences between platforms

What is "Bootstrapping"? (2/3)

What is "Bootstrapping"? (3/3)

General execution flow

Order of loading files (1/1)

Front-end request

Entry point
index.php

Load WordPress environment and template
wp-blog-header.php

Load the WordPress library
wp-load.php

Set up the WordPress query
wp()

Load the theme template
WPINC/template-loader.php

Order of loading files (2/2)

Back-end request

Entry point
wp-admin/index.php

Load WordPress environment and template
wp-admin/admin.php

Load the WordPress library
wp-load.php

Set up the WordPress query
wp_dashboard()

Order of loading files (3/3)

Inside wp-load.php

Load configuration

Set up the environment

Load Plugin API

Set up database

Set up cache

Load multisite

Load localization

[Run 5-minute-installation if needed]

Load rest of WordPress

...

wp-config.php

wp-settings.php

plugin.php

wp-db.php [ && db.php ]

cache.php [ || object-cache.php ]

ms-blogs.php & ms-settings.php

l10n.php & class-wp-locale.php

wp_not_installed()

Long list of require calls

...

Going Into More Detail

Notable Constants

  • ABSPATHPath to the root folder of the WordPress installation
  • SHORT_INITShort-circuit WP loading to run a minimal system
  • MULTISITEEnable multisite network
  • IS_SUBDOMAIN_INSTALLWhether multisite is a subdomain or subfolder network
  • WP_LANG_DIRPath to translation files
  • DOING_AJAXCurrent request is an AJAX request
  • IFRAME_REQUESTCurrent request is an IFrame request
  • WP_INSTALLINGPart of the installation routine, skip plugins/theme

Full reference in wp-core-bootstrap/documentation on GitHub (WIP)

Notable Global Variables

  • $blog_idID of currently active site in a network
  • $pagenowCurrently active page
  • $current_userCurrently active user
  • $wpdbDatabase abstraction in use
  • $wp_object_cacheCache abstraction in use
  • $wp_queryCurrently active database query
  • $wp_filterHooks registered through the Plugin API
  • $current_siteCurrently active WP_Network
  • $current_blogCurrently active WP_Site

Full reference in wp-core-bootstrap/documentation on GitHub (WIP)

Plugin API initialization

  • Class declaration for WP_Hook is loaded early in wp-settings.php

  • Fetches existing hooks from global $wp_filter, in case drop-ins have added filter manually before the Plugin API was ready

  • Some hooks run before plugins, so can only be used by non-web runtimes:
    enable_loading_advanced_cache_dropin
    enable_maintenance_mode
    enable_wp_debug_mode_checks

  • Huge list of hooks * preloaded through WPINC/default-filters.php

Pluggable Functionality (1/2)

Pluggable Files in WP_CONTENT_DIR ("drop-ins")

  • advanced-cache.phpAdvanced caching plugin
    (only when WP_CACHE=true)
  • db.phpCustom database class
  • db-error.phpCustom database error message
  • install.phpCustom install script
  • maintenance.phpCustom maintenance message
  • object-cache.phpExternal object cache
Multisite only
  • sunrise.phpExecuted before Multisite is loaded
    (only when SUNRISE=true)
  • blog-deleted.phpCustom site deleted message
  • blog-inactive.phpCustom site inactive message
  • blog-suspended.phpCustom site suspended message

Pluggable Functionality (2/2)

Pluggable Functions in WPINC/pluggable.php

  • wp_set_current_userChange the current user by ID or name
  • wp_get_current_userRetrieve the current user object
  • get_userdataRetrieve user info by user ID
  • get_user_byRetrieve user info by a given field
  • cache_usersRetrieve info for user lists to prevent multiple queries by get_userdata()
  • wp_mailSend mail, similar to PHP's mail
  • wp_authenticateAuthenticate a user, confirming the login credentials are valid
  • wp_logoutLog the current user out
  • wp_validate_auth_cookieValidates authentication cookie
  • wp_generate_auth_cookieGenerate authentication cookie contents
  • wp_parse_auth_cookieParse a cookie into its components
  • wp_set_auth_cookieLog in a user by setting authentication cookies
  • wp_clear_auth_cookieRemoves all of the cookies associated with authentication
  • is_user_logged_inChecks if the current visitor is a logged in user
  • auth_redirectChecks if a user is logged in, if not it redirects them to the login page
  • check_admin_refererMakes sure that a user was referred from another admin page
  • check_ajax_refererVerifies the Ajax request to prevent processing requests external of the blog
  • wp_redirectRedirects to another page
  • wp_sanitize_redirectSanitizes a URL for use in a redirect
  • _wp_sanitize_utf8_in_redirectPerforms a safe (local) redirect, using wp_redirect()
  • wp_safe_redirectPerforms a safe (local) redirect, using wp_redirect()
  • wp_validate_redirectValidates a URL for use in a redirect
  • wp_notify_postauthorNotify an author (and/or others) of a comment/trackback/pingback on a post
  • wp_notify_moderatorNotifies the moderatorabout a new comment that is awaiting approval
  • wp_password_change_notificationNotify the blog admin of a user changing password, normally via email
  • wp_new_user_notificationEmail login credentials to a newly-registered user
  • wp_nonce_tickGet the time-dependent variable for nonce creation
  • wp_verify_nonceVerify that correct nonce was used with time limit
  • wp_create_nonceCreates a cryptographic token tied to a specific action, user, user session, * and window of time
  • wp_saltGet salt to add to hashes
  • wp_hashGet hash of given string
  • wp_hash_passwordCreate a hash (encrypt) of a plain text password
  • wp_check_passwordChecks the plaintext password against the encrypted password
  • wp_generate_passwordGenerates a random password drawn from the defined set of characters
  • wp_randGenerates a random number
  • wp_set_passwordUpdates the user's password with a new encrypted one
  • get_avatarRetrieve the avatar <img> tag for a user
  • wp_text_diffDisplay a human readable difference between two strings

Database connection

  • Direct dependence on MySQL *

  • Abstracted through wpdb (leaky)

  • Pluggable through WP_CONTENT_DIR/db.php

* this includes MariaDB, a MySQL fork

Custom database implementation (1/2)

  • Provide WP_CONTENT_DIR/db.php that sets the global $wpdb to a custom instance

  • Skips compatbility checks unless $wpdb->is_mysql returns true

  • Class wpdb is already loaded, so custom implementation can extend if needed

Custom database implementation (2/2)

File WP_CONTENT_DIR/db.php:


                global $wpdb;

                class AwesomeDB extends wpdb {
                    const ANSWER = 42;

                    function db_version()    { return 'AwesomeDB 1.0'; }
                    function db_connect()    { return true; }
                    function query( $query ) { return static::ANSWER; }
                }

                $wpdb = new AwesomeDB();
            

Some alternative database implementations

  • HyperDB by Automattic

  • LudicrousDB by John James Jacoby

  • SQLite Integration by Kojima Toshiyasu (abandoned?)

Caching setup

  • Abstracted through wp_cache_* functions

  • Used transparently for most queries

  • Pluggable through WP_CONTENT_DIR/object-cache.php
    and WP_CONTENT_DIR/advanced-cache.php

Custom cache implementation (1/2)

  • Provide WP_CONTENT_DIR/object-cache.php that sets the global $wp_object_cache to a custom instance and provides wp_cache_* functions

  • Provide WP_CONTENT_DIR/advanced-cache.php if you need to proactively fiddle with the loading process

  • Loading of the WP_CONTENT_DIR/advanced-cache.php file can be controlled through the 'enable_loading_advanced_cache_dropin' filter

Custom cache implementation (2/2)

File WP_CONTENT_DIR/object-cache.php:


                        // Override Cache API functions.
                        function wp_cache_get( ...$args ) {
                            $wp_object_cache->get( ...$args );
                        }
                        function wp_cache_set( ...$args ) {
                            $wp_object_cache->set( ...$args );
                        }
                        function wp_cache_delete( ...$args ) {
                            $wp_object_cache->delete( ...$args );
                        }
                        function wp_cache_flush() {
                            $wp_object_cache->flush();
                        }
                        ...
                        function wp_cache_init() {
                            $wp_object_cache = new AwesomeCache();
                        }
                    

File WP_CONTENT_DIR/my-plugin/src/AwesomeCache.php:


                        // Provide actual implementation class.
                        // This can't extend WP_Object_Cache, as it won't
                        // have been declared.
                        class AwesomeCache {
                            // This is where we hold the awesomeness.
                            private $cache;

                            public function __construct() {
                                // Initialize awesomeness here.
                            }

                            public function get( ...$args ) {...}
                            public function set( ...$args ) {...}
                            public function delete( ...$args ) {...}
                            public function flush() {...}
                            ...
                        }
                    

Localization setup

Set WP_LANG_DIR to either WP_CONTENT_DIR/languages or WPINC/languages

Load MO class for reading GetText translation files

Load 'default' translated strings based on locale

Set up $wp_locale global

Initialize $wp_locale_switcher

Translations

  • Stored in global array $l10n with the key being the text domain

  • If a text domain was not found, it is loaded on demand (looking in WP_LANG_DIR first)

  • If a text domain could not be loaded, an instance of NOOP_Translations is returned

Multisite identification and loading (1/2)

Declare functions to work with multisite tables and data
WPINC/ms-blogs.php

Set up multisite environment
WPINC/ms-settings.php

Declare functions to load multisite into memory
WPINC/ms-load.php

Load default multisite constants
WPINC/ms-default-constants.php

Load sunrise drop-in if it exists and SUNRISE has been defined
WP_CONTENT_DIR/sunrise.php

Multisite identification and loading (2/2)

If either $current_site or $current_blog are not set yet...

Extract domain from $_SERVER['HTTP_HOST']

Extract path from $_SERVER['REQUEST_URI']

If DOMAIN_CURRENT_SITE and PATH_CURRENT_SITE are defined, use these

If we're dealing with a subfolder install, identify network first, then query network for site path

If we're dealing with a subdomain install, identify site by exact domain and at most first segment of path

In case of failure, trigger actions ms_network_not_found or ms_site_not_found

Sunrise drop-in (1/2)

  • Loaded if the constant SUNRISE is set and the file WP_CONTENT_DIR/sunrise.php exists

  • Allows control over multisite setup mechanism

  • Deactivates the entirety of the detection on the previous slide if it sets $current_site and $current_blog

  • Entry point for domain mapping

Sunrise drop-in (2/2)

File wp-config.php:


                        // This is your customized wp-config.php file
                        // that contains your install configuration.

                        // [ ... ]

                        // Activate sunrise mechanism.
                        define( 'SUNRISE', true );

                        // [ ... ]
                    

File WP_CONTENT_DIR/sunrise.php:


                        // This file is responsible for detecting what
                        // network and site to use for a given request.

                        global $current_site, $current_blog;

                        // This is actually the current WP_Network.
                        $current_site = WP_Network::get_instance(
                            custom_logic_to_detect_network_id()
                        );

                        // This is the current WP_Site.
                        $current_blog = WP_Site::get_instance(
                            custom_logic_to_detect_site_id()
                        );
                    

Bootstrap Performance Impact

Feature Project Announcement

Nextgen Bootstrap/Load (1/2)

  • Goal 1 — Documentation

    - Detailed docs for old and new code

    - Include characterization tests to detect breaking changes

  • Goal 2 — Modernized Flow

    - Subsystems should be cleanly swappable/extensible

  • Goal 3 — Contextual Optimization

    - Only load what is effectively needed to produce the desired output

  • Goal 4 — Unified Structure

    - Reduce idiosyncrasies to provide a consistent user/dev experience

  • Goal 5 — Compatibility

    - Don't break existing sites

    - Grow with future requirements

Nextgen Bootstrap/Load (2/2)

  • Phase 1 — Discovery

    - Be clear about the status quo

    - Identify issues

  • Phase 2 — Design

    - Plan a coherent architecture that meets all requirements

    - Get rid of idiosyncrasies

  • Phase 3 — Execution

    - Build with backward compatibility as requirement

    - Build with future compatibility as target

  • Phase 4 — Merge Proposal

    - Ship it!

What's Next ?

Learn — Bootstrap Documentation

Discuss — WordPress Slack Channel

Contribute — Bootstrap GitHub Organization

Questions ?

I'm Alain Schlesser.


Follow me on Twitter:

  @schlessera

Or visit my Personal Blog:

   www.alainschlesser.com