Tag: ajax

Manipulating browser URL using Javascript without refreshing the page

In modern browsers, one of the most interesting feature is that you can change the browser url without refreshing the page. During this process you can store the state of the history so that you can pull the necessary data when someone hits the back-button in the browser and then take necessary action based on that. It’s not as complicated as it may sound now. Let’s write some code to see how it works.

[sourcecode language=”javascript”]
var stateObject = {};
var title = "Wow Title";
var newUrl = "/my/awesome/url";
history.pushState(stateObject,title,newUrl);
[/sourcecode]

History objects pushState() method takes three parameter as you can see in the above example. First one, a json object, is very important. Because this is where you will be storing arbitrary data related to the current url. Second parameter will be the title of the document, and third one is the new url. You will see your browser’s address bar is updated with the new url, but the page was not refreshed 🙂

Let’s see another example where we will be storing some arbitrary data against each url.

[sourcecode language=”javascript”]
for(i=0;i<5;i++){
var stateObject = {id: i};
var title = "Wow Title "+i;
var newUrl = "/my/awesome/url/"+i;
history.pushState(stateObject,title,newUrl);
}
[/sourcecode]

Now run and hit the browser back button to see how the url is being changed. For each time the url is changed, it is storing a history state object with the value “id”. But how can retrieve the history state and do something based on that. We need to add an event listener for “popstate” event which is fired everytime the history object’s state is changed.

[sourcecode language=”javascript”]
for(i=0;i<5;i++){
var stateObject = {id: i};
var title = "Wow Title "+i;
var newUrl = "/my/awesome/url/"+i;
history.pushState(stateObject,title,newUrl);
alert(i);
}

window.addEventListener(‘popstate’, function(event) {
readState(event.state);
});

function readState(data){
alert(data.id);
}
[/sourcecode]

Now you can see whenever you hit the back button, a “popstate” event is fired. Our event listener then retrieves the history state object which was associated with that url and prompt the value of “id”.

It’s easy and pretty interesting, eh?

Caching Ajax requests in WordPress

In modern WordPress themes, theme developers are serving the page requests via ajax. Both paginated blog page and single posts (might be in full or partial) are served. Though WordPress is very fast if properly tuned, but it’s meaningless to pull the same data from WordPress database again and again unless there is any change. Which means, you can safely cache such ajax requests and reduce loads on your database by adding a few lines of extra code in your theme’s functions.php. In this article, we will learn how to take advantage of such caching in WordPress

Step 1: Register Ajax callback for serving paginated blog pages
Here is a typical codeblock that can serve paginated blog pages via ajax. There is no caching yet
[sourcecode language=”php”]
add_action("wp_ajax_blog", "get_blog");
add_action("wp_ajax_nopriv_blog", "get_blog");

function get_blog(){
global $post;
$page = $_REQUEST[‘page’];
if(!$page) $page=1;
$pp = get_option("posts_per_page");
$offset = ($page*1-1)*$pp;
$args = array(
"posts_per_page"=>$pp,
"offset"=>$offset
);
$posts = get_posts($args); //get the posts
foreach($posts as $post){
setup_postdata( $post );
get_template_part("templates/post",get_post_format($post->ID));
}
die();
}
[/sourcecode]

Now if you go to the url “http://your_blog_url/wp-admin/admin-ajax.php?page=1 ” you can see the latest posts, change the page value to 2,3,4 and so on to see previous posts. Each posts in the loop are rendered via get_templates(). Please note how we used the get_post_format() function in the loop to serve different templates based on post formats.

So what is bad in this code? Nothing, yet Everything! If 100 users are visiting your blog and they are visiting blog pages, each and every time these posts are pulled from database. Each and everytime they are pulling the very same data until you had edited any post, or created a new post. So why this extra load should go to DB? lets minimize it 🙂

