Skip to main content

Sitecore

SXA Map component Part 7 Most Relevant Google reviews

A red car driving down and winding road

Challenge:

As a user, while browsing locations or businesses on the SXA Map, I want to see the most relevant Google review comments so I can gain more insights about the location or business.

Solution:

To set up the SXA Map on the page and add Google average rating and total reviews in the info window of the markers, please check the post-SXA Map component Part 6 Google average rating and total reviews.

Once we complete the discussed implementation in the above post, we enhance the SXA Map to display the most relevant Google reviews comments in a modal when we click “Google average rating and total reviews” shown in the info window.

A quick look at the following output of the implementation discussed in this post so we get more clarity.

Quick Look On Google Rating and Review Modal with Most relevant Google reviews

Quick Look On Google Rating and Review Modal

 Include Bootstrap JS in the SXA Site Theme

Please refer to the post – Integrate Library in Sitecore SXA authored by one of my awesome colleagues, – Anchal Katoch, to include Bootstrap JS to our SXA Site Theme. This is needed for our Modal implementation.

Create a Modal Template for the most relevant Google reviews and other general data of the Business or Location

We can use the same page we developed as part of the post SXA Map component Part 6 Google average rating and total reviews. Or duplicate the same page item. Open the page item in the experience editor. Add a rendering in the main placeholder > Page Content > Plain HTML (Reusable). Add the data source and update the field “Code” with the following Modal Template code.

<div class="modal fade d-none" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel"></h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-rating-and-review"></div>
      <div class="modal-body">                
        <div class="google-review-comment row d-none">
            <div class="col-4">
                <img class="profile_photo_url" src="INSERT_PROFILE_PHOTO_URL_HERE" alt="Profile Photo"/>
            </div>
            <div class="col-8">
                <a class="author_name" href="INSERT_AUTHOR_URL_HERE" target="_blank">INSERT_AUTHOR_NAME_HERE</a>
                <div class="rating">INSERT_RATING_HERE </div>
                <div class="relative_time_description">INSERT_RELATIVE_TIME_DESCRIPTION_HERE</div>
                <div class="time">Posted on INSERT_TIME_HERE</div>
                <p class="text">INSERT_REVIEW_TEXT_HERE</p>
            </div>
        </div>
        <div>
            <a class="more_reviews" href="" target="_blank">Check on Google Map for more reviews</a>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>

To simplify, we’ve used the “Plain HTML (Reusable)” rendering. You can choose an alternative method, such as cloning the Page Content or adding a Page content variant, to incorporate this code into Scriban. Any of these approaches will be effective as long as we successfully place this code on the page.

Add click event on the “Google average rating and total reviews” shown in the info window to prepare and open the modal.

Download the latest files custom-location-rating-and-review.js and component-map-location-rating.scss, and copy them to the desired scripts and sass folders in the Theme folder. Basically, we update the existing files here.

We have made some updates to custom-location-rating-and-review.js. In these updates, we have enhanced the requestPlaceDetails function by including ‘reviews’ in the fields parameter, which allows us to retrieve the reviews list in the response of getDetails(). Furthermore, to facilitate the preparation and opening of the modal, we have also updated the getRatingAndReviewByPlaceID() function to handle the click event on the “Google average rating and total reviews” displayed in the info window. Additionally, we’ve introduced a new function, getDateAndTimeFromTimestamp(), as follows.

function requestPlaceDetails(ratingAndReviewDiv, noRatingAndReviewDiv) {
    return function (results, status) {
        if (status === google.maps.places.PlacesServiceStatus.OK) {
            var request = {
                placeId: results[0].place_id,
                fields: ['rating', 'user_ratings_total','reviews'] //reviews has been added so we get the reviews in response
            };
            var sxamap = XA.connector.mapsConnector.getMaps()[$('.map-canvas').attr('id')];
            var service = new google.maps.places.PlacesService(sxamap);
            service.getDetails(request, getRatingAndReviewByPlaceID(ratingAndReviewDiv, noRatingAndReviewDiv));
        }
    };
}

