Need help with Pagination function

So, I have this blog-post section that I added pagination to, but I also needed to add a way of filtering all blog posts by category. I was able to do both, but when I filter based on a category, the pagination doesn’t work as intended.

Basically, what happens is that the number of pages stays the same instead of adapting to the new number of blog-posts based on the new filter. So I end up with a lot of pages where you only see 2 or 3 or even 0 posts.

I’m not using the blog template that already has some filtering functionalities because my client wants to have multiple specialized blogs for different topics but without changing the URL of the original blog posts so they don’t affect the rakings that they already have so that’s why using the blog template is not ideal in my case since I would have to create multiple blogs that would change the original URL of the blog-post.

I’ve tried filtering first, I’ve also tried filtering and storing them in an array but the pagination doesn’t work on arrays so that didn’t work so I ended up in a roadblock.

I’m relatively new to Shopify theme coding so any help would be much appreciated.

Let me know if you need me to share anything else.

Here’s the live website where the issue is present: Guides for Survivalists & Preppers

Here’s the blog-posts.liquid code:

{%- render 'section-spacing-collapsing' -%}

<style>
  #shopify-section-{{ section.id }} {
    --blog-posts-per-row: {% if section.blocks.first.type == 'blog' %}{{ section.blocks.first.settings.blog.articles_count | default: 3 | at_least: 2 | at_most: section.blocks.first.settings.posts_count | at_most: 3 }}{% else %}3{% endif %};
    --blog-posts-grid: {% if section.blocks.first.settings.stack_items or section.blocks.first.type == 'article' %}auto / minmax(0, 1fr)){% else %}auto / auto-flow 74vw{% endif %};
  }

  @media screen and (min-width: 700px) {
    #shopify-section-{{ section.id }} {
      --blog-posts-grid: {% if section.blocks.first.settings.stack_items or section.blocks.first.type == 'article' %}auto / repeat(var(--blog-posts-per-row), minmax(0, 1fr)){% else %}auto / auto-flow 52vw{% endif %};
    }
  }

  @media screen and (min-width: 1000px) {
    #shopify-section-{{ section.id }} {
      --blog-posts-grid: auto / repeat(var(--blog-posts-per-row), minmax(0, 1fr));
    }
  }
</style>

<div {% render 'section-properties' %}>
  <div class="devContainer">

    <div class="section-stack">
      {%- render 'section-header', subheading: section.settings.subheading, heading: section.settings.title, heading_color: section.settings.heading_color, heading_gradient: section.settings.heading_gradient, content: section.settings.content, link_text: section.settings.link_text, link_url: section.settings.link_url -%}

      <div class="blog-posts {% unless section.blocks.first.settings.stack_items %}scroll-area bleed md:unbleed{% endunless %}">

        {%- for block in section.blocks -%}
          {%- case block.type -%}
            {%- when 'blog' -%}
              {%- capture sizes -%}(max-width: 699px) calc(100vw - 40px), (max-width: 999px) calc(100vw / 3 - 64px), calc(min(100vw - 96px, {{ settings.page_width }}px) / {{ block.settings.blog.articles_count | at_most: 3 }}){%- endcapture -%}

              {%- assign selected_tag = section.settings.category_filter -%}

              <!-- Start Pagination (on all articles) -->
              {%- paginate block.settings.blog.articles by block.settings.posts_count -%}
                {%- assign articles_shown = 0 -%} <!-- Counter to track how many articles are shown -->
                {%- for article in block.settings.blog.articles -%}
                  
                  {%- if selected_tag == 'all' or article.tags contains selected_tag -%}
                    {%- render 'blog-post-card', article: article, show_excerpt: section.settings.show_excerpt, show_date: section.settings.show_date, show_author: section.settings.show_author, show_comments_count: section.settings.show_comments_count, show_category: section.settings.show_category, sizes: sizes, position: forloop.index -%}
                    {%- assign articles_shown = articles_shown | plus: 1 -%}
                  {%- endif -%}
                {%- endfor -%}

                {%- if articles_shown == 0 -%}
                  <!-- Show a message if no articles match the filter -->
                  <p>No articles match your selected category.</p>
                {%- endif -%}

                {%- render 'pagination', paginate: paginate -%} <!-- Render pagination controls -->
              {%- endpaginate -%}
              <!-- End Pagination -->

            {%- when 'article' -%}
              {%- capture sizes -%}(max-width: 1000px) calc(100vw - 40px), calc(min(100vw - 96px, {{ settings.page_width }}px) * 0.65){%- endcapture -%}

              {%- if block.settings.article != blank -%}
                {%- render 'blog-post-card', article: block.settings.article, featured: true, background: block.settings.background, text_color: block.settings.text_color, show_excerpt: section.settings.show_excerpt, show_date: section.settings.show_date, show_author: section.settings.show_author, show_comments_count: section.settings.show_comments_count, show_category: section.settings.show_category, sizes: sizes, position: forloop.index -%}
              {%- else -%}
                {%- render 'blog-post-card', featured: true, show_excerpt: section.settings.show_excerpt, show_date: section.settings.show_date, show_author: section.settings.show_author, show_comments_count: section.settings.show_comments_count, show_category: section.settings.show_category, sizes: sizes -%}
              {%- endif -%}
          {%- endcase -%}
        {%- endfor -%}
      </div>
    </div>
  </div>
</div>