Step 2: Add caching layer
here is a revised format of the code block above, but now with caching.
[sourcecode language=”php”]
add_action("wp_ajax_blog", "get_blog");
add_action("wp_ajax_nopriv_blog", "get_blog");

function get_blog(){
global $post;
$page = $_REQUEST[‘page’];
if(!$page) $page=1;

/** supply from cache **/
$page_from_cache = get_option( "artpress_page{$page}", 0 );
if($page_from_cache){
die($page_from_cache);
}
/** cache end **/

$pp = get_option("posts_per_page");
$offset = ($page*1-1)*$pp;
$args = array(
"posts_per_page"=>$pp,
"offset"=>$offset

);
$posts = get_posts($args);

ob_start();
foreach($posts as $post){
setup_postdata( $post );
get_template_part("templates/post",get_post_format($post->ID));
}
$new_cache = ob_get_flush();

/** save the cache **/
update_option( "artpress_page{$page}",$new_cache);
/** end cache **/
die($new_cache);
}
[/sourcecode]

In the code above, we first checked the page number. Then, checked in the wordpress options table if there is a cache present with a key named “artpress_page”. Now, for the first time it wont be there. So we just pull the records from the database as usually and then using the output buffering functions we capture the output, instead of pushing instantly to the browser. And then we update the options table with this output. So next time when same page will be requested, database wont be hit. Ok, database will be hit (this options table data is coming from the db) but you can see it wont touch the posts table again, and avoid running expensive queries (which includes many joins) in that table. It also saves CPU a bit.

Step 3: Invalidate cache whenever a post is edited, or created
This is an important step. We need to flush the cache whenever a new post or page is created to make sure our blog shows the up to date data.

[sourcecode language=”php”]
add_action("save_post","invalidate_cache");
function invalidate_cache(){
$counts = wp_count_posts();
$total_published_posts = $counts->publish;
$posts_per_page = get_option( "posts_per_page");
$total_page = ceil($total_published_posts/$posts_per_page);
for($i=1;$i<=$total_page;$i++){
delete_option( "artpress_page{$i}" );
}
}
[/sourcecode]

Now, we are in good shape. Our ajax requests are served from cache and properly purges whenever necessary. You can serve your single post same way.

If you want to serve single posts from the cache, one thing you need to keep in mind is that you are loading up an important table “options” with a lot of data. So you can change the code above and store the cache in filesystem instead of options table. You should have write permission in the uploads directory by default. So that wont be tough at all.

I hope you enjoyed this article 🙂

Displaying comments template when serving a single post via ajax in wordpress

I ran into this issue this morning, the comment form wasn’t showing up. I was using a custom comment template and I thought that there might be some issue with the custom template. So I tried with default template but the result was same. After googling for a while, I’ve found the workaround. Here is the solution for you

[sourcecode language=”php”]
//functions.php
add_action("wp_ajax_single", "get_single");
add_action("wp_ajax_nopriv_single", "get_single");

function get_single(){
error_reporting(0); //see later to understand why it is here
global $post;
$post_id = $_REQUEST[‘id’];
if($post_id){
$post = get_post( $post_id);
setup_postdata( $post );
get_template_part( "templates/single");
die();
}
}
[/sourcecode]

The code above registers an ajax callback for accepting GET/POST calls at “/wp-admin/admin-ajax.php?action=single&id=” and display the single post using the template file located at “templates/single.php” in your current theme.

Now, in the “templates/single.php” you must include the following code-block at the top to make sure the comments_template() function work

[sourcecode language=”php”]
global $withcomments;
$withcomments = true;
[/sourcecode]

Anyway, it was also mentioned in the codex like this, but I was confused as I thought it was actually inside the “single display” at first 🙂

Loads the comment template. For use in single Post and Page displays. Will not work outside of single displays unless $withcomments is set to 1.

By the way, that error_reporting(0) line is there to suppress a deprecated notice which says that your theme is missing “comments.php” even if it’s there.

Hope you enjoy this article