function getRatingAndReviewByPlaceID(ratingAndReviewDiv, noRatingAndReviewDiv) {
    return function (place, status) {
        if (status == google.maps.places.PlacesServiceStatus.OK) {
            if(noRatingAndReviewDiv.length > 0 && ratingAndReviewDiv.length > 0)
            {
                if (place.rating != undefined && place.user_ratings_total != undefined) {
                    ratingAndReviewDiv.toggleClass('ratings-and-reviews');
                    ratingAndReviewDiv.removeClass('d-none');
                    ratingAndReviewDiv.html(ratingAndReviewDiv.html().replace('#average_rating#', `${place.rating.toFixed(1)} <i data-star="${place.rating.toFixed(1)}"></i>`).replace('#review_count#', place.user_ratings_total));
                    
                    //On click of Rating and review text, open the Modal showing the most relavant reviews.  
                    ratingAndReviewDiv.click(function(){
                        var existingReviewModal = $(`${ratingAndReviewDiv.attr('id')}-modal`);
                        var reviewModal;
                        var exampleModel = $('#exampleModal');
                        if(exampleModel.length == 0)
                        {
                            return;
                        }
                        
                        if(existingReviewModal.length == 0)
                        {
                            var locationName = $(`#${ratingAndReviewDiv.attr('id')}-main .title`).text();
                            var ratingAndReviewData = ratingAndReviewDiv.html();
                            reviewModal = exampleModel.clone();
                            reviewModal.attr('id',`${ratingAndReviewDiv.attr('id')}-modal`);
                            reviewModal.removeClass('d-none');
                            reviewModal.find('.modal-title').text(locationName);                                
                            reviewModal.find('.modal-rating-and-review').html(ratingAndReviewData);
                            var commentTemplate = reviewModal.find('.google-review-comment');
                            $.each(place.reviews, function(i, comment) {
                                var reviewComment = commentTemplate.clone();
                                reviewComment.find('.profile_photo_url').attr('src',comment.profile_photo_url);
                                reviewComment.find('.author_name').text(comment.author_name);
                                reviewComment.find('.author_name').attr('href',comment.author_url);
                                reviewComment.find('.rating').html( `${comment.rating.toFixed(1)} <i data-star="${comment.rating.toFixed(1)}"></i>`);
                                reviewComment.find('.relative_time_description').text(comment.relative_time_description);
                                reviewComment.find('.time').text(getDateAndTimeFromTimestamp(comment.time));
                                reviewComment.find('.text').text(comment.text);
                                reviewComment.appendTo(reviewModal.find('.google-review-comment').parent());
                                reviewComment.removeClass('d-none');
                            });
                            reviewModal.find('.more_reviews').attr("href",`https://www.google.com/maps?q=${encodeURIComponent(locationName)}`);
                            reviewModal.find('.more_reviews').detach().appendTo(reviewModal.find('.google-review-comment').parent());
                            reviewModal.appendTo($('exampleModal').parent());
                        }
                        else
                        {
                            reviewModal = existingReviewModal;
                        }
                        var myModal = new bootstrap.Modal(reviewModal, {
                          keyboard: false
                        });
                        myModal.toggle();
                    });
                    noRatingAndReviewDiv.remove();
                }
            }
        }
    };
}

function getDateAndTimeFromTimestamp(timestamp)
{
    const date = new Date(timestamp * 1000);
    const formattedDate = date.toLocaleString();
    return formattedDate;
}

Run the following commands in PowerShell from the Site Theme folder, or build with your custom command, if any.

gulp buildAll

sxa upload All

Demo

Final demo showing the items and page.

Final Demo of Google Rating and Review Modal with Most relevant Google reviews

Final Demo of Google Rating and Review Modal

Reviews list in response from getDetails() contains a maximum of 5 reviews sorted by “Most Relevant” by default (Reference). Hence, we have given a link, “Check on Google Maps for more reviews,” in the Modal at the end of the Reviews list, which leads to the location on Google Maps. From there, users can check the reviews tab for more reviews.

From each review comment, we extract the following data in the getDetails() response: profile_photo_url, author_name, author_url, rating, relative_time_description, time (converted to Date and Time), and text. We then bind this data to the Modal in custom-location-rating-and-review.js.

Check out the Map Extension 2.0 Repository for the implementation shown in this post.

Note: To fetch all the reviews of the Business, you may explore the Google Business Profile API service.

Hope this helps, and please do check out other SXA Map component posts for more enhancements around Map.

Happy Sitecore Learning 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Sandeepkumar Gupta

Sandeepkumar Gupta is a Lead Technical Consultant at Perficient. He enjoys research and development work in Sitecore. He has contributed to Sitecore projects based on SXA, ASP.NET MVC, and Web Forms. He has also contributed to Sitecore upgrade projects.

More from this Author

Categories
Follow Us