Themes, Plugins and Tutorials

Ajax Themes

Ajax is a great method for loading new content onto a web page without having to do an entire page refresh. It’s sometimes used in WordPress themes for paging, loading in full content after an excerpt, or dynamically displaying new comments as they are posted.

Ajax can also be used to load more significant amounts of content, but it gets more complicated. URLs don’t update by default, which is important if someone wants to bookmark that particular post or share it. Browser navigation buttons for “Back” and “Forward” can also be an issue.

Thankfully there are HTML5 methods for dealing with browser history and states, and an awesome jquery plugin that provides some fallback for older browsers. This tutorial will walk you through the code required for a theme that makes extensive use of ajax and also point you to some live demos.

When to Use Ajax

Sites that use ajax well generally have a good reason for it. One of my favorite ajax sites is Designers MX, which hosts music mixes. By using ajax the site is able to keep the music playing uninterrupted while users navigate through the site.

When animations could be interrupted by a fresh page load, ajax is also extremely helpful. I developed a site for Byron Reece that features a large slider at the top for selecting posts. If the user had to load a new page after clicking on an item on the slider the site interaction would not have worked.

Sites that have heavy initial page weight but then just need to load in small snippets can benefit enormously from ajax. An example might be a gallery site that displays a huge amount of thumbnails initially, but then just needs a single request for a larger image when the user selects it.

How URL Pushstates Work

