Loading WordPress Posts Dynamically With AJAX

AJAX has become all the rage in the past couple of years and for good reason. AJAX (Asynchronous JavaScript and XML) is a way to have a “conversation” with the server and display the results without reloading the page.

This technique allows us to refresh “Like” counters, add items to a shopping cart, create dynamic forms and much more – all without reloading the page.

In this post, I’ll show you how to load posts in place with AJAX using the Twenty Fifteen default theme as our base.

We’ll look at why AJAX is used and, starting with a simple example, building AJAX loading functionality into Twenty Fifteen.

Why Use AJAX?
Getting Started: Creating a Child Theme
Hello AJAX!
Enqueuing Our Javascript
Creating an Event
Creating an AJAX Call
Communicating With WordPress
Overview

Loading Posts With AJAX
A Note About AJAX Calls
Better User Experience

AJAX Pitfalls

Note: If you run into any issues trying to set up AJAX on your site, we can help! Our support team is available 24/7 to help you with any WordPress issue (not just questions about our own plugins!), so whether you’re having problems with AJAX or want some advice on how to do CSS tweaks, get in touch! 

Why Use AJAX?

When WordPress loads the first page of posts on a WordPress site, it requests them from the database and uses a loop to display them using the markup we’ve added. Aside from this, navigation menus, widgets, graphics and other media, javascript files, stylesheets and a bunch of other things are loaded.

Note that 72 requests are made on each page load.

As you can see in the image above (taken from Chrome Developer Tools), a fair number of assets are loaded. There is room for optimization here and some assets like scripts will be cached, but even then it is a lot.

When page two of our posts is loaded it all happens again. WordPress retrieves the posts and displays them using our markup. It also loads all the outlying elements of the page all over again. In many cases (but not all) this is a waste of bandwidth and detrimental to user experience. After all, no one likes waiting around for pages to load.

Getting Started: Creating a Child Theme

Before we modify Twenty Fifteen we should create a child theme. This ensures we can continue updating the theme without losing our changes. You can read all about how to do in in out guide How to Create a WordPress Child Theme.

Hello AJAX!

Let’s begin with a simple example that demonstrates how AJAX Works. We’ll target the links inside the pagination strip at the bottom of the page so that when you click on a page number it will dynamically load that page using AJAX. When a pagination link is clicked we will send a request to the server and alert the result.

We’ll be targeting the number links inside the pagination section.

Enqueuing Our Javascript

Our first port of call is creating the JavaScript file and enqueueing it via our theme’s functions.php file.

I created a js folder and a ajax-pagination.js file in it. Once you have done the same, open your functions file and add the script to the already existing theme_enqueue_assets() function:

If you’re confused about enqueuing read our article on adding scripts and styles to WordPress the right way. In a nutshell, we’ve told WordPress what we’d like to call our script (parameter one), where it is located (parameter two), what the pre-requisites are (parameter three), the version number (parameter four) and that we’d like to load it in the footer (parameter five).

Note that when enqueueing the stylesheet I used get_template_directory_uri(). This function always points to the directory of the parent theme. When enqueueing our script I used get_stylesheet_directory_uri(). This points to the child theme’s directory if used within a child theme.

Since we’re loading the script in the footer you can paste alert( ‘Script Is Enqueued’ ) into ajax-pagination.js and reload the page to check if it works. If it does, the text should be alerted properly.

Creating an Event

The next task is to create an event which will trigger an AJAX call. In our case the event is the clicking of a specific link. To target the link we’ll need to find out a bit about the element classes and IDs around it.

The source code for the pagination from Chrome Dev Tools.

In case you’re wondering how I got this to show up, I pressed Shift + Command + C on my Mac (Shift + Control + C on Windows), hovered over the element I wanted to inspect and clicked it.

This tells me that our pagination links have the class page-numbers, the next link also has the class of next and these are all contained in a nav element with the class of nav-links. Not shown here is the previous link, which has the class of prev in addition to the regular page-numbers class.

For the time being, let’s not worry about all that, let’s just target any link within the pagination container. We can create a simple alert like this:

Note that everything is wrapped in an anonymous function. I recommend you do the same. Take a look at this thread on why this is helpful. I’ve created a click event, prevented the default functionality from firing (i.e. loading the page) and I’ve alerted some text.

Creating an AJAX Call

Instead of working with client side data (alerting a preset text) we should grab some dynamic data from the server side. We’ll need to do a tiny amount of prepwork. Here’s why: We need to give the AJAX call a URL to work with. Our Javascript file has no knowledge of our environment, so we can’t use something like get_stylesheet_directory_uri() in there. We can, however, use a localization technique to pass variables to our JavaScript. Let’s do that now in our functions file:

