Sign in

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

  • This topic has 8 replies, 3 voices, and was last updated 1 month, 3 weeks ago by .
Viewing 9 posts - 1 through 9 (of 9 total)
  • Author
    Posts
  • #6044
    candidexmedia

    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
    Tomasz Dziuda

    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.

    --
    Do you appreciate the support you've received today? If so, consider donating to the Publii team by clicking here; we'll be sure to use your donation to make Publii even better!

    #6157
    candidexmedia

    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
    t79

    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
    candidexmedia
    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
    t79

    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
    t79

    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
    t79

    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
    t79

    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];
    }
    };
    };

     

Viewing 9 posts - 1 through 9 (of 9 total)
  • You must be logged in to reply to this topic.