A Look At Wordpress' WP Class

wordpress logo
This is my interpretation in pseudo code of the WP class in Wordpress. I did this mainly to know what's going on under the hood. If you get anything of value from it, great.

wp-config.php

When Wordpress boots up, wp-settings.php is included from the wp-config.php file:

  define('WPLANG', '');
  define('WP_DEBUG', false);
  if ( !defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/');
  require_once(ABSPATH . 'wp-settings.php');

wp-settings.php

The WP class is instantiated once within the wp-settings.php file. The instance exists as a global variable, $wp, throughout the system.

.
$wp = new WP();
.

This is a snapshot of the WP Class as of Wordpress 3.3.1, March 11, 2012. All variables and methods are made public. The meat of the WP Class framework consists of:

class WP {
  var $public_query_vars = array();
  var $private_query_vars = array();
  var $extra_query_vars = array();
  var $query_vars;
  var $query_string;
  var $request;
  var $matched_rule;
  var $matched_query;
  var $did_permalink;

  function add_query_var($qv) {}
  function set_query_var($key, $value) {}
  function parse_request($extra_query_vars) {}
  function send_headers() {};
  function build_query_string() {}
  function register_globals() {}
  function init() {}
  function query_posts() {}
  function handle_404() {}
  function main() {}
}

First thing to note is there are two arrays with one for private and the other for public query variables.

Public Query Variables

Publicly available query variables that you can access directly from the $wp variable. By public I believe this means what can be typed into the user agent's address bar (like mysite.com/?m=something&p=something):

  • m
  • p
  • posts
  • w
  • cat
  • withcomments
  • withoutcomments
  • s
  • search
  • exact
  • sentence
  • debug
  • calendar
  • page
  • paged
  • more
  • tb
  • pb
  • author
  • order
  • orderby
  • year
  • monthnum
  • day
  • hour
  • minute
  • second
  • name
  • category_name
  • tag
  • feed
  • author_name
  • static
  • pagename
  • page_id
  • error
  • comments_popup
  • attachment_id
  • subpost
  • subpost_id
  • preview
  • robots
  • taxonomy
  • term
  • cpage
  • post_type

Private Query Variables

The private query variables are only used in the parse_request() call. You must set extra_query_vars and they must match with the same named private_query_vars to get pass through and get set. This ensures that named variables outside this space does not get injected into the query_vars space.

foreach ( (array) $this->private_query_vars as $var) {
  if ( isset($this->extra_query_vars[$var]) )
    $this->query_vars[$var] = $this->extra_query_vars[$var];
}
  • offset
  • posts_per_page
  • posts_per_archive_page
  • showposts
  • nopaging
  • post_type
  • post_status
  • category__in
  • category__not_in
  • category__and
  • tag__in
  • tag__not_in
  • tag__and
  • tag_slug__and
  • tag_id
  • post_mime_type
  • perm
  • comments_per_page
  • post__in
  • post__not_in

add_query_var($qv)

Very simple code that adds a string to the public query variables array. First checks if the string exists in the array and then adds it if it doesn't exist. Note that this just adds the query variable name to the array. It does not set it with a value.

// if query variable string name is not in the public query variable array
if (!in_array($qv, $this->public_query_vars))
  $this->public_query_vars[] = $qv;  // add it

set_query_var($key, $value)

Creates a key and sets the value to a query variable in the query vars array (not the public_query_vars)..

  $this->query_vars[$key] = $value;

main($query_args='')

This is where the processing for a request begins.

Initialize thyself
Parse a request
Send HTTP headers
Run the query to fetch posts
Setup a 404 header if didnt find anything else setup a HTTP 200 header
Register globals (not PHP globals but Wordpress. These are just date stuff and deprecated)
Setup the "wp" action to execute all action (not filter) hooks

handle_404()

This is for handling a 404 error (page not found). There is a lot of logic in this handler and most of it won't make sense unless you truly understand the bowels of the system. Basically this will check to see if any posts were returned from a query and a bunch of other tests based on.

handle_404 is only called from main() after query_posts(). At this point, Wordpress either found something or not for the given request. This function will setup a HTTP 200 Success or HTTP 404 headers.

if not in admin mode, the number of posts is 0, are not on an existing 404 page, query string ['robots'] not robot,  query string['s'] not set as a search page and not home page {
  if a tag, category, taxonomy, author, post archive, queried object, not paged {
    if not 404
      return a HTTP 200 Success
   }
   set 404 flag
   return a HTTP 404 not found status
}
else if is not a 404
  return HTTP 200 Success

init()

The init function basically just makes one call, wp_get_current_user() which instantiates a user. Doesn't really make much sense to me for a user to be instantiated in a WP object. More so when there is no $user variable within the class to hold it.

query_posts()

This function builds the query string and invokes the query based on the public query_vars. Notice we get a hint here that there is a $wp_the_query variable lying around.

global $wp_the_query;
$this->build_query_string();
$wp_the_query->query($this->query_vars);

This is the global Wordpress system variable that gets instantiated in wp-settings.php. It is an instance of WP_Query.
$wp_the_query->query() basically parses the query string and then calls get_posts() that does all the post processing.

send_headers()

Although I don't fully understand all the gyrations on this one, this is what I gather:

  1. Sets up HTTP headers for some esoteric stuff and exits
  2. Same as above and gives listeners opportunity for send_headers action

The esoteric stuff is for:

  • if user is logged in, a string is returned for HTTP headers to not cache
  • if it is a 404 error set to not cache and set content-type and character set
  • if a rss feed set content-type and character set
  • Setting last modified date
  • Checking HTTP_IF_NONE_MATCH, HTTP_IF_MODIFIED_SINCE for a HTTP 304

build_query_string()

Builds the query string based on the public query_vars of the WP class by iterating through each key/value pair and building query strings behind the scenes:

paged=2
paged=2&category_name=sports
tag=hockey
pagename=about
category_name=sports
name="my-title-post&category_name=sports"

It also makes a call to the query_string filter but this is deprecated. Instead, one should use the request filter instead. I kind of think this is a great place to do some debugging if you are a theme or plugin developer in this filter. You can do stuff like the following to get information right before the call to hit the database. You can put this in your functions.php file:

function request_filter_hook($request) {
global $wp;
global $wp_query;
global $debugTheme;

if (true == $debugTheme) {
// interrogate to see whats available
echo "<h2>Dump of request variable</h2>";
var_dump($request);

echo "<h2>Dump of wp_query variable</h2>";
var_dump($wp_query);

echo "<h2>Dump of wp variable</h2>";
var_dump($wp);
  }
  return($request);
}

$debug Theme= true;
add_filter('request', 'request_filter_hook');

parse_request($extra_query_vars='')

This is the workhorse that parses an HTTP request.

Create empty query_vars and post_type_query_vars arrays

// Handle $extra_query_vars and represent as an array
If extra_query_vars was passed in as an array then
  reference it
else
  treat it as a string like search?item1=foo&item2=bar
  convert to an array $extra_query_vars(item1=>foo, item2=>bar)

// care of path_info, request_uri, and 404
Get the rewrite rules
Assume by default we can't find anything and it is a HTTP 404

Breakup PATH_INFO into variable parts
Breakup REQUEST_URI into variable parts
Breakup PHP_SELF into variable parts

Get the home url and strip off the trailing slash
Exclude the home url in these strings leaving only folder/title
  REQUEST_URI
  PATH_INFO
  PHP_SELF
Sets $wp's request variable
Iterate through the internal rewrite rule list to find a match with the request
if there is a match
  grab only the query string part (i.e. ?blah=something&blah2=something2)
  do some reg expression magic to substitute strings in the query
  parse the into an array (i.e. $a("blah"=> 'something', "blah2"=> "something2"))

transfer extra_query_vars to query_vars
apply filters on request for the query vars
announce to listeners parse_request

Summary

Phew! That was quite a long article but if you got something out of it, thats terrific. I sure did and picked up a few things that I can use along the way as well.

$wp->main() to you!

ASO ad


Filed under: