Displaying product rating and reviews
The Reviews & Ratings API allows you to access product rating information, post new reviews and fetch a list of existing product reviews. If you follow the instructions in this documentation, or if you used the default store template as the base for your store, you can add all elements described below to the product_partial partial. We suggest you to create separate partials for each element, to keep the product details partial simple.
Required scripts
The rating selector requires mootools_more.js and demo_effects.js scripts to be loaded on the page. You can find the scripts in Combining and minifying JavaScript and CSS files article on LemonStand form.
Displaying product rating
The Shop_Product class has two fields which you can use for extracting the product rating information:
- $rating_approved - returns a rating based on approved reviews.
- $rating_all - returns a rating based on all reviews, included non-approved.
The both fields return a value in the 0 - 5 range. Value 0 means that there is no rating information available for the product. Values have increment of 0.5 i.e.: 1, 1.5, 2, 2.5, 3, 3.5, 4. 4,5, 5. There is no 0.5 value, because the minimal rating a visitor can set is 1.
To display a product rating on the Product Details page you can just output the rating value to the page:
Product rating: <?= $product->rating_all ? $product->rating_all : '(no rating information)' ?>
{% set rating = field(product, 'rating_all') %}
Product rating: {{ rating is null ? '(no rating information)' : rating }}Also you can implement a more sophisticated CSS solution and display ratings as stars:

Implementation example:
<?
$rating = $product->rating_all;
?>
<span class="rating_stars rating_<?= str_replace('.', '', $rating) ?>">
<?= $rating ? null : '(no rating information)' ?>
</span>{% set rating = field(product, 'rating_all') %}
<span class="rating_stars rating_{{ rating|replace({'.':''}) }}">
{{ rating is null ? '(no rating information)' : null }}
</span>The code outputs a span element with CSS two CSS classes applied. The second CSS class names depends on a product rating and it can be used for applying corresponding backgrounds using a CSS stylesheet. In your Demo store we use the following use in the CSS file:
span.rating_stars {
display: block;
height: 20px;
margin-bottom: 18px;
background: transparent url(../images/rating_stars_large.png) no-repeat -2px -180px;
padding-left: 100px;
padding-top: 3px;
color: #666666;
font-size: 11px;
}
.rating_selector span.rating_stars {
width: 96px;
padding-left: 0;
margin-top: 3px;
cursor: pointer;
}
span.rating_stars.rating_1 {background-position: -2px -160px;}
span.rating_stars.rating_15 {background-position: -2px -140px;}
span.rating_stars.rating_2 {background-position: -2px -120px;}
span.rating_stars.rating_25 {background-position: -2px -100px;}
span.rating_stars.rating_3 {background-position: -2px -80px;}
span.rating_stars.rating_35 {background-position: -2px -60px;}
span.rating_stars.rating_4 {background-position: -2px -40px;}
span.rating_stars.rating_45 {background-position: -2px -20px;}
span.rating_stars.rating_5{background-position: -2px 0;}We have images for all ratings in a single PNG file:

Displaying a list of product reviews
There are two methods in the Shop_Product class which allow you to fetch product reviews:
- list_reviews() - returns only approved reviews.
- list_all_reviews() - returns all reviews, including non-approved.
Both methods return a collection (Db_DataCollection) of reviews. Each element in the collection is an object of the Shop_ProductReview class.
To display a list of reviews you can use the following code:
<?
$reviews = $product->list_all_reviews();
if (!$reviews->count):
?>
<p>There are no reviews for this product.</p>
<? else: ?>
<ul>
<? foreach ($reviews as $review): ?>
<li>
<? if ($review->rating): ?>
<span class="rating_stars_small rating_<?= $review->rating ?>"><?= $review->rating ?></span>
<? endif ?>
<h4><?= h($review->title) ?></h4>
<p class="description">Posted by <?= h($review->author) ?> on <?= $review->created_at->format('%x') ?></p>
<p><?= nl2br(h($review->review_text)) ?></p>
</li>
<? endforeach ?>
</ul>
<? endif ?>{% set reviews = product.list_all_reviews() %}
{% if not reviews.count %}
<p>There are no reviews for this product.</p>
{% else %}
<ul>
{% for review in reviews %}
<li>
<span class="rating_stars_small rating_{{ review.rating }}">{{ review.rating }}</span>
<h4>{{ review.title }}</h4>
<p class="description">Posted by {{ review.author }} on {{ review.created_at.format('%x') }}</p>
<p>{{ review.review_text|nl2br }}</p>
</li>
{% endfor %}
</ul>
{% endif %}This code outputs a list of reviews in the following format:

