Pippins Plugins
  • Email
  • Facebook
  • Feedburner
  • Github
  • Google
  • Twitter
  • Vimeo
  • Youtube
  • Rss
  • About
  • News
  • Join the Site
    • Member Benefits
    • Member Plugins
    • Email Notifications
  • Plugin Store
    • Affiliate Area
    • Checkout
  • Plugins
    • Plugin Portfolio
      • Plugin Portfolio – List View
    • Free
    • Premium
    • Member Plugins
    • Coding Standards
    • Get Plugin Support
  • Tutorials
    • Series
      • Plugin Development 101
      • Creating a User Follow System Plugin
      • Customizing Restrict Content Pro
      • Displaying Content with Easy Content Types
      • Writing Your First WordPress Plugins, Basic to Advanced
      • Working with Widgets
      • User Submitted Image Galleries
      • Plugin Thoughts
      • Integrating Stripe.com with WordPress
      • WordPress Rewrite API
    • Member Exclusive
      • Free Members
      • Subscriber Only
    • Difficulty
      • Beginner
      • Intermediate
      • Advanced
    • Action and Filter Hooks
    • Ajax
    • Custom Post Types
    • External APIs
    • Short Codes
    • Taxonomies
    • Video Tutorials
    • Widget Tutorials
    • WordPress Admin / Dashboard
    • Working with jQuery
    • WordPress Database
    • Writing Plugins
    • Tag Index
  • Reviews
  • Support Forum
  • Contact
    • Support the Site
    • Request Code Review
    • Plugin Support

WordPress Rewrite API – Part 3

Posted on March 23, 2012 by Abid Omar in Action and Filter Hooks, Advanced, Ajax, Member Restricted, Subscriber Only, Tutorials, Writing Plugins 7 Comments
Home» Tutorials » Action and Filter Hooks » WordPress Rewrite API – Part 3
Tweet
Love It - 4
This entry is part 3 of 3 in the WordPress Rewrite API Series
← WordPress Rewrite API – Part 2
  • WordPress Rewrite API – Part 1
  • WordPress Rewrite API – Part 2
  • WordPress Rewrite API – Part 3

In part 3 of the WordPress Rewrite API series, we will be covering adding custom endpoints to specific places of your blog content. Endpoints are extremely powerful, and in this case, they will allow us to enable AJAX in the default theme WordPress (Twenty Eleven), so that when loading a post or page, it’s all done without reloading the page, via AJAX.

How does it work?

There are multitudes of ways to AJAXify WordPress themes. Chris Coyier has made a very detailed screencast about one way of doing it. The main idea is that the JavaScript script loads the HTML page and then inserts it inside the DOM replacing the old page content.

This has the advantage of being simple, easy to implement and works out of the box for most of the themes. But there is still a huge inconvenience of doing it that way. AJAX was introduced to avoid page reloads and make loading pages faster; loading the whole page HTML when you only need the post content and comments is an unnecessary overhead (and bandwidth) that could be avoided.

Another disadvantage is that all pages will be rendered with AJAX. It works in most cases, but in some cases you do NOT want to have the page loaded with ajax, since you might need to reload necessary JavaScript and CSS files, or render the page with a completely different HTML structure.

The proposed solution in this tutorial will approach both issues mentioned above. For the first, we’ll create a JSON output for each AJAX enabled page. For the second, we’ll give the JavaScript a way to check that the page is AJAX enabled, if not, it’ll load normally as it used to.

Obviously, our solution is not perfect. Since we are loading the JSON data only with JavaScript, we need to know the HTML structure of the post content and comments in advance to be able to construct it. This means that our solution is theme specific (in this tutorial, we assume that you have activated WordPress default theme “Twenty Eleven”) which is good in my opinion. Cross-theme solutions will certainly come at the expense of performance.

Adding an endpoint

The add_rewrite_endpoint function allows us to add custom end points like /trackback/ and /format/xml. This could be done by the rewrite API functions detailed in the previous tutorials of the series but this function is a lot easier: You don’t have to add a rewrite rule, a rewrite tag; and you get to define “places” where the endpoint will be added. Finally, you hook the function call with the init action. There is no need to refresh the rewrite rule on plugin activation and deactivation.

For example, if you want to add an endpoint to the comment pages, you simply do it with one line of code

<?php
add_rewrite_endpoint('endpoint', EP_COMMENTS)
?>

If you want to add the endpoint to all pages in your blog

1
2
3
<?php
add_rewrite_endpoint('endpoint', EP_ALL)
?>

