Showing all reviews and ratings on a page in Magento
Finally, a new post, and at last it is about Mangeto Commerce (http://www.magentocommerce.com/). In my first Magento how-to you’ll learn how to retrieve all product reviews and show them on a single page, together with the average rating. For this, I assume you have already created a new module and are able to view the page. You’ll only need to manipulate a block and a template.
First, let’s retrieve the reviews collection (this method will go into the block):
function getReviews() {
$reviews = Mage::getModel('review/review')->getResourceCollection();
$reviews->addStoreFilter( Mage::app()->getStore()->getId() )
->addStatusFilter( Mage_Review_Model_Review::STATUS_APPROVED )
->setDateOrder()
->addRateVotes()
->load();
return $reviews;
}
We’re using Mage_Review_Model_Mysql4_Review_Collection, which is a resource model. First setup the collection, filtering by store – we only want to retrieve the product reviews in the current store -, by status – show only approved reviews -, and ordering by date in reverse order, then load the collection.
addRateVotes() helps loading all the ratings/votes for that review. We’re gonna use this collection to compute the average rating.
Next, let’s move on to the template for a second. We’re gonna call the getReviews() method, then iterate through all the reviews. For each review you would probably want to display the title, nickname, date and details, but also the product associated and the user rating. For the first four, things are pretty easy, all you have to do is call getTitle(), getNickname(), getDetail(), getCreatedAt() on each review object.
To display the product name & link, we need to retrieve the product associated with each review – unfortunately I wasn’t able to find a way to join the product tables inside the query for retrieving all the reviews. So, we need to create a helper method inside our block, called getProduct(). We’re gonna use a storage/registry variable called _loadedProducts, so that we avoid loading the same product multiple times.
function getProduct( Mage_Review_Model_Review $review ) {
if( !isset($this->_loadedProducts[ $review->getEntityPkValue() ]) ) {
$this->_loadedProducts[$review->getEntityPkValue()] = Mage::getModel('catalog/product')->load( $review->getEntityPkValue() );
}
return $this->_loadedProducts[ $review->getEntityPkValue() ];
}
And inside the template:
<?php $_prod = $this->getProduct( $review ); ?> <a href="<?php echo $_prod->getProductUrl(); ?>"><?php echo $_prod->getName(); ?></a>
One last thing, if you intend to display the average rating of each review, add another helper method inside the block:
function getAverageRating( Mage_Review_Model_Review $review ) {
$avg = 0;
if( count($review->getRatingVotes()) ) {
$ratings = array();
foreach( $review->getRatingVotes() as $rating ) {
$ratings[] = $rating->getPercent();
}
$avg = array_sum($ratings)/count($ratings);
}
return $avg;
}
And then call it in the template (in this example we’re using Magento’s default styling):
<div class="rating-box"> <div class="rating" style="width: <?php echo ceil($this->getAverageRating( $review )); ?>%;"></div> </div>
That is all! You now have a page where all product reviews can be display.
Things to consider: pagination and cache!
Update: Seems that Magento comes prepared for reviews on products, categories and customers. We only need to load product reviews, so it would be wise to filter by entity. Unfortunately, the current version of Magento doesn’t allow filtering for a certain entity, only by entity and entity PK (which is the product ID in this case). Of course, we could write a decorator and write a method to just add a filter for entity_code = 'product', but the quickest (and dirtiest) way of doing it is by adding a check inside the template foreach loop (or adding a helper method in the block):
if( $review->getEntityId() == 1 ) { continue; }
//1 is the id of the 'product' entity - if you write a method, use a class constant
Note: This has only been tested on Magento 1.3.x – 1.5.x.

