1

I have a page that shows a listing of entries (called products) by category. Those product entries have related content (reviews) stored in another channel that are tagged using a relations field.

On the category page, I want to show the overall rating (the sum of all ratings)for each individual product shown.

I'm calculating and showing the overall rating currently on the product profile page with no problems. But on the category page, I'm having trouble showing that overall rating also. I think my problem is where I'm using the relatedto field (in my queryParams variable) to associate the reviews to the product entry associated with the category.

Any help is appreciated.


<!-- get category from URL -->
{% set category = craft.categories.group('productCategories').slug(craft.request.lastSegment).one %}


<!-- display craft product entries related to category-->

{% set entries = craft.entries.relatedTo(category)
    .limit(30)
    .orderBy ('dateCreated desc')
    .all() %}

<!-- set variable to grab the associated reviews -->

    {% set queryParams = {
        section: 'userProductReviews',
        relatedTo: 'entry'
    } %}

{% set reviewQuery = craft.entries(queryParams).all() %}

<!-- overall rating code -->

{# set sum of product ratings per entry#}

    {% set sumOverallratings = 0 %}

    {% for entry in reviewQuery %}
        {% set sumOverallratings = sumOverallratings + entry.overallRating %}
    {% endfor %}

{# the actual number of reviews related to product entry #} 

  {% set reviewCount =  craft.entries(queryParams).total() %}

{# set the average for the rating #}

    {% set productOverallAverage = sumOverallratings / reviewCount %} 

2

You nailed it! relatedTo: 'entry' is indeed your issue. Two problems I see with it: 1) you're checking for things related to the string entry, which doesn't do you a lot of good, and 2) even if it wasn't a string you're not setting the entry variable anywhere.

Here's what you need to do:

{% set category = craft.categories.group('productCategories').slug(craft.request.lastSegment).one %}

{# we should only continue if we actually have a category #}
{% if category %}

    {# let's call this products to keep things simpler #}
    {% set products = craft.entries
        .relatedTo(category)
        .orderBy('dateCreated desc')
        .limit(30)
        .all() %}

    {# we need to loop over our products before we even start worrying about the reviews #}
    {% for product in products %}

        {# obviously here is where you'd add your html markup to display the products #}
        {{ product.title }}

        {# we now have a `product` variable to use as our relatedTo param #}
        {% set productReviews = craft.entries
            .section('userProductReviews')
            .relatedTo(product)  
            .all() %}

        {# we can use the already existing query to get the total count (as opposed to sending off a whole new query) via the `| length` filter #}
        {% set reviewCount = productReviews | length %}
        {% set sumOverallRatings = 0 %}

        {# I've also renamed these variables to keep things easy to understand #}
        {% for review in productReviews %}
            {% set sumOverallratings = sumOverallRatings + review.overallRating %}
        {% endfor %}

        {% set productOverallAverage = sumOverallratings / reviewCount %}

        {# and now you have your average rating! #}
        {{ productOverallAverage }}

    {% endfor %}

{% endif %}

For bonus points, you could tidy up the part where you're querying and calculating the ratings (as long as you're on Twig 2.10+) using the reduce filter.

With reduce you could replace everything inside the {% for product in products %} ... {% endfor %} loop with this (and whatever html markup you're using):

{% set productReviews = craft.entries
    .section('userProductReviews')
    .relatedTo(product)  
    .all() %}

{{ productReviews | reduce((totalSum, review) => totalSum + review.overallRating) / productReviews | length }}

The reduce filter here is taking your array of product entries and basically adding up the value of all the overallRating fields, which we then divide by the length of the productReviews array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.