The endpoint mask is flexible. For example, you can add the endpoint to both the search and tag pages

1
2
3
<?php
add_rewrite_endpoint('endpoint', EP_SEARCH + EP_TAGS)
?>

A query variable with the same name as the endpoint will be created. Before the template gets rendered (‘template_redirect’ filter) this variable can be read with the WordPress get_query_var function.

Generating the JSON output

We’ll be creating a JSON output for all pages in our blog. In addition to that, we’ll be creating a verification page which will serve as a check that the page is JSON enabled. The purpose of this page is to make the most out of performance. The verification page will return a short string of text “enabled” if the page supports AJAX calls.

To generate the JSON output, PHP has the json_encode function. The function accepts any type of data (except a resource) and converts it to a JSON string. Generally, it’s either an array or an object. We are using both here: An array with two keys “post” and “comments” which are objects.

<?php
// Adding the json endpoint
add_action( 'init', 'ao_add_json_endpoint' );
function ao_add_json_endpoint() {
  add_rewrite_endpoint('json', EP_ALL );
}
// Template redirect
add_action( 'template_redirect', 'ao_template_redirect' );
function ao_template_redirect() {
  global $post;
  switch (get_query_var('json')) {
    case 'verify':
      echo 'enabled';
      exit;
    case 'response':
      $arr = array ('post' => $post, 'comments' => get_comments(array('post_id' => $post->ID)));
      echo json_encode($arr);
      exit;
  }
}
?>

The ao_json_endpoint registers ‘/json/’ as a valid endpoint to all pages; and also ‘json’ as a query variable. The ao_template_redirect function evaluates the query variable before the template is rendered and renders the right content.

It’s worth mentioning that limiting AJAX enabled pages should be done in the ‘verify’ switch case where we are returning ‘enabled’ for all pages in our case. Limiting from the add rewrite endpoint function is possible, but will return a full page (404 not found for pages outside the scope of the endpoint mask) which is against the idea of minimizing the size of the request.

So to check that the page is AJAX enabled, you call in your browser the following (which should return ‘enabled’ if it is)

http://blogurl.com/blog_post/json/verify

To load the JSON version of a blog post, you need to call in your browser URL

http://blogurl.com/blog_post/json/response

This is a little inconvenient and unusual if you ask me. There is nothing wrong with it, but this format is a friendlier, shorter and feels more natural

http://blogurl.com/blog_post/json

If you load this URL, though, the ‘json’ endpoint will be ignored and the normal blog post page will be loaded. This makes sense since the query variable is not set. The query variable needs to be set somehow.

WordPress has a “request” filter that applies to the query variables that are passed to the default main SQL query when the page is called. We can hook to this function, and check if the ‘json’ query variable is set and null. In this case, we set the ‘json’ query variable to ‘response’ our default target.

1
2
3
4
5
6
7
8
9
<?php
add_filter('request', 'ao_set_queryvar');
function ao_set_queryvar($vars) {
  if (isset($vars['json']) &amp;&amp; $vars['json'] === '') {
    $vars['json'] = 'response';
  }
  return $vars;
}
?>

On the front-end

On the front-end, we’ll need to hijack every internal URL click event in the page and attach it to a function that performs a few things

  1. Loads the verification page and evaluates the returned content
  2. If the page is AJAX Enabled, load the JSON data and insert it into the page
  3. If the page is not AJAX Enabled, redirect the browser to the clicked URL

To detect internal URLs, I’m using a jQuery plugin called urlinternal coded by Ben Alman. It’s usage is pretty simple

1
$('a:urlInternal')

This returns all internal URLs in the page. It’s possible to detect external URLs, and fragment links. Refer to the plugin page for a complete description and documentation.

Parsing JSON is easy with the jQuery parseJSON function. It turns a JavaScript JSON string to a JavaScript object. Using “console.info(returned_json)”, you can get a better idea about hierarchy of the returned JSON object.

Note, I have added all of the necessary code to create the HTML structure of the page that matches the Twenty Eleven theme. It’s pretty straight forward, so it should not need explaining, but if you have questions, ask in the comments.

The JavaScript Code