{% schema %}
{
  "name": "Blog posts",
  "class": "shopify-section--blog-posts",
  "tag": "section",
  "disabled_on": {
    "templates": ["password"],
    "groups": ["header", "custom.overlay"]
  },
  "max_blocks": 1,
  "settings": [
    {
      "type": "checkbox",
      "id": "full_width",
      "label": "Full width",
      "default": true
    },
    {
      "type": "checkbox",
      "id": "show_excerpt",
      "label": "Show excerpt",
      "default": true
    },
    {
      "type": "checkbox",
      "id": "show_date",
      "label": "Show date",
      "default": true
    },
    {
      "type": "checkbox",
      "id": "show_author",
      "label": "Show author",
      "default": false
    },
    {
      "type": "checkbox",
      "id": "show_comments_count",
      "label": "Show comments count",
      "default": false
    },
    {
      "type": "checkbox",
      "id": "show_category",
      "label": "Show category",
      "info": "Add tag organize blog posts [Learn more](https://help.shopify.com/en/manual/online-store/blogs/writing-blogs#add-tags-to-a-blog-post).",
      "default": true
    },
    {
      "type": "select",
      "id": "category_filter",
      "label": "Select Category (Tag)",
      "options": [
        {
          "value": "all",
          "label": "All Categories"
        },
        {
          "value": "Homeowners",
          "label": "Homeowners"
        },
        {
          "value": "Survivalists & Preppers",
          "label": "Survivalists & Preppers"
        },
        {
          "value": "Fire Emergencies",
          "label": "Fire Emergencies"
        },
        {
          "value": "General Safety",
          "label": "General Safety"
        },
        {
          "value": "Industrial & Professional",
          "label": "Industrial & Professional"
        }
      ],
      "default": "all"
    },
    {
      "type": "text",
      "id": "subheading",
      "label": "Subheading"
    },
    {
      "type": "text",
      "id": "title",
      "label": "Heading",
      "default": "Blog posts"
    },
    {
      "type": "richtext",
      "id": "content",
      "label": "Content"
    },
    {
      "type": "url",
      "id": "link_url",
      "label": "Link URL"
    },
    {
      "type": "text",
      "id": "link_text",
      "label": "Link text",
      "default": "View all"
    },
    {
      "type": "header",
      "content": "Colors",
      "info": "Gradient replaces solid colors when set."
    },
    {
      "type": "color",
      "id": "background",
      "label": "Background"
    },
    {
      "type": "color_background",
      "id": "background_gradient",
      "label": "Background gradient"
    },
    {
      "type": "color",
      "id": "text_color",
      "label": "Text"
    },
    {
      "type": "color",
      "id": "heading_color",
      "label": "Heading color"
    },
    {
      "type": "color_background",
      "id": "heading_gradient",
      "label": "Heading gradient"
    }
  ],
  "blocks": [
    {
      "type": "blog",
      "name": "Blog",
      "settings": [
        {
          "type": "blog",
          "id": "blog",
          "label": "Blog"
        },
        {
          "type": "range",
          "id": "posts_count",
          "min": 2,
          "max": 9,
          "label": "Posts to show",
          "default": 3
        },
        {
          "type": "checkbox",
          "id": "stack_items",
          "label": "Stack on mobile",
          "default": false
        }
      ]
    },
    {
      "type": "article",
      "name": "Blog post",
      "settings": [
        {
          "type": "article",
          "id": "article",
          "label": "Blog post"
        },
        {
          "type": "color",
          "id": "background",
          "label": "Background"
        },
        {
          "type": "color",
          "id": "text_color",
          "label": "Text"
        }
      ]
    }
  ],
  "presets": [
    {
      "name": "Blog posts",
      "blocks": [
        {
          "type": "blog",
          "settings": {
            "blog": "news"
          }
        }
      ]
    },
    {
      "name": "Featured blog post",
      "settings": {
        "title": "",
        "link_text": ""
      },
      "blocks": [
        {
          "type": "article"
        }
      ]
    }
  ]
}
{% endschema %}

Yeah this is an issue that has plagued many projects I have worked on in the past.

For those it was more of hiding products from showing within collections which resulted in the awkward amount of products displayed at the time.

In the case of blog posts, are you filtering them with the tags (example: /tagged/news)?

If so, then the pagination should still work as expected.

If you’re instead trying to have this in a section then you may look into using the Section Rendering API or AJAX templates (paginate by 1000, ?view=filtered-articles with no layout, for example) then pulling and replacing the view when filtered.

Hey Rob, thanks for your reply

Yeah I’m using the tags that you can manually create for each blog posts when you go in the admin panel.

I’ve tried using the blog template and filtering and pagination work well but the issue is that I’m my client wants to have different blogs like a “resources page” where you only see certain types of blog posts for like homeowners or industrial apart from the default “News” blog. But also we can’t change the URL of the original blogpost since it would affect its ranking and I belive you can’t have multiple templates assigned to one blog so using the blog template is not ideal in my case.

So that’s why I’m trying to use a customer section as show in the code.

So thank you so much for your answer, I’ll look into the options that you shared.

Thanks!

You could link to the blogs with the ?view=template-name approach so that they use a specific template.

Regarding having separate blogs that is doable too. I get that the URL issue would be there to start but you could always set up URL redirects for the old posts so that they still link in properly.

Personally, I think setting up the new blogs/templates and URL redirects would be the ideal approach here. Then you would not need to do various AJAX calls and replace views based on the sounds of it. (I mean you could still do that for a potentially smoother experience than needing to load an entire page.)

Hey Rob, thanks again for your answers.

I’ve tried the redirect link approach by setting up the new blog and adding some blog posts (just title image and excerpt) and then setting up the redirect with the link of the new blog posts to the old one, but I was having a hard time making them work. Then I realized that the link that’s redirecting from (Redirect from) needs to not be an active page, but I need it to be active so it displays in this new “Resources” page.

Any recommendations on how to resolve this? I’m not sure if there’s like a different way to set up link-redirects.

Thanks

Redirect from does not need to be an active page. You could setup something like /join that redirects to checkout with a membership subscription product if you wanted to.

It is a means of redirecting A to B where B should be something on the storefront.