Display average value from reviews in frontmatter

I have a business directory and I have just added reviews. These are working as planned.
In the frontmatter of the listings, the review ratings are written as follows
“1/5”
“2/5”
“3/5”
“4/5”
“5/5”

I would like to display an average rating of the reviews for each listing.

Here is an example of the review frontmatter for a business listing with two reviews.

reviews:
  review_1:
    name: "Jason W"
    date: "13th October 2022"
    rating: "2/5"
    activity: "Wildlife Experiences"
    statement: "I am not happy with the experience. I was bored and couldn't wait to leave... Not impressed!"
    response: 
      name: "Geoff T"
      date: "14th October 2022"
      statement: "Apologies, please contact us for a full refund."

  review_2:
    name: "William K"
    date: "14th October 2022"
    rating: "4/5"
    activity: "Wildlife Experiences"
    statement: "Pretty good!"
    response: 
      name: "Geoff T"
      date: "14th October 2022"
      statement: "Thank you!"

How do I add the ratings and divide them by the number of reviews?

It would be simpler to store the rating as an integer. You can add “out of 5” in your template.

To clarify, do you mean storing 1, 2, 3, 4 or 5 instead without quotes. Yes, that’s doable.

rating: 2

Say I did that, how would you display an average rating for the page?

First, structure your front matter “reviews” as an array of reviews.

reviews:
- id: review_1
  name: "Jason W"
  date: "13th October 2022"
  rating: 2
  activity: "Wildlife Experiences"
  statement: "I am not happy with the experience. I was bored and couldn't wait to leave... Not impressed!"
  response: 
    name: "Geoff T"
    date: "14th October 2022"
    statement: "Apologies, please contact us for a full refund."
- id: review_2
  name: "William K"
  date: "14th October 2022"
  rating: 4
  activity: "Wildlife Experiences"
  statement: "Pretty good!"
  response: 
    name: "Geoff T"
    date: "14th October 2022"
    statement: "Thank you!"

To calculate average rating in your template:

{{ $ratingTotal := 0 }}
{{ range .Params.reviews }}
  {{ $ratingTotal = add $ratingTotal .rating }}
{{ end }}
{{ $ratingAverage := div $ratingTotal (len .Params.Reviews) }}

Note that we are dividing one integer by another, which results in an integer. If you would prefer your average to be a float:

{{ $ratingAverage := div (float $ratingTotal) (len .Params.Reviews) }}

To display with one digit after the decimal point:

{{ $ratingAverage | printf "%.1f out of 5.0" }}

Although not required, I find this data structure is easier to comprehend, and it eliminates the need for a unique key for each review. So unless you need the key for some reason, you can simplify the front matter with:

reviews:
- name: "Jason W"
  date: "13th October 2022"
  rating: 2
  activity: "Wildlife Experiences"
  statement: "I am not happy with the experience. I was bored and couldn't wait to leave... Not impressed!"
  response: 
    name: "Geoff T"
    date: "14th October 2022"
    statement: "Apologies, please contact us for a full refund."
- name: "William K"
  date: "14th October 2022"
  rating: 4
  activity: "Wildlife Experiences"
  statement: "Pretty good!"
  response: 
    name: "Geoff T"
    date: "14th October 2022"
    statement: "Thank you!"

Thank you for your help. I have restructured the frontmatter and that all seems to be working without a hitch with my current reviews.

However, I am getting an error on the following:

{{ $ratingTotal := 0 }}
{{ range .Params.reviews }}
  {{ $ratingTotal = add $ratingTotal .rating }}
{{ end }}

{{ $ratingAverage := div (float $ratingTotal) (len .Params.Reviews) }}

The error:

render of "page" failed: ".../themes/outlearn/layouts/directory-city/single.html:240:47": execute of template failed at <len .Params.Reviews>: error calling len: reflect: call of reflect.Value.Type on zero Value render of "page" failed: call of reflect.Value.Type on zero Value  failed to render pages: call of reflect.Value.Type on zero Value 

My frontmatter is currently:

reviews:
- name: "Jason W"
  date: "13th October 2022"
  rating: 2
  activity: "Wildlife Experiences"
  statement: "I am not happy with the experience. I was bored and couldn't wait to leave... Not impressed!"
  response: 
    name: "Geoff T"
    date: "14th October 2022"
    statement: "Apologies, please contact us for a full refund."
- name: "William K"
  date: "14th October 2022"
  rating: 3
  activity: "Wildlife Experiences"
  statement: "Pretty good!"
  response: 
    name: "Geoff T"
    date: "14th October 2022"
    statement: "Thank you!"

One or more of the content pages rendered by your template does not contain any reviews in front matter.

So we code defensively:

{{ with .Params.reviews }}
  {{ $ratingTotal := 0 }}
  {{ range . }}
    {{ $ratingTotal = add $ratingTotal .rating }}
  {{ end }}
  {{ $ratingAverage := div (float $ratingTotal) (len .) }}
  {{ $ratingAverage | printf "%.1f out of 5.0" }}
{{ end }}
2 Likes

That worked perfectly. I have adjusted it to display stars, but your answer worked as intended. Thank you!

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.