Implementing 'Show More' Feature for Shopify Blog Posts

Hey everyone, I’m trying to figure out how to add a ‘Show More’ button to my Shopify blog page instead of using the standard pagination. I’ve looked at the current code, which includes a grid layout for articles and sidebar options, but I’m not sure how to modify it for this feature.

Here’s a simplified version of what I’m working with:

<div class="blog-container">
  {% for post in blog.posts limit: 10 %}
    <div class="blog-post">
      <h2>{{ post.title }}</h2>
      <p>{{ post.content | truncate: 150 }}</p>
    </div>
  {% endfor %}
  
  {% if blog.posts.size > 10 %}
    <button id="load-more">Show More</button>
  {% endif %}
</div>

We’ve tried some methods that work for product collections, but they don’t seem to do the trick for blog posts. Any ideas on how to get this working? I’m open to using JavaScript if needed. Thanks in advance for any help!

I’ve implemented a similar feature on my Shopify store’s blog, and I can share what worked for me. The key is to use AJAX to fetch more posts when the ‘Show More’ button is clicked.

First, you’ll need to create a new template for loading additional posts. In your theme, add a new snippet called ‘blog-post-item.liquid’ with the HTML structure for a single post.

Then, modify your main blog template to include a div for the posts and the ‘Show More’ button:

<div id='blog-posts-container'>
  {% for post in blog.posts limit: 10 %}
    {% render 'blog-post-item', post: post %}
  {% endfor %}
</div>

{% if blog.posts.size > 10 %}
  <button id='load-more' data-url='{{ blog.url }}'>Show More</button>
{% endif %}

Finally, add some JavaScript to handle the button click and load more posts:

document.getElementById('load-more').addEventListener('click', function() {
  var button = this;
  var container = document.getElementById('blog-posts-container');
  var url = button.getAttribute('data-url');
  var currentCount = container.children.length;

  fetch(url + '?view=ajax&page=' + Math.ceil((currentCount + 1) / 10))
    .then(response => response.text())
    .then(html => {
      container.insertAdjacentHTML('beforeend', html);
      if (container.children.length >= {{ blog.posts.size }}) {
        button.style.display = 'none';
      }
    });
});

This approach worked well for me, but you might need to adjust it based on your specific theme and requirements.

I’ve tackled this issue before, and here’s a solution that worked well for me:

Instead of modifying the existing template, create a new one specifically for AJAX requests. Name it ‘blog.ajax.liquid’ and include only the blog post loop without any surrounding HTML.

In your main blog template, add a data attribute to the ‘Show More’ button with the current page number:

<button id="load-more" data-page="1">Show More</button>

Then, use JavaScript to handle the button click:

document.getElementById('load-more').addEventListener('click', function() {
  var button = this;
  var page = parseInt(button.dataset.page) + 1;
  
  fetch('/blogs/your-blog-handle?page=' + page + '&view=ajax')
    .then(response => response.text())
    .then(html => {
      document.querySelector('.blog-container').insertAdjacentHTML('beforeend', html);
      button.dataset.page = page;
      if (html.trim() === '') button.style.display = 'none';
    });
});

This approach keeps your code clean and separates concerns effectively.