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; } }); });