Download
We're evolving to serve you better! This current forum has transitioned to read-only mode. For new discussions, support, and engagement, we've moved to GitHub Discussions.

Filtering Post Navigation ( {{nextPost}} and {{previousPost}} ) by tag

  • #6044
    Avatar photo[anonymous]

    Hi everyone!

    I’m working on creating a custom post.hbs template for a section of my website where the next post and previous post would be filtered to only display the next and previous post of a particular, specific tag (ordered by publish date).

    I know that it’s possible to create a post list from specific tags into an article, and that the {{#getPostsByTags}} helper exists, but what would be the best practice to combine {{nextPost}} / {previousPost}} with {{#getPostsByTags}}?

    I’m using the premium Documentation theme.

    #6048
    Avatar photo[anonymous]

    Hi,

    I afraid that at this moment preparing such feature will be quite complicated. In fact you should prepare a custom helper (https://getpublii.com/dev/tags/custom-helpers/) which uses @website.contentStructure.posts (https://getpublii.com/dev/website-global-variable/) to meet your conditions for every post. It is in my opinion possible but can be complicated to implement.

    #6157
    Avatar photo[anonymous]

    Thanks for your reply, Tomasz!

    I’ve decided to go with a workaround, where I created three custom post templates for the posts in the section of my site. I’m sharing my workaround below in case it helps anyone.

    I made sure that the posts that were intended for this particular section of my site were published/backdated one after the other in order. I then created the following custom templates for:

    1. The “first” post
    2. The “middle” posts
    3. The “last” post

    For the “first” post template, I took out the previous post navigation.

    For the “last” post template, I removed the next post navigation.ย  (I would post the exact lines of code, but I keep getting blocked by the forum)

    This way, the navigation between posts in this particular section of my site remains somewhat self-contained.

    #6161
    Avatar photo[anonymous]

    Interesting feature request ๐Ÿ™‚ I have taken the fridom to make a helper that does this, if it only has one tag. This helper will get the next and previous post for all of the tags to that post.

    Skjermbilde-2021-08-13-kl.-22.24.35

    module.exports = function (Handlebars) {
     		return {
    
      // Helper that findes the next and previous post for each tag.
      nextPreviousPostByTag: function(thisPost, allTagsWithPosts) {
        
        let nextPosts = [];
        let previousPosts = [];
        
        // going through all the tags
        for (tagIndex in thisPost.tags) {
        
          // All the post to that tag.
          let tagPosts = allTagsWithPosts.find(tag => tag.id == thisPost.tags[tagIndex].id);
          // This post are number X in that tag-post list.
          thisPostIndex = tagPosts.posts.findIndex(post => post.id == thisPost.id);
          
          // Find post by index and put in array.
          function GetPost(postIndex, postArray) {
            
            let postAllreadyFound = postArray.find(post => post.id == 
                    tagPosts.posts[postIndex].id);
            if (postAllreadyFound) {
              // If post already are added because it was found through a diffrent tag.
              postAllreadyFound['tags'].push(tagPosts.name);
            } else {
            
              let post = {};
              post['id'] = tagPosts.posts[postIndex].id;
              post['title'] = tagPosts.posts[postIndex].title;
              post['url'] = tagPosts.posts[postIndex].url;
              post['tags'] = [];
              post['tags'].push(tagPosts.name);
              
              postArray.push(post);
              
            }
          }
          
          // If this post is not first post with that tag, find next.
          if (thisPostIndex > 0) {
          
            GetPost(thisPostIndex - 1, nextPosts);
            
          }
          
          // If this post is not last post with that tag, find previous. 
          if (thisPostIndex < tagPosts.posts.length - 1) {
          
            GetPost(thisPostIndex + 1, previousPosts);
    
          }
        }
            
        let output = [];
        output.push(nextPosts);
        output.push(previousPosts);
          
        return output;
      }	
     		};
     };
     		
    
    
    //////////////////////////////////////////////////////////////////////////////
    
    ////////// In post.hbs:
    
      <nav style="display: flex; justify-content: space-between; align-items: flex-start">
        {{#each (nextPreviousPostByTag this @website.contentStructure.tags)}}
          
      {{#each this}}
    • {{title}} <br> {{#each tags}}{{this}} {{/each}}
    • {{/each}}
    {{/each}} </nav> ////// in config.json "renderer": { ... "includeHandlebarsInHelpers": true,
    #6212
    Avatar photo[anonymous]
    Thank you for sharing this helper t79! I really appreciate it. ๐Ÿ™‚
    I just had a few follow-up questions:
    • Where would this helper code (everything above “<span class=”enlighter-c0″>////////// In post.hbs:” in your code snippet) live in the theme directory?
      </span>
    • Where in the code snippet should one swap out the name of the tag they want to filter through

    Thanks again!

    #6214
    Avatar photo[anonymous]

    Hi.

    The last question first:

    If you only want to filter on a specific tag you have to change line 11 (or line 8, if you have the same bug in the code viewer as me sometimes).

    That will be from:
    for(tagIndex in thisPost.tags) { ย 
    
    to:
    for(tagIndex inย [{'id':1}]) {"

    Where the id number is the tag id you find in the list of tags inside of publii.

    You can also just remove the for loop, and then change the next line.

    .find(tag => tag.id == thisPost.tags[tagIndex].id);
    
    to:
    .find(tag => tag.id == 1);
    
    or maybe better:
    .find(tag => tag.name == 'icecream');
    

    First question:

    The code lives in the ‘helpers.js’ file, that you probably have to create. And it is located in the root folder together with ‘index.hbs’.

    Update to the code:

    I have made a small change in the output of the helper, so it becomes easier for me to place the content.

    {{#each (nextPreviousPostByTag this @website.contentStructure.tags) }}
      
      {{#if notEmpty}}
      
        <nav style="display: flex; justify-content: space-between; width: 100%;">
        
        <ul style="flex-grow: 1; text-align: left; list-style-type: none; padding: 0;">
          {{#each next}}
            
  • {{title}}
  • {{/each}} <ul style="flex-grow: 1; text-align: right; list-style-type: none; padding: 0;"> {{#each prev}}
  • {{title}}
  • {{/each}} </nav> {{/if}} {{/each}}

    Then I want to say thanks for your problem since I now have new functionality in my webpage which I would not have thought of myself. You can see it here https://terjeurnes.com/todays-playlist-four-seasons-and-eternity.htmlย The page is still under construction and are not “published” yet, more technical stuff to fix ๐Ÿ™‚

#6215
Avatar photo[anonymous]

EDIT!!!! THE FIRST APPROACH DOES NOT WORK!

You have to remove the for loop and change the line below.

EDIT AGAIN. to sleepy today. I have to go through the code, will post it soon.

#6216
Avatar photo[anonymous]

Then I have it, I think. I have simplified it since you only are looking for one tag.

//// In helpers.js

module.exports = function (Handlebars) {
  return {

  nextPreviousPostByTag: function(thisPost, allTagsWithPosts) {
  
    let tagPosts = allTagsWithPosts.find(tag => tag.id == <YOUR TAG ID>); 
                  // or use: tag.name == <YOUR TAG NAME>);
      
    thisPostIndex = tagPosts.posts.findIndex(post => post.id == thisPost.id);
    
    function getPost(postIndex) {

      let post = {};
      post['title'] = tagPosts.posts[postIndex].title;
      post['url'] = tagPosts.posts[postIndex].url;

      return post      
    
    }

    var nextPosts = null;
    var previousPosts = null;

    if (thisPostIndex > 0) {
      nextPosts = getPost(thisPostIndex - 1);
    }
     
    if (thisPostIndex < tagPosts.posts.length - 1) {  
      previousPosts = getPost(thisPostIndex + 1);
    }

    let output = {
      "notEmpty": (previousPosts != null || nextPosts != null ? true : false),
      "next": nextPosts,
      "prev": previousPosts
    };
    
    return [output];
  }

  };
 };

//// In post.hbs

  {{#each (nextPreviousPostByTag this @website.contentStructure.tags) }}
    
    {{#if notEmpty}}
    
      <nav style="display: flex; justify-content: space-between; width: 100%;">
      
      <ul style="flex-grow: 1; text-align: left; list-style-type: none; padding: 0;">
        {{#if next}}
          
  • {{next.title}}
  • {{/if}} <ul style="flex-grow: 1; text-align: right; list-style-type: none; padding: 0;"> {{#if prev}}
  • {{prev.title}}
  • {{/if}} </nav> {{/if}} {{/each}}
    #6217
    Avatar photo[anonymous]

    And the helper can be simplified more. Have not tried but this should also work.

    module.exports = function (Handlebars) {
      return {
    
      nextPreviousPostByTag: function(thisPost, allTagsWithPosts) {
      
        let tagPosts = allTagsWithPosts.find(tag => tag.id == <YOUR TAG ID>); 
                      // or use: tag.name == <YOUR TAG NAME>);
          
        thisPostIndex = tagPosts.posts.findIndex(post => post.id == thisPost.id);
    
        var nextPosts = null;
        var previousPosts = null;
    
        if (thisPostIndex > 0) {
          nextPosts = tagPosts.posts[thisPostIndex - 1];
        }
         
        if (thisPostIndex < tagPosts.posts.length - 1) {	
          previousPosts = tagPosts.posts[thisPostIndex + 1];
        }
    
        let output = {
          "notEmpty": (previousPosts != null || nextPosts.length != null 
                                    ? true : false),
          "next": nextPosts,
          "prev": previousPosts
        };
        
        return [output];
      }
      
      };
     };
    #9591
    Avatar photo[anonymous]

    Thanks again t79, and happy to see that your example site is still up! Someone asked a similar question recently, and I remembered the detailed explanation you gave.

    I haven’t gotten a chance to test this myself, but it would be great to include this in the Custom Helpers guide, Publii team. ๐Ÿ™‚