Create a js folder in your plugin directory and save the URL internal jQuery plugin and this snippet in it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
(function($) {
	$(document).ready(function() {
		function create_article(post_title, post_content) {
			var title = '<header class="entry-header"><h1 class="entry-title">' + post_title + '</h1></header>',
				content = '<div class="entry-content">' + post_content + '</div>';
			var html = '<article class="page type-page status-publish hentry">' + title + content + '</article>';
			return html;
		}
		function display_page (data) {
			var post_title = data.post.post_title,
				post_content = data.post.post_content,
				post_guid = data.post.guid;
			$('#content').html(create_article (post_title, post_content));
		}
 
		$('a:urlInternal').on('click', function(e) {
			e.preventDefault();
			$('#content').html('loading...');
			var url = $(this).attr('href');
			$.get(url + 'json/verify/', function(data) {
				if (data === 'enabled') {
					$.get(url + 'json/', function(data) {
					display_page($.parseJSON(data));
					});   
				} else {
					window.location = url;
				}
			});
		});
	});
})(jQuery);

The PHP code

Save this PHP code into your main plugin file and activate it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php
/*
 Plugin Name: WordPress AJAX
 Plugin URI: http://wpajax.com
 Description: WordPress AJAX
 Author: Abid Omar
 Version: 1.0
 */
 
// Enqueue Scripts
add_action('wp_enqueue_scripts', 'ao_enqueue_scripts');
function ao_enqueue_scripts() {
	$plugin_path = trailingslashit(WP_PLUGIN_URL . '/' . plugin_basename(dirname(__FILE__)));
	wp_enqueue_script ( 'ao_urlinternal',  $plugin_path . 'js/jquery.ba-urlinternal.min.js', array('jquery') );
	wp_enqueue_script ( 'ao_ajax',  $plugin_path . 'js/ajax.js', array('jquery'));
}
 
// Adding the json endpoint
add_action( 'init', 'ao_add_json_endpoint' );
function ao_add_json_endpoint() {
	add_rewrite_endpoint( 'json', EP_ALL );
}
 
// Activating the json query variable
add_filter('request', 'ao_set_queryvar');
function ao_set_queryvar($vars) {
	if (isset($vars['json']) && $vars['json'] === '') {
		$vars['json'] = 'response';
	}
	return $vars;
}
 
// Template redirect
add_action( 'template_redirect', 'ao_template_redirect' );
function ao_template_redirect() {
	global $post;
	switch (get_query_var('json')) {
		case 'verify':
			echo 'enabled';
			exit;
		case 'response':
			$arr = array ('post' => $post, 'comments' => get_comments(array('post_id' => $post->ID)));
			echo json_encode($arr);
			exit;
	}
}

You can now test the plugin by loading your site’s home page (running the Twenty Eleven theme) and clicking on any post / page link. The page will be loaded with AJAX.

Moving further

This tutorial can be the beginning of an AJAX enabled theme solution. There are a lot of shortcomings that can’t be covered in a single tutorial, but this should be a really good starting point.

  • Browser History; and enabling the next and previous button
  • Loading comments which will require looping through the comments array
  • Enabling AJAX for comments and forms
  • A custom output for the home page and other special pages

If you are a premium subscriber, then the complete plugin is free to download below.
Join the Site to Download

Abid Omar

Abid Omar is an independent consultant specializing in HTML5 , JavaScript and WordPress. He is located in Sunny Tunisia.
Tweet Follow @pippinsplugins
Abid Omar, Ajax, endpoint