By adding this code inside the my_enqueue_assets() function we will have defined the ajaxpagination object (parameter 2). The object will receive its members according to the array supplied as the third parameter in the wp_localize_script() function. In other words, once we’ve added this code we should be able to use ajaxpagination.ajaxurl to define the URL to the admin-ajax.php which we use to handle AJAX calls.

The reason this works is that the localization function outputs the definition of this object before our JavaScript is loaded. It looks something like this:

Getting back to our JavaScript file, we now have everything we need to build an AJAX call. Here’s how:

As you can see the $.ajax() function is what we’re using here. There are special functions for post and get methods but I prefer using this function because of its flexibility. You can read about all the parameters in the jQuery Documentation.

Using the url parameter we pass the URL of the script we want to send data to. This should be the admin-ajax.php file which can be found in the wp-admin directory. We defined this above via the wp_localize_script() function.

The type is set to post. We could also use get, our query is not too sensitive but I prefer to post data unless the user needs access to the parameters.

The data parameter is an object which contains the data you want to pass. In our case I will be able to access a $_POST[‘action’] variable, the value of which would be ajax_pagination. You can pass as many as your application requires of course.

0 is returned if no server-side code is written.

Finally, the success parameter is a function which alerts the result of our AJAX call. We’ll make this a bit fancier below, for now this is sufficient for testing. If you try clicking on a link now it actually works but won’t be very useful since we haven’t defined the server side code. In fact, what you should see alerted is 0.

So why does this happen? When I said “we haven’t defined server side code,” I wasn’t entirely truthful. We haven’t, but WordPress has. There is some content in the admin-ajax.php file we are using. If you take a look at the source code of that file you should see that the script uses die( ‘0’ ) in a couple of cases.

If we don’t supply an action the admin-ajax.php script dies and returns 0. If we do supply an action but we don’t hook into the required WordPress hooks nothing happens and at the very end of the file we die again, returning 0. In conclusion we are already communicating with the server.

Communicating With WordPress

To get a meaningful answer from WordPress we need to define some WordPress actions. This is done using a set pattern. Let’s dive in by continuing our example in the functions file of our theme:

I’ve hooked a function to two hooks. Hooks that take on the wp_ajax_[action_name] format are only executed for logged in users. Hooks that take on the wp_ajax_norpiv_[action_name] format are only executed for non-logged in users. The great benefit of this is that you can very easily separate functionality.

The action names I mentioned above refer to the action defined in our AJAX call in Javascript (action: ‘ajax_pagination’) – they must match. The function name can be anything you like, I used my_ajax_pagination for clarity.

The function itself can contain anything you’d like. You can log out users, grab their data, publish a post and so on. Whatever you want to return to Javascript you must echo. In the example above I’ve echoed the title of the blog, pulled in dynamically via the get_bloginfo() function.

The final step is to use die(). If we don’t define this, the die function defined in admin-ajax.php at the very end of the file will kick in and you will end up echoing 0 in addition to whatever else you are echoing. If you try out the code above you should now see the title of your website returned.

Overview

That concludes our basic example! Before we move on to pulling in posts via AJAX, let’s quickly recap the steps necessary to perform an AJAX action:

Enqueue a Javascript file if you don’t already have one
Use wp_localize_script() to pass the URL of your admin-ajax.php file
Create the AJAX call in Javascript
Hook a function using the appropriate hook name
Code the function which may return data back to Javascript

Loading Posts With AJAX

Now for the juicy stuff! I started this project by writing the JavaScript code for it. Without further ado, here is the basic version. We’ll expand on it with some tweaked user experience soon.

This is much the same as our basic example. The first thing you’ll notice is that I’ve added a way to detect which page the user wants to request. Each link has a span element in it which is hidden (it is there for screen readers). I make a clone of the element to make sure I don’t modify the original, remove the span and parse the remainder as an integer. This gives us the page number we need.

I will also need to know the query parameters used. On the main page this is pretty simple, it’s just the paged parameter since we’re working with the default query. If we start off on an archive page (like a category archive) we’ll need to know the category name as well.

We’ll pass the query variables using the localization method we learned earlier. For now we’ll use ajaxpagination.query_vars even though this is not yet defined. Finally, on success we remove all article elements from the main container, we remove the pagination element and append the return value of our AJAX call to the main container.

This return value will contain the posts and the new navigation element. Note that I’ve changed the name of the parameter from response to html because it makes a bit more sense. To finish up we use the localization array to pass the original query parameters.