Each review can have a rating. You can output review ratings as numbers, or using the CSS method described earlier. Below are CSS rules which we use for styling review ratings in the LemonStand demo store.
span.rating_stars_small
{
display: block;
width: 73px;
height: 15px;
text-indent: -100000em;
text-align: left;
background: transparent url(../images/rating_stars_small.png) no-repeat -3px -135px;
margin: 8px 0;
}
span.rating_stars_small.rating_1 {background-position: -3px -120px;}
span.rating_stars_small.rating_2 {background-position: -3px -90px;}
span.rating_stars_small.rating_3 {background-position: -3px -60px;}
span.rating_stars_small.rating_4 {background-position: -3px -30px;}
span.rating_stars_small.rating_5 {background-position: -3px top;}The image:

Creating the Write a Review form
The Write a Review form should contain fields for entering the review title, visitor's name, email, rating and the review text. The code below creates a simple review form:
<? if (isset($review_posted)): ?>
<p>Your review has been successfully posted.</p>
<? else: ?>
<h3>Write a review</h3>
<label>Rating</label>
<select name="rating">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<label for="review_title">Title</label>
<input id="review_title" name="review_title" type="text"/>
<? if (!$this->customer): ?>
<label for="review_author_name">Your Name</label>
<input id="review_author_name" name="review_author_name" type="text"/>
<label for="review_author_email">Email</label>
<input id="review_author_email" type="text" name="review_author_email"/>
<? endif ?>
<label for="review_text">Review</label>
<textarea rows="5" id="review_text" name="review_text"></textarea>
<input type="button" value="Submit" onclick="return $(this).getForm().sendRequest('shop:on_addProductReview', {
extraFields: {no_flash: true},
update:{'product_page': 'product_partial'}
})"/>
<? endif ?>{% if review_posted is defined %}
<p>Your review has been successfully posted.</p>
{% else %}
<h3>Write a review</h3>
<label>Rating</label>
<select name="rating">
<option value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<label for="review_title">Title</label>
<input id="review_title" name="review_title" type="text"/>
{% if not this.customer %}
<label for="review_author_name">Your Name</label>
<input id="review_author_name" name="review_author_name" type="text"/>
<label for="review_author_email">Email</label>
<input id="review_author_email" type="text" name="review_author_email"/>
{% endif %}
<label for="review_text">Review</label>
<textarea rows="5" id="review_text" name="review_text"></textarea>
<input type="button" value="Submit" onclick="return $(this).getForm().sendRequest('shop:on_addProductReview', {
extraFields: {no_flash: true},
update:{'product_page': 'product_partial'}
})"/>
{% endif %}
The code hides the author name and author email fields for logged in customers. For choosing a product rating you can use a simple drop-down menu or a jQuery (or MooTools) plugin. The submit button triggers an AJAX request which invokes the shop:on_addProductReview handler. This handler adds a review to the database. Also the request updates the product page. The implementation will work without any modifications if you use the default store (included to the installer) as a basement for your store, or if you followed development instructions explained in this documentation. Specifically, the AJAX request configuration supposes that there is an element with the product_page identifier on a page, and that there is a partial named product_partial, which displays the product information.
Next: Displaying product bundle items
Previous: Displaying product manufacturer information
Return to Product page