You’ll notice on the Byron Reece site that when you click on an a different item in the slider the URL updates even though a fresh page load is not happening. In modern browsers that support HTML5 push states, this url looks like any other you would normally use on the web. In legacy browsers, like IE8, it reverts to the hash url structure (#!).

Most of this URL magic is handled by history.js. All you do is send a title and url for the new browser state when the ajax event happens.

A Simple Example

I coded out a much simpler example of an AJAX driven site using the TwentyEleven theme as a base for an example. Any links clicked in the top navigation menu will load the new content from that link into the #primary and #secondary divs.

I wouldn’t suggest building a site like this, as you don’t get a whole lot of upside for using ajax here, but it works well for demonstration purposes.

Enqueue the Required Javascript

For the pushstates to work as I used them, you’ll need to load history.js. There is a compressed version for use with jquery that can be downloaded here. I also load another javascript file that contains the custom code, which I saved in ajax_demo_init.js.

ajax_demo_init

This is the custom javascript that enables history.js, tells the site which link targets to load via ajax, and pushes the new browser states. I’ll post it as a block here, and then explain in more detail below:

Pushing the Title and URL

This snippet tells the site which links should be loaded by ajax (‘#access a’). To fully ajaxify a site you’d probably want it to detect external vs internal links, and load all the internal ones with ajax.

The path variable is what sets the new url. The title is what will be at the top of the browser window and show up when bookmarked.

You might need to be a little careful with the title. You’ll notice in my Ajax Demo the full title is there on a fresh page load, but on an ajax load it drops site name from the title. To get it to match perfectly you’d have to tweak the title variable slightly.

Binding the Listener on Statechange

This idea took a little while for me to understand. When someone clicks on a link that you want to load via ajax, you don’t actually trigger any of the ajax on that click function. Instead, you have the click trigger a statechange event and pass it the needed variables for url and title.

The real work is done in the statechange listener. Here’s a real simple example with all the console log events uncommented so you can see what’s going on:

You can see the event was triggered by a mouseclick, and that “Example One” is the new title, “http://themes.wptheming.com/ajax-demo/example-one” is the URL that will be loaded.

Any functions in the statechange listener will also be fired when someone clicks the “back” or “forward” buttons in their browser.

Loading in the New Content via Ajax

The final piece is to actually load in the new content using ajax. If you’re unfamiliar with how this works, I’d also read the jQuery documentation the load function. For the TwentyEleven ajax example, we replace the #primary and #secondary divs with content from the new URL. This all happens inside the load_site_ajax function:

I also dim the content, so that the user is aware that it will change shortly:

$('#content').fadeTo(200,.3);

Once the content has loaded, the ajax loader disappears because the new content doesn’t have the ajax loader in #primary (remember, it was prepended using javascript). So, all that’s left to do is undim the new content:

$('#content').fadeTo(200,1);

One final issue I had, is that the menu items weren’t highlighting correctly because WordPress applies certain classes to them depending on which page it has loaded. When you load new content into #primary or #secondary and change the URL, the menu will keep the same classes it had on the initial page load. One way around that is to also reload the menu:

A Note on Browser Compatibility

There’s a couple issues with older browsers, but I think the main one is bookmarking. If a user visits the home page in IE8, then loads a secondary page via ajax, the URL will look something like this:

However, if you visit that URL directly- it will only load the home page, not the page you thought you bookmarked (http://themes.wptheming.com/ajax-demo/example-one).

I worked out a method for detecting a hash and loading the correct content after the initial load, but it doesn’t work in modern browsers- and sort of defeats the point of using ajax since it is now loading the initial page content and then new page content:

// For legacy browser support
// Only checks for hashes, so more robust support might be needed if you use anchors
if (window.location.hash) {
load_site_ajax();
}

I’m sure someone has worked out a better way to do this! Please share it in the comments.

Additional Thing to Watch Out For

If you use social buttons like Google+ or Twitter, don’t expect them to automatically update with the new URL. I’ll write a follow-up post about how to get those working.

A lot of WordPress themes use body classes for styling. These won’t update on an ajax load.

Did I Miss Something?

If you see anywhere I can improve the code, please share it in the comments- especially about legacy browser support.

Download the AJAX Demo Code

If you’d like to get the Ajax Demo theme code, it’s available as a $15 dollar download. The javascript code is the same as posted in this tutorial- just conveniently bundled into a theme version.

I am trying to load the ‘About Us’ page using ajax in my theme. The page actually uses your thematic plugin to get custom user data. Will it be possible to load the about us content frame using of_get_option(‘about_us_content’) function in this ajax script?

It will really help if you can make your ajax twentyeleven theme example available for download.

I tried swapping out the body classes using several different methods but was never able to make it work. One of the more hackish methods was to save the body classes into a hidden div inside #content, and then try to replace the page’s body classes after the ajax call using jquery- but no luck. I’d be interested to see if someone could make it work.

This issue just came up for me while using WP Super Cache but relying on dynamic body classes to show/hide certain protected content based on user role, logged-in/logged-out and a few IE related fixes.

For a couple other sections on my site I was using Ajaxize to load some custom wp_query loops to keep them updated with the newest posts. That plugin takes any function (even custom functions) and then adds an ajaxified wrapper to it as a div which you can then put into your template.

But you can’t wrap the element with ajax as then the whole page is ajaxified and caching becomes irrelevant. In addition, I tried creating a custom function that groups all my body class filters together and ajaxizing them but then the normal WP body class filters are ignored (like post type, page id, etc). So, no bueno.

Cool! If you’re really interested in ajax powered themes, I’d also recommend checking out some of the newer stuff that developers are working on with backbone- especially Zach Tollmanz with Theme Foundary. Here’s a link to one of his projects: https://github.com/tollmanz/backbone-wordpress-theme

Great stuff man! I’m currently working on an ajaxed wordpress site with soundcloud integration for a record label, and as I had little experience with AJAX I went through numerous approaches, rewriting and trying loads of stuff.

I stumbled upon your post after finishing a “works okay in most browsers” /#/-scumbag-script, and decided to give your method a shot: Instant success, now it works cross browser, better than before, and code is sexy and simple.

So thank you handsomely for this, and grats – this has been by far not only the best, but also simpliest and cleanest approach I could find in all the last weeks!

Oh and I just found a minor problem: – With on() everything works, except when I click a link in the content part. – With live() this problem doesnt happen. – With delegate() neither, but then it won’t work in IE.

Impressive guide to adding ajax navigation to any theme. However I did have to make some minor adjustments. Namely due to the fact that once it’s loaded once via ajax, the page you click won’t for the next, since all the links have returned to normal. So remember to change the code so that it adds the push state again. So the code that does that I turned that into a function instead and called it once on first load, then later inside load_site_ajax().

Kudos to you Devin, it certainly was the easiest to implement out there that did what I wanted with this one client that wanted a custom WP theme.

Yeah, I actually came across this the other day when working on a different site. All the click bindings can be added to a function and re-applied after an ajax request if you need it to apply to those new elements too. I’ll put it on the list to update…

hi! first of all thanks for the great post here. I’m testing your code and it works perfectly for any kind of post content but the problem comes when I load a page with javascripts (lightbox gallery or jw player), they don’t work.do you know the cause of this behavior?(I’m not much into ajax stuff..) thanks

hi! i thank you first the great post which helped me to implement limk change on adress bar while using ajax. I only have one remark, why the content on the page does’t change when clicking on “go back” and “go forward” buttons on web broweser.

This is a great tutorial. I have everything working except for the disqus commenting system. When I load a single post, it no longer loads Disqus. I found a reset function that they provide, but that did not work. Any insight that you can provide?

The Disqus scripts are likely only loaded on single posts. So if you start on an archive page, and then move to a single post, it hasn’t loaded the script it needs in the head. You can try to set it up so the Disqus scripts are loaded on every page (and use a callback to reinit), or have it try to smartly load the scripts when it needs them.

I am having a lot of trouble with scripts working after the ajax is called – any jquery running on content that I am replacing, stops working, even if it was previously loaded on the page. For example, I am loading a new product into the content area, and the pinterest button that runs on a javascript stops working once the ajax is triggered. My slider stops working as well, and so does my add to cart button… any advice?

Has anyone had any success adding this to a underscores (_S) based theme? I added it to twentyeleven with no problem but couldn’t get it work with my theme which is based on _S or with an unmodified version of _S.

Thought I’d share two issues I ran into that I was able to fix pretty easily.

1) When I loaded a page my sidebar (#secondary) was showing up under the main content area (#primary). I updated line 32 of ajax_demo_init.js to$("#main").load(State.url + ' #primary ', function(data) { Works fine. 2) Also I have a slider on the home page of the theme I’m using this in. If I went from the home page, to another page and back to the home page the slider wouldn’t initialize. So I re-initialized it in the callback that starts on line 34 and it worked again.

Hi, is it possible to control which pages are ajaxfied? I need to omit 1 or 2 pages from AJAX. Noticed your first nav link (ajax demo) does not load the sidebar. I’m looking for this but to apply to any page. Thanks.

I’m not sure if anyone ran into this problem but I noticed it’s still present on the demo page where the ajaxified page load only occurs on one click instance after an actual page load. I solvedthat problem by changing $(‘#access a’).on(‘click’, function(e) .. to $(document).on(‘click’,’#access a’, function(e)…