Blog

Inside the Minds of the Machine

WordPress Tips and Tricks

Ajax requests for high traffic websites

When we re-launched the PBS NewsHour web site we included many page components which loaded via Ajax requests. Our functions were based on the documentation provided by the WordPress codex on using Ajax. Unfortunately, this method created all kinds of caching nightmares and was responsible for poor site performance.

In the case of the NewsHour, our Ajax requests were not user specific, they were simply to load various content blocks into pages. For example, on the sidebar we have a feature called “The Rundown” which features our trending stories.

Instead of running a function to generate this sidebar “widget” on every page, we decided to create an Ajax widget. The benefit would be that the WordPress query for this widget would only need to run once by the sever before being cached. This piece of content was displayed on tens of thousands of pages. Removing it from the sidebar would be a big gain performace wise. In addition to server caching, browser caching would also prevent the end-user from having to download the same data over-and-over again.

Where we ran into trouble

Using Ajax by registering functions forces all of the queries to pass through WordPress’ built-in admin-ajax.php function. This works fine in theory, and is probably necessary if you’re seeking unique data for a user, but if you’re using Ajax like we were, these Ajax requests make their way around the your caching reducing site speed.

In our case, the Ajax requests are shared by all visitors of the site, they see the same sidebar widgets, and “load more” pagination changes.

We needed a better solution for making Ajax requests

Our sites use W3 Total Cache. W3TC doesn’t cache the Ajax requests being made through the built-in admin-ajax.php. We’ve devised the following work around to get our Ajax content cached by W3TC, thus dramatically improving our page load speeds.

In this example, we will create a sidebar item which will display our most recent posts. Typically developers would just place this query into their sidebar.php file, but then the query would have to run every time a page is loaded. This was un-acceptable for a very high-traffic website. Instead we will separate this content into a small Ajax query which will only need to be run once per caching cycle.

Now we’ll complete the basic setup and create a widget that displays the most recent 5 posts on our sidebar.

The Setup

STEP 1 — Setup controller and template files

  1. Register a new custom post type “ajax” for your ajax controllers. Add this to you themes functions.php.
    function custom_create_post_types() {
    register_post_type('ajax', array(
            'labels' => array(
                'name' => __('Ajax'),
                'singular_name' => __('Ajax'),
                'search_items' => __('Search Ajax'),
                'add_new_item' => __('Add New Ajax'),
                'edit_item' => __('Edit Aax')
            ),
            'public' => true,
    	'show_ui' => true,
            'has_archive' => false,
            'rewrite' => array('slug' => 'ajax'),
            'query_var' => true,
            'exclude_from_search' => true,
            'menu_position' => 20,
            'supports' => array('title'),
            'taxonomies' => array()
        ));
    }
    add_action('init', 'custom_create_post_types', 1);
  2. Visit your permalinks page in wordpress to initialize the new url path. Simply visiting this page will automatically update your permalinks. (settings > permalinks)
  3. Create a custom header for ajax. In you theme root create header-ajax.php. Note: the doctype declaration is very important, W3TC won’t cache the content without this!
    <?php
    header('HTTP/1.1 200 OK');
    show_admin_bar(false);
    remove_all_actions('wp_footer', 1);
    remove_all_actions('wp_header', 1);
    ?>
    <!DOCTYPE html>
  4. Create a custom footer for ajax. In you theme root create footer-ajax.php.
    <?php /* intentionally blank */ ?>
  5. Create a custom single template for ajax. In you theme root create single-ajax.php.
    <?php
    	
    get_header('ajax');
    
    // note: we'll add content here later.
    
    get_footer('ajax');
    
    ?>

STEP TWO — Create controller post(s)

  1. In your wordpress admin, select “Ajax” from the menu and add a new post. Give the post a title with a slug for your controller. Example: “recent-posts”.
  2. You can now add a line to single-ajax.php instructing this template to load the specific ajax controller. (Note: in this example “12” is the post id for ‘recent-posts’)
    <?php
    
    get_header('ajax');
    
    if (is_single(array(12, 'recent-posts'))) {include (TEMPLATEPATH . '/ajax-recent-posts.php');}
    
    /* you can add additional controllers here later */
    
    get_footer('ajax');
    
    ?>
  3. Now we can create a new template file “ajax-recent-posts.php”. This file has a function to generate and display the six most recent posts.
    <h3>Recent Posts</h3>
    <ul>
    <?php
    $args = array('post_type' => 'post', 'orderby'  => 'date', 'order'  => 'asc', 'showposts'  => '6');
    $my_query = new WP_Query($args); 
    while ($my_query->have_posts()) : $my_query->the_post(); 
    	$title = get_the_title( $post->ID );
    	$permalink = get_permalink( $post->ID );
    	echo "<li class='item'><a href='$permalink'>$title</a></li>";
    endwhile; 
    ?>
    </ul>

STEP THREE — Integrating into your theme.

  1. At this point you could preview your new ajax controller by visiting http://yourURLhere/ajax/recent-posts/. You should see the results of your custom query.
  2. To add this to your theme, create an empty div on your sidebar where you want this content to be loaded.
    <div id='ajaxrecentposts'><!-- recent posts loaded via ajax --></div>
  3. Now all you need to do is add a little jQuery to pull your Ajax into this div. First add the following script to your main header.php file, it adds a JS variable for templating.
    <script>var wpURL = "<?php echo get_bloginfo('wpurl'); ?>/";</script>
  4. In the javascript file for your site (or your footer), you can add the jQuery call to render the most recent posts into the sidebar. The first part makes sure the <div id=”ajaxrecentposts”> exists before requesting the content.
    jQuery(document).ready(function($) {
    	if ($("#ajaxrecentposts")[0]){
    		$("#ajaxrecentposts").load(wpURL+'ajax/recent-posts/');
    	}
    });

This initial setup may seem a little tricky at first, but once you’ve got it setup adding additional Ajax controllers is a breeze!

* Be sure to provide fall backs for browsers that don’t have JS enabled.