The following function should be placed in our my_enqueue_assets() function replacing the localization we had earlier:

All we need to do now is flesh out the my_ajax_pagination() function. Whatever this function echoes will replace the content on our page. Here’s the final code with an explanation below:

Using our passed parameters we build a custom query. This involves basically taking the query variables we passed and making sure that the page number we passed overwrites the paged parameter. We then use our final $query_vars array to create a new query.

We need to make the $GLOBALS[‘wp_query’] variable equal to our new posts object. The reason we need to do this is that the the_posts_pagination() function uses this global variable.

Next, notice that I’ve added a function to the editor_max_image_size filter and a few rows down I remove it. This was something unexpected that came up. I actually created a WordPress Trac Ticket. We may see some progress on it! Here’s the issue:

When images are loaded in the post they all look just fine. However, if you complete this tutorial without these filters your images will be narrower, only 660px wide instead of the necessary 825px. The reason for this is that the function that loads the images eventually calls a function named image_constrain_size_for_editor(). This function makes sure that images in the post editor aren’t too wide. To determine weather this size reduction should take place it uses the is_admin() function. Since our code runs through admin-ajax.php which technically is in the admin, WordPress scales our images down, mistakenly thinking we are using them in the editor.

Luckily we can use the editor_max_image_size filter to determine the maximum size for the editor. Since we want to leave everything as is, except for during our AJAX call we add the filter using our custom values (array( 825, 510 )) and then immediately remove it just to make sure it doesn’t cause trouble anywhere else.

The next step is to use our query to list our posts. I copied a lot from the index.php file in the parent theme. if there are no posts we use the template which is meant to handle that, otherwise we loop through the posts and use the post display template. Finally we use the same pagination format we see in the index file.

A Note About AJAX Calls

It’s important to remember that AJAX calls are always considered to originate from the admin. What this means is that draft, scheduled and private posts may be returned with this call. If you don’t want this to happen, you’ll need to control the behaviour with appropriate parameters such as post_status.

Better User Experience

With AJAX solutions like this, it is extremely important to focus on user experience. I’m working in a local environment so everything loads really quickly, but on a production server images and other assets may take more time to load.

Due to this you should at least add a loader or loading text and disable further clicks on the navigation elements. We will take care of these by making the posts and the navigation disappear right after the user clicks and displaying the text “loading new posts.” When the success event fires we remove the loading text and display the posts. Here’s our updated AJAX call:

We now have a separate beforeSend and success function. The former is performed as soon as you click the link, before the AJAX call is sent to the server. The later is performed once we receive data back from the server.

Before the call is sent we remove the articles and the navigation. This makes sure users can’t keep clicking on navigation links while they’re waiting for things to load. Next we scroll to the top of the document. Then, we append a loading notification to make it clear to users what’s going on. I’ve used the same markup as Twenty Fifteen uses on post-not-found pages. In the success function we remove the loader and load our content, all done!

AJAX Pitfalls

AJAX is extremely powerful; apart from loading posts you can perform all sorts of actions via AJAX calls. There are quite a number of dangers and things to look out for while using it, here are a few:

Safety can be a major concern. If you want to delete a post via AJAX you need to make sure the user has the intent and the permission (using nonces), for example. When using regular methods WordPress has built-in protections in some cases but with AJAX you usually have to think of this on your own.

Graceful degradation is another facet of AJAX, although something that is becoming less important. Basically: no JavaScript, no AJAX. If you rely on AJAX heavily, users who have it disabled will not be able to use our application. Javascript has become so ubiquitous that this is almost irrelevant, but may come up in some situations. In this case you need to make sure that clicking on the actual link will work as well.

User experience is very frequently overlooked. AJAX functionality is indeed cool, but a reliably working website is cooler. Users are used to pages loading when they click links. You need to make everything very transparent, users should know what is going on and why. You should use AJAX to enhance your work, not to bring as much bling as you can to the table.

Conclusion

As you can see, implementing AJAX requires a bit of preparation and practice but once it’s second nature you’ll find that it comes easily. It probably took you a while to read through this and it will take even more time to do it for the first time, but I coded the whole example in about 15 minutes.

AJAX is one of those techniques which can be difficult because it encompasses almost all programming languages used in a framework like WordPress. Things are spiced up further by having to adhere to conventions like hooks and localization.

Practice makes perfect. I guarantee you’ll fall in love AJAX if you start to use it.

Щелкните ниже, чтобы поставить оценку!
Всего: 0 В среднем: 0

Написать комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *