Sunday, February 12, 2017

Enabling Infinite Scrolling / Ajax Loading on Wordpress Baskerville Theme (Anders Norén)

Baskerville Infinite Scrolling With Plugin


I recently built a website using Anders Norén's free Wordpress theme, Baskerville. This is probably one of the best free themes out there, and definitely the best free theme for sites that are trying to emulate the pinterest / masonry grid style of sites, where individual products are laid out in a re-sizable grid layout.

My only complaint with this theme is that it is just begging to be used with an Ajax infinite scrolling feature, but it does not support it out of the box. I have seen multiple forum posts asking for the author to add it, but it looks like no progress has been made (and I don't blame Anders - he is a very busy and amazingly talented author who deserves to spend his time on more pressing projects).

I didn't want to give up on this theme, but infinite scrolling became a requirement for my new site, so I set out to somehow add the feature to this theme. In the end, it actually didn't take that long to figure out and was not nearly as complicated as I thought.

Initially I was going to take a backend approach and try to rewrite a bunch of PHP, but I quickly realized it would be far easier to use a pre-built plugin to provide the backend support for AJAX loading, and write some Javascript myself to get it working with the theme.

How I added infinite scrolling to the Baskerville Wordpress Theme:

Step 1: Install the "Ajax Load More - Infinite Scroll" Plugin

Go the link above and install the plugin. There are lots of customization options, but the one that you must change is the "Repeater Templates" - you need to tell this plugin what PHP to execute on each iteration of the main WP loop that loads posts. If you are using the Baskerville theme without modifications to the main loop, your repeater section should have the following layout code:

<div class="post-container">
       
 <div id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
        
  <?php get_template_part( 'content', get_post_format() ); ?>
                  
 </div> <!-- /post -->
</div>

Here is what it looks like in settings:
Baskerville - Ajax Load More Plugin Repeater Settings

Step 2: Add the shortcode generated by the Ajax Load More Plugin to the theme index.php

To add the "load more" button or scroll trigger to the main page, I needed to add the shortcode generated by the plugin to the homepage of the site - I did this by using the code "echo do_shortcode()". I added by the pagination buttons, which you might want to disable after adding infinite scrolling. Here is the section of relevant code from my modified index.php file:

<?php if ( $wp_query->max_num_pages > 1 ) : ?>
  
  <div class="archive-nav section-inner">
     
             <div class="ajax_load_more_wrapper">
                <?php echo do_shortcode('[ajax_load_more id="9981359626" container_type="div" post_type="post" css_classes="" button_label="Click for More!" button_loading_label="Loading more awesome stuff..." pause="true" scroll="false" offset="10"]'); ?>
            </div>
            
   <?php echo get_next_posts_link( '&laquo; ' . __('Older posts', 'baskerville')); ?>
      
   <?php echo get_previous_posts_link( __('Newer posts', 'baskerville') . ' &raquo;'); ?>
   
   <div class="clear"></div>
   
  </div> <!-- /post-nav archive-nav -->
 
 <?php endif; ?>

Of course, you want to replace my shortcode snippet with whatever your plugin generates - it will be different depending on how you customize the button text, if it loads on click vs scroll, etc.

Step 3: Add custom Javascript to move newly loaded posts into correct area and fix layout

This is where I think most people have given up - if you stop at this point, the posts that are loaded by the infinite scrolling plugin appear very screwed up - they will load on the side and be very squished. Not good. The solution? I wrote some pretty simple Javascript that simply moves the newly loaded posts into the correct area (which is a div wrapper with the class "posts"), re-initializes some theme-specific code, and then, and this is the most important part, tells the Masonry library that new posts have been added and that it needs to reflow the layout to organize the posts. For those that are unaware, "Masonry" is a javascript library, and it is the power behind the dynamic responsive card based layout used in these theme. It has built in methods for triggering a reflow when new content has been added - the one we are interested in is "appended":
Appended: Adds and lays out newly appended item elements to the end of the layout.
Here is all of my custom Javascript that I wrote - this only needs to be added once. The code attaches itself to the callback of the Ajax Load More plugin so that it is executed each time a new set of posts are loaded through AJAX.

$ = jQuery;
(function() {
  $.fn.almComplete = function(alm){
      
      // Masonry setup - check your global.js file for details
      var globalMasonryObject = $blocks; 
      
      console.log("New Ajax load completed!");
      
      // Main area that  holds all the individual posts objects
      var mainPostArea = document.querySelector("div.content > .posts");
      
      // All posts that are loaded by wordpress Ajax scroll plugin
      var allAjaxPosts = document.querySelectorAll("div.alm-reveal > .post-container");
      
      // Move all Ajax posts from plugin wrapper to main area
      for (var x=0; x<allAjaxPosts.length; x++){
          thisAjaxPost = allAjaxPosts[x];
          mainPostArea.appendChild(thisAjaxPost);
      }
      
      // re-init flexsliders
      $(".flexslider").flexslider({
            animation: "slide",
            controlNav: false,
            prevText: "Previous",
            nextText: "Next",
            smoothHeight: true   
        });
      
      // Load addthis innline toolboxes - uncomment the below line if you use addthis
      //addthis.layers.refresh();
      
      // Update masonry layout AFTER images have loaded (prevents overlapping elements)
      imagesLoaded(allAjaxPosts,function(){
          $blocks.masonry('appended',allAjaxPosts);
          setTimeout(function(){
              $blocks.masonry();
          },100);
      });
  };
})(jQuery);

Alternative Method:

I can't verify this, but from looking at a recent update for the Baskerville theme, it looks like Anders might have added support for the Jetpack plugin, which allows for infinite scrolling. However, I still prefer my method, because it allows for more generic ajax loading plugins with just small modifications, plus it allows for more customization in how the infinite scrolling appears and works. Also, the Jetpack plugin is rather bloated, whereas with my solution I am installing a singular plugin with a very narrow scope.

7 comments:

  1. Awesome ... Thank you very much. This worked great for me

    ReplyDelete
  2. In which file will the last code be inserted? ...$ = jQuery;
    (function() {....

    ReplyDelete
    Replies
    1. Good question. That is largely up to you and how you have your theme (or child theme) structured. You could simply paste it into your footer file, within a script tag, or you could do something like have it in a separate JS file and load that file via functions.php and wp_enqueue_scripts (that is how I did it).

      Example with wp_enqueue_script - wp_enqueue_script('AjaxMasonryFix',get_stylesheet_directory_uri().'/js/AjaxMasonryFixer.js',array('jquery'),'1.4',true);
      -- In the example above, you would have copied and pasted my code into a new file - "AjaxMasonryFixer.js".

      Delete
  3. Because WordPress is open-source, there is literally hundreds of thousands of people who are working to help make it better. https://medijo.lt/etiketes/

    ReplyDelete
  4. Great write-up, I am a big believer in commenting on blogs to inform the blog writers know that they’ve added something worthwhile to the world wide web!.. Vector Art

    ReplyDelete