1

I have a single page site with posts that get loaded via Ajax on the same page via slide down div. When a post is 'activated,' I want that state to be set so that when I visit the url directly, it goes to that specific post already showing in the div.

My question is:

Do I create the posts in single.php and call them minus the header and footer? Or do I create the template as part of the Ajax function? Keep in mind that my next task would be figuring out how to implement history.js so the states are set in the url, history stack, etc.

Here's my Ajax function:

function my_load_ajax_content () {

    $args = array(
        'p' => $_POST['post_id'],
        'post_type' => 'projects'
        );

    $post_query = new WP_Query( $args );
    while( $post_query->have_posts() ) : $post_query->the_post(); ?>

    <div class="post-container">
        <div id="project-left-content">
            <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
            <?php the_content(); ?>

            <!-- If there is a URL -->
            <?php if( get_field('url') ): ?>
                <a href="http://<?php the_field('url'); ?>" target="_blank"><?php the_field('url'); ?></a>
            <?php endif; ?>
        </div>
        <div id="project-right-content">

            <?php if( have_rows('slides') ): ?>

                <div id="slider">

                    <!-- Slider Setup -->
                    <?php if( have_rows('slides') ):
                        $slideNumber = 0;
                        while ( have_rows('slides') ) : the_row();
                        $slideNumber++;
                    ?>

                        <input type="radio" name="slider" id="slide<?php echo $slideNumber; ?>">

                    <?php endwhile;endif; ?>

                    <!-- Slide -->
                    <?php if( have_rows('slides') ): ?>
                        <div id="slides">
                            <div id="overflow">
                                <div class="inner">

                                    <?php if( have_rows('slides') ):
                                    while ( have_rows('slides') ) : the_row();

                                        $slideImage = get_sub_field('slide_image');
                                    ?>

                                    <article>
                                        <img src="<?php echo $slideImage; ?>" alt="<?php the_title(); ?>">
                                    </article>

                                    <?php endwhile;endif; ?>

                                </div><!-- #inner -->
                            </div><!-- #overflow -->
                        </div><!-- #slides -->

                    <?php endif; ?>

                    <!-- Controls -->
                    <?php if( have_rows('slides') ):
                        $slideNumber = 0;
                    ?>
                        <div id="active">

                            <?php while ( have_rows('slides') ) : the_row();
                                $slideNumber++;
                            ?>
                                <label for="slide<?php echo $slideNumber; ?>"></label>
                            <?php endwhile; ?>

                        </div><!-- #active -->
                    <?php endif; ?>
                </div><!-- #slider -->
            <?php endif; ?>
        </div><!-- #project-right-content -->
    </div><!-- .post-container -->

    <?php
    endwhile;
    wp_die();
}

add_action ( 'wp_ajax_nopriv_load-content', 'my_load_ajax_content' );
add_action ( 'wp_ajax_load-content', 'my_load_ajax_content' );

Here's a simplified version of my Ajax call:

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

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

    $.ajax({
        type: 'POST',
        url: ajaxURL,
        context: this,
        data: {'action': 'load-content', post_id: post_id },
        success: function(response) {
            $('#project-container').html(response); // response
            return false;
        }
    });
});

Here's my HTML:

<div id="project-container"></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" href="<?php the_permalink(); ?>" data-id="<?php the_ID(); ?>" data-title="<?php the_title(); ?>">+</a>
        </div>
    </article>

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

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

If anyone can show me the way, I'd really appreciate it. I can't seem to find much info on single page WordPress sites and HTML5 history.

Edit: Updated the Ajax function to the full version (was previously simplified).

3 Answers 3

0
+50

I did something similar to this on einsteinworld.com.

The way I did it was to use a function in functions.php to get and render the content, then I called the same function from single.php or via ajax depending on the scenario.

Like that you can either use the global $post for direct navigation to the page, or just pass-in the post id via ajax and query for $post. Don't forget to wp_localize_script and add your function for use with ajax

Use History.pushState to push the post's permalink when called via ajax.

Here's the skeleton code

/* In $(document).ready... */

History.pushState(null, [next-page-title], [next-page-url]);

$().update_content({
  post_id   : [next-page-id]
});


/* js function */

$.fn.update_content = function(args){

  var data = {
    action  : 'my_function',// in functions.php
    post_id : args['post_id']
  };

  $.post( MyAjax.ajaxurl, data, function(response) {
    if( response != 0 ){
      // put the returned content in the DOM
    }else{
      // Do something else      
    }
  });
};

/* in functions.php */

function my_function(){
  if( isset( $_POST['post_id'] ) ){
    $post = get_post( $_POST['post_id'] );
    $ajax = true;
  }else{
    $ajax = false;
  }

  echo [html-to-display-the-post-content]

  // if this is ajax'd stop the output
  if( $ajax )
    die();
}

Update The site referenced above is no longer live, but the answer still works :)

0

I'd say that depends mainly on the complexity of the posts you load.

If they are as simple as...

<div class="post-container">
        <?php the_title( '<h1 class="entry-title">', '</h1>' ); ?>
        <?php the_content(); ?>
</div><!-- .post-container -->

...I'd just put that in the AJAX handler and be done with it.

If the posts are more complex you might just want the bare naked data as JSON via AJAX and build the HTML from it on the client side, maybe even using some frontend framework.

history.js should be easy to implement (and would probably also be better as a separate question). Anyway:

History.pushState({post_id:1}

History.Adapter.bind(window,'statechange',function(){
    var State = History.getState(); // {"post_id":1}
    //AJAX Call
});

...should bring you most of the way.

If you elaborate a bit more on the details I can improve this answer.

3
  • The posts will consist of a title, content, a list of categories, and a slide. I updated the function in the OP. Let me know if that helps in any way. Unfortunately for me, I have no idea how to grab the bare data as JSON via Ajax and build the HTML on the client side. I'm learning Ajax as I go.
    – Desi
    Commented Jan 22, 2015 at 14:29
  • Thanks. Okay this already looks like in need for a clean template solution. Also you'll need some special handling for the slider as you not only need to insert the HTML but initialize the JS. I am afraid this is becoming too big of a thing for a single question on this site. We can only answer focused questions of a single issue with freestanding solutions. Maybe you can tackle one issue at a time and create or look for questions regarding each single issue.
    – kraftner
    Commented Jan 22, 2015 at 15:36
  • As already said - please create a new question as this is a separate issue from your initial question.
    – kraftner
    Commented Jan 23, 2015 at 11:43
0

Two fairly simple ways I can think of:

  1. Use the output of your function my_load_ajax_content to draw <div id="project-container"></div> when you first render the page
  2. When the page loads, trigger your click button.
$(window).on('load', function(){
    $('.post-link').first().trigger('click');
});

As long is jQuery is loaded and you are showing most recent posts at the top, the above should automatically trigger your code when you first visit the page.

If you don't want the most recent post in both the div and the top of the page, you could adjust your page template to simply not draw the most recent post (e.g. the first in the list) by skipping over it, using the pre-get-posts filter, etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.