Search code examples
jqueryajaxwordpressbrowser-historyhistory.js

Saving the state of a page with content loaded via Ajax


Background

I'm loading my projects (posts) via Ajax into a div on the front page whenever a project link is clicked. The response is fine and I've managed to get pushState() to work wonderfully.

Problem

I'm having problems saving the state when the project has been loaded.

When a project loads, the url changes from example.com to example.com/title-of-post. I want to save the state when the project has been loaded (example.com/title-of-post) so that when a user inputs example.com/title-of-post into the address bar, the page loads with that project loaded in the div.

Note: example.com/title-of-post used to redirect to example.com/projects/title-of-post but I made an htaccess redirect on that.

Example

This page is a good example of what I'm trying to achieve, although I'd rather not use hashtags in the url. Notice how when you visit that url, the respective project (dubai) is already loaded.

What I have done (using History.js)

$('.post-link').on('click', function(e) {
    e.preventDefault();

    var post_id = $(this).data('id'),
        projectTitle = $(this).data('title'), 
        projectSlug = $(this).data('slug'), 
        ajaxURL = site.ajaxurl; 

    $.ajax({
        type: 'POST',
        url: ajaxURL,
        context: this,
        data: {'action': 'load-content', post_id: post_id },
        success: function(response) {

            // Load the response from the Ajax call
            $('#project-container').html(response);

            // Make history
            var stateDataObj = { project: projectSlug };
            History.pushState(stateDataObj, site.title, site.url + '/' + projectSlug);

            // Revert to our previously saved state
            History.Adapter.bind(window, 'statechange', function(){ // Note: We are using statechange instead of popstate
                var State = History.getState(); // Note: We are using History.getState() instead of event.state
                var stateDataObj = State.data;
                $(this).closest('#main').find('#project-container').html(response);
            });

            return false;
        }
    });
});

This is my WordPress loop.

<div id="project-wrapper">
    <a href="#" class="close-button">&times;</a>
    <div id="project-container"></div>
</div>

<div id="projects-list">

<!-- Start the loop -->
<?php $home_query = new WP_Query('post_type=projects');

while($home_query->have_posts()) : $home_query->the_post(); ?>

    <article class="project">
        <?php the_post_thumbnail( 'home-thumb' ); ?>
        <div class="overlay">
            <a class="post-link expand" href="<?php the_permalink(); ?>" data-id="<?php the_ID(); ?>" data-title="<?php the_title(); ?>" data-slug="<?php global $post; echo $post->post_name; ?>">+</a>
        </div>
    </article>

<?php endwhile; ?>
<?php wp_reset_postdata(); // reset the query ?>

</div><!-- #projects-list -->

Solution

  • see its the url that the problem. Its resolved before the browser loads so hence using url locations rather than query vars is more difficult.

    But to do this, Get the current url using excluding the hostname using $_SERVER[REQUEST_URI] then you can match this to whatever project you want to load and load using php.

    You will need to do this a little differently than a rewrite rule. You will need a function hooked into init to catch the url before it tries to load the url and redirect to the frontpage . You will also need to pass the url information along session or cookie.

    If you were just to use a query var ?name=page you could skip the redirect etc. And your save state would work with a simple js function. Hopefully i have changed your mind :)