AJAX Post Load with live URL updating

Wordpress

My newest project for DeLACA I wanted to do something cool and fresh, specifically having the entire site load in a single browser session (no page reloading) that still had SEO relevant URLs.

It took a little legwork to get it working, but it’s easier to do than you think. Code dump below.

WordPress PHP:

<?php
function ajaxMenu_script() {
	wp_enqueue_script('ajaxMenu_script', get_stylesheet_directory_uri() . '/includes/ajaxMenu.js', array( 'jquery') );
}
add_action('wp_head','ajaxMenu_script');

function ajax_pageload() { ?>
<script type="text/javascript">
	var ajaxurl 	= <?php echo json_encode(admin_url("admin-ajax.php")); ?>;
	var ajaxnonce	= <?php echo json_encode(wp_create_nonce("itr_ajax_nonce")); ?>; 
	var siteurl		= <?php echo json_encode(get_bloginfo('url')); ?>;
</script>
<?php } add_action('wp_head','ajax_pageload');

function ajaxMenu_process() {
	//	intercept post data
	$id 	= $_POST['id'];

	//	fetch post data by ID
	$post	= get_post($id);

	$data	= array(
		'post_content'	=> $post->post_content,
		'post_title'	=> $post->post_title,
		'post_slug'		=> $post->post_name,
		'post_url'		=> $post->guid
	);

	$data 	= json_encode($data);

	die($data);

}
add_action('wp_ajax_nopriv_ajaxMenu_process','ajaxMenu_process');
add_action('wp_ajax_ajaxMenu_process','ajaxMenu_process');

function ajaxMenu_nav($menu_name) { 

	$return .= '<ul id="main">';

	global $wp_query;
	$currentId = $wp_query->queried_object_id;

	if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_name ] ) ) {
		$menu = wp_get_nav_menu_object( $locations[ $menu_name ] );
		$menu_items = wp_get_nav_menu_items($menu->term_id);
		foreach ( (array) $menu_items as $key => $menu_item ) :
		    $title 	= $menu_item->title;// Menu Item title
			$url	= $menu_item->url; // Menu Item URL
		    $id 	= $menu_item->object_id; // Post ID
		    $post 	= get_post($id); // Post Obj
		    $slug 	= $post->post_name; // Post Slug
		    $title 	= $post->post_title; // Post Title
		    $active	= ($id == $currentId) ? 'active' : '';
		    $return .= '<li><a class="'.$active.'" href="'.$url.'" data-page-title="'.$title.'" data-page-id="'.$id.'" data-page-slug="'.$slug.'">'.$title.'</a></li>';
		endforeach;
    } else {
		$return .= '<li>Menu "' . $menu_name . '" not defined.</li>';
	} 

	$return .= '</ul>';

	echo $return;
}

Code inside of our ajaxMenu.js:

jQuery(document).ready(function ($) {

	ajaxMenuConfig = {
		menu 		: $('ul#main li a, #logo a'),
		container 	: $('section#pages')
	}

	ajaxMenuConfig.menu.click(function (e) {
		e.preventDefault;

		slug 	= $(this).attr('data-page-slug');
		title	= $(this).attr('data-page-title');
		id 	= $(this).attr('data-page-id');
		current	= $(this);

		console.log(slug,id,title);

		//	Don't do anything if the current page is already loaded
		if( current.hasClass('active')) 
		{
			return false;
		} 
		else // or else process our AJAX
		{

		ajaxMenuConfig.container.addClass('loading');

		$.ajax({
			type 	: 'POST',
			url 	: ajaxurl,
			data 	: {	action 	: 'ajaxMenu_process',
						'id'	: id
					},
			success	: function(data, textStatus, XMLHttpRequest) {

				//	Extract the JSON array from the returned string
				data = JSON && JSON.parse(data) || $.parseJSON(data);

				//	Aesthetic loading of the new content
				ajaxMenuConfig.container.fadeOut('fast');
				ajaxMenuConfig.container.queue(function() {
					ajaxMenuConfig.container.html('');
					ajaxMenuConfig.container.load(data.post_url+' .single', function() {
						ajaxMenuConfig.container.fadeIn('fast');
					});
					$.dequeue(this);
				});
				//ajaxMenuConfig.container.fadeIn('fast');

				//	Configure an object to be passed to the current state
				pushHistoryObj = {
					'html' : html,
					'slug' : slug
				}

				//	Change the current URL to the returned slug
				window.history.pushState(pushHistoryObj,data.post_title,siteurl+'/'+slug+'/');

				//	Update the current post item
				ajaxMenuConfig.menu.removeClass('active');
				current.addClass('active');

			},
			error: function(MLHttpRequest, textStatus, errorThrown) {
  				alert(errorThrown);
  				return false;
  			}
		});

		ajaxMenuConfig.container.removeClass('loading');

		return false;
		}
	});

});