7 comments on “WordPress Rewrite API – Part 3”

  1. dkotter says:
    March 23, 2012 at 4:05 pm

    For anyone else that might be having issues, I had to go to the Permalinks page in the admin to get this to work. Until I did that, I would get a 404 error when clicking on a link.

    Also, and I may be wrong about this, but you have the template_redirect being an add_filter, which I think should be add_action. Not sure if it makes much of a difference though. And the first code part, the first function you have it being an add_filter and then in the full code at the end you have it as an add_action. I think both should be add_action.

    But great tutorial. Would have come in really handy a few weeks ago when I was trying to do something similar.

    Reply
    • Pippin says:
      March 24, 2012 at 12:09 pm

      Ah, yes, sometimes permalinks will need to be refreshed, but not always.

      Technically it will work with add_action( ‘template_redirect’, ‘ao_template_redirect’ ); or add_filter( ‘template_redirect’, ‘ao_template_redirect’ );, but I believe add_action is better. I’ve updated the code.

      Thanks for the input!

    • Abid Omar says:
      March 24, 2012 at 3:06 pm

      Permalinks need to be refreshed every time you change the rewrite rules (on plugin activation/deactivation). Sometimes another plugin refresh the rules and break yours. For a plugin I made, I found that the solution is to check that your rewrite rules are in the wp_rewrite object otherwise to add them again and refresh another time.

      And you are correct on the “template_redirect” hook. It’s listed as an action in WordPress codex, so better use add_action for that.

  2. Anuroop says:
    March 24, 2012 at 2:50 pm

    Hi Pippin,

    This is totally irrelevant to the topic..but this is more of general doubt.
    I am using the update-notifier.php downloaded from codecanyon site which is used to notify the customers about the plugin updates and it looks like you are also using the same file as I could see that one of your customers reported that they faced a problem

    “Fatal error: Call to undefined function get_plugin_data() in /(MY PATH)/wp-content/plugins/easy-content-types/update-notifier.php on line 57″

    from the page…http://codecanyon.net/item/easy-custom-content-types-for-wordpress/discussion/234182?page=21

    In reply to this you said that this issue has been fixed..can you please suggest me how you have suggested this issue in your plugin as it would be of tremendous help to me as well

    Thanks,
    Anuroop

    Reply
    • Pippin says:
      March 24, 2012 at 2:55 pm

      To fix the issue, you just need to wrap your include(‘custom-plugin-updater.php’) call inside of if(is_admin()) { … }. The get_plugin_data() function only exists inside of the admin area.

  3. Anuroop says:
    March 24, 2012 at 3:19 pm

    This is awesome…it works…thanq so much man :)

    Reply
  4. Bartosz says:
    September 17, 2012 at 7:10 am

    Hi,

    Would it be possible to create a permalink structure containing terms from multiple taxonomies like that:

    domain.com/%custom_post_type%/taxonomy1_term/%taxonomy2_term%/%postname%/

    I can’t handle that so I wonder if it’s possible at all.

    Regards,
    Bart

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

  • Login

Lost your password?

Please enter your username or e-mail address. You will receive a new password via e-mail.

  • Facebook Become a Fan Like

  • Twitter Subscribe on Twitter Follow

  • YouTube Follow my Videos Subscribe

  • RSS Feed Subscribe with RSS Subscribe

Easy Digital Downloads

Most Loved

  • Love It Pro for WordPress
  • Write a “Love It” Plugin with Ajax to Let Users Love Their Favorite Posts / Pages
  • Simple Notices Pro Plugin for WordPress
  • User Bookmarks for WordPress
  • Front End Registration and Login Forms Plugin

Similar Plugins and Posts

  • Using Ajax in Your Plugin and WordPress Admin
  • Create a Live Search in WordPress with jQuery and Ajax
  • Love It Pro for WordPress
  • Write a “Love It” Plugin with Ajax to Let Users Love Their Favorite Posts / Pages
  • WordPress Rewrite API – Part 2

Latest Premium Content

  • Plugin Development 101 – Introduction to Adding Dashboard Menus
  • Plugin Development 101 – Intro to Loading Scripts and Styles
  • User Follow System – Part 5
  • Plugin Development 101 – Intro to Short Codes
  • Plugin Development 101 – Registering a Custom Post Type
  • Plugin Development 101 – Intro to Actions

Latest Tutorials

  • Test Your Plugins with RTL (0)

    Right-To-Left languages are those that...

  • Submitting Your First Pull Request to a WordPress Plugin on Github (5)

    Github is an extremely popular tool for managing WordPress plugins, and one...

  • Plugin Development 101 – Introduction to Adding Dashboard Menus (1)

    Adding new menus, both top level and sub level, to the WordPress Dashboard is a really common task for plugins...

Enter your email to receive automated updates when new posts are published

Latest Tweets

  • @HipHopMakers should be back shorlty
    May 25, 2013
  • @mrpritchett good idea. Not in the plugin currently but I like the odea
    May 25, 2013
  • @mrpritchett what kind of short codes?
    May 25, 2013

Topics

shortcodes featured add_options_page attachments campaign monitor meta box Rémi Corson register_setting the_content hook Tom McFarlin wp_enqueue_script contextual help do_action login Related posts authors attachment image forms mail chimp short codes plugin recent posts post types bbpress apply_filters comments short code taxonomies custom post type Ajax images gallery Stripe taxonomy jquery widgets users add_filter easy content types add_action widget restrict content pro easy digital downloads

Weekly Newsletter

Useful Links

  • Join the Site
  • Plugin Store
  • Affiliate Area
  • Tag Index
  • Support the Site
  • Suggest a Tutorial
  • Random Post
  • Contact

Monthly Archives

(c) 2013 Pippin's Plugins