How to loop through all pages and render 3 posts randomly

I want to implement an option where I want to show 3 related blog posts at the bottom of every blog post. Here I am encountered with 2 problems
1: When I use {{ range .Site.pages }} it loops through all content pages(I have some other content apart from blog in my content folder) and I {{ range .Site.Pages where }} is not working in single.html.
2: I don’t want to include current post in the related posts. So, somehow I should exclude the current post in the loop. I couldn’t find the way to do so.
Early suggestions needed.

Hello @kiran-nani,

Try the following snippet:

{{ $randomPosts := shuffle .Site.Pages | first 3 }}

It shuffles the array with all the pages and take the first three elements that could be rendered…

Ya of course but in my content folder I have the following folders - blog, landingpages and some other pages. So, when I loop through the pages using .Site.Pages it gives all pages but I want to loop through blog only

Then let’s modify our small script :wink:

{{ $randomPosts := shuffle (where .Site.Pages "Type" "blog") | first 3 }}

In default/single.html where function is not working…:pensive:

Such functions should be accessible in all templates. Could you post the error message that Hugo outputs?

Sorry, it’s working with where function. Now, the problem is that it prints the current post also as a related post, how can I overcome this

Could you elaborate that you mean with related post

The random posts are stored in $randomPosts as a list. Hence you’ve to range over this list to display the random page’s content.

Sorry, It may be my problem that not to convey my problem perfectly. Just assume the following situation:
I am on a single blog page(Let the name of the blog be" How to use hugo" ) and at the bottom I have 3 related posts. Now, when I use the above code with shuffle and range functions to print 3 random posts some times it prints the post that I read above(i.e., “How to use hugo”). In short when I read blog 1 it should show 2, 3, 4 as suggested instead of 1, 2, 3

I shouldn’t answer posts if I’m in hurry. Nonetheless, thanks for the clarification. After filtering out all pages of type post we’ve to apply a second filter to remove the current page.

My approach is to use the .UniqueID variable of each page. It’s unique id for the current page (actually the MD5 hash of the content file’s path). The second filter ranges over all pages and compares the unique id of all blog posts with the unique id of the current page. If the unique ids aren’t equal we include them the $filteredPosts.

{{ $filteredPosts := where (where .Site.Pages "Type" "blog") "UniqueID" "!= ".UniqueID }}
{{ $relatedPosts := shuffle $filteredPosts | first 3 }}

@digitalcraftsman
{{ range first 3 where (where .Site.Pages "Type" "blog") "UniqueID" "!= ".UniqueID | shuffle }} {{ .Render "summary" }} {{ end }}
getting an error if I use above code :point_up_2:

Which code? The code you’re providing or the code that @digitalcraftsman is providing?

Did you try @digitalcraftsman 's code instead?

{{ $filteredPosts := where (where .Site.Pages "Type" "blog") "UniqueID" "!= ".UniqueID }}  
{{ $relatedPosts := shuffle $filteredPosts | first 3 }}  
{{ range $relatedPosts }}  
{{ .Render "summary"}}  
{{ end }}  

Can you include your error from the console, please? Also, just guessing, but do you have a summary.html view since that’s what you’re calling in your last example?

Hey there. I’d also like to arrange some posts in the footer of every page randomly. I tried the code mentioned in this topic and an error occurred:

ERROR 2017/12/06 11:00:01 Failed to add template "blog/single.html" in path "/home/rea/works/theblog/layouts/blog/single.html": template: blog/single.html:163: unexpected . after term "\"!= \""
ERROR 2017/12/06 11:00:01 blog/single.html : template: blog/single.html:163: unexpected . after term "\"!= \""
ERROR 2017/12/06 11:00:01 Error while rendering "page": template: "blog/single.html" is an incomplete or empty template