Product Comparison Tool

Client: “Now that we have all of our product data loaded into the new site, I want a tool where users can select multiple products and compare them side by side.”

Gulp….“Let me think about that one for a bit…”

 
Download the EE Code for Product Comparison Tool

Not an unreasonable request, right?  As a consumer I’ve often used such tools to quickly compare multiple products I was interested in purchasing.  Comparison tables can quickly help you find differences and similarities that would be tough to see bouncing around different product-specific pages.

But how to pull this off on an ExpressionEngine based site?

As is so often the case with EE, what looks difficult at first blush turns out to not be too difficult.  Let me show you the front end of what I came up with so you can better tell if it’s close to what you need:

There is a short screencast here that requires Flash, but isn’t crucial to the tutorial.

 

Overview

  • The drop-downs are dynamically populated from channel:entries tags so if our client adds or deletes products he won’t have to worry about replicating those edits for the drop-downs.
  • While the drop-downs display entry titles, you are really choosing entry_ids.
  • When you click “Compare” a bit of javascript grabs the entry_id’s from the 3 drop-downs, appends them onto the URL and reloads the template.
  • Additional channel:entries loops then see those entry_id’s and use them to retrieve the content for the chosen entry.
  • Each column is actually its own HTML table, floated using CSS to create the side-by-side view.

Main releases/compare Template
Let’s work through the main template (available as a download):

<!doctype html>
<
html>
<
head>
    <
title>Compare Releases</title>
    <
meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <
script type="text/javascript">
        <!-- 
Begin
        site 
"http://localhost:8888/index.php/releases/compare/";
        function 
combineMenus(frmproduct_1product_2product_3{
            with 
(frm{
            str 
product_1.options[product_1.selectedIndex].value;
            
str += product_2.options[product_2.selectedIndex].value;
            
str += product_3.options[product_3.selectedIndex].value;
            
url site str;
            
window.location.href url;
           
}
        }
        
//  End -->
    
</script> 

This is the javascript that assembles the expected page URL including the 3 entry_id’s from the selected products.  If you use this code make sure to change the site= parameter to the URL to your comparison template.

<style type="text/css">
    
table.compare {width:170pxfloatleft;}
    td {text
-alignleftpadding2pxheight28px;}
    td
.label {text-align:rightpadding5px 4px 0px 0px}    
    th {height
80px;
    form
#compare_form {padding: 0px 0px 0px 100px;}
    
select {width167px;}
</style>
</
head

Just some basic CSS mainly to get the result tables to line up by floating.  I went this route because it made exception-handling much easier (what if user selects an option only from the first and third boxes, etc). 

<body>
<
h1>Compare Record Releases</h1>        
<
form name="compare_releases" id="compare_form" method="post" action="http://localhost:8888/index.php/releases/compare/">
    <
input type="button" class="compare_form" value="Compare" onclick="combineMenus(this.form, this.form.product_1, this.form.product_2, this.form.product_3)" />
    <
select name="product_1">
        <
option value="">Choose Release</option>
        
{exp:channel:entries channel="releases"" dynamic="no" disable="trackbacks|categories|member_data|pagination|custom_fields"}
            <option value ="
{entry_id}/" {if segment_3==entry_id}selected="selected"{/if} >{title}</option>
        {/exp:channel:entries}
    </select>    

    <select name="
product_2">
        <option value="">Choose Release</option>
        {exp:channel:entries channel="
releases"" dynamic="no" disable="trackbacks|categories|member_data|pagination|custom_fields"}
            
<option value ="{entry_id}/" {if segment_4==entry_id}selected="selected"{/if} >{title}</option>
        
{/exp:channel:entries}
    
</select>    

    <
select name="product_3">
        <
option value="">Choose Release</option>
        
{exp:channel:entries channel="releases"" dynamic="no" disable="trackbacks|categories|member_data|pagination|custom_fields"}
            <option value ="
{entry_id}/" {if segment_5==entry_id}selected="selected"{/if} >{title}</option>
        {/exp:channel:entries}
    </select>    
</form> 

These are the dynamically-generated drop-downs.  It may or may not make sense to chunk these out into a reusable embedded template or snippet, but since they are pretty simple I just left them this way. All we need are the default fields from the channel so our disable parameter can disable everything else for best performance.

{if segment_3 !="" OR segment_4 !="" OR segment_5 !=""}
    
<table class="compare">
        <
thead><tr><th>&nbsp;</th></tr></thead>
        <
tbody>
            <
tr><td class="label">Title</td></tr>
            <
tr><td class="label"># of Tracks</td></tr>
            
<tr><td class="label">Formats</td></tr>            
        </
tbody>
    </
table>
{/if} 


This conditional displays the comparison table labels if the template has been loaded with entry_id’s showing in the URL.

{if segment_3 !=""}
    {embed
="embeds/comparison_column" the_segment="{segment_3}"}
{
/if}    

{if segment_4 
!=""}
    {embed
="embeds/comparison_column" the_segment="{segment_4}"}
{
/if}    

{if segment_5 
!=""}
    {embed
="embeds/comparison_column" the_segment="{segment_5}"}
{
/if}    
</body>
</
html

These conditionals pull in the embedded template that displays a column.  Since the columns need to be identical and only need to look at a different segment for the right entry_id to pull content for, I created an embedded template and just pass the segment variable as an embed variable.  While the comparison column in this tutorial is simple, the odds are that on a production site it would be much more complex and you might as well only create that table once.

The embeds/comparsion_column Template

{exp:channel:entries weblog="releases" limit="1" entry_id="{embed:the_segment}" disable="trackbacks|categories|member_data|pagination" dynamic="no"}
    
<table class="compare" border="1">
        <
thead>
            <
tr><th><img src="{releases_album_thumb}" title="{title}" alt="{title}" /></th></tr>
        </
thead>
        <
tbody>
            <
tr><td><a href="{url_title_path='releases/detail'}">{title}</a></td></tr>
            <
tr><td>{releases_number_tracks}</td></tr>
            <
tr><td>
                
{releases_formats}
                    {if item
=="MP3"}<img src="{site_url}images/interface/release_itunes.png" alt="MP3" />{/if}
                    {if item
=="CD"}<img src="{site_url}images/interface/release_cd.png" alt="CD" />{/if}
                    {if item
=="LP"}<img src="{site_url}images/interface/release_lp.png" alt="LP" />{/if}
                {
/releases_formats}
            
</td></tr>
        </
tbody>
    </
table>
{/exp:channel:entries} 

Pretty straightforward here, we just use the passed-in variable to determine what URL segment to grab the entry_id from. 

Wrapping Up
So there you have it - with a small bit of javascript together with native ExpressionEngine tools like segment variables, conditionals, embedded templates, and embed variables, you can pretty quickly pull entries from a channel and display them in a side-by-side comparison table for happy users.

Category Navigation

<< Previous Entry   

 

Previous Comments

Picture of Shane

by Shane

Date: Saturday, February 4th, 2012
Comment: #1

This is awesome Mike. Thank you for sharing.

Mike Boyink

by Mike Boyink (Author)

Date: Saturday, February 4th, 2012
Comment: #2

My pleasure!

Picture of Dan

by Dan

Date: Tuesday, February 14th, 2012
Comment: #3

So simple, but so effective. I am only put off by the fact that with 5 entry ID’s in the URL (comparing 5 products), it starts to make the URL look ugly, so may change to use the entry_id instead.

Will also sort the entry ID’s alphabetically to ensure only 1 URL is possible per combination.

Picture of Mel

by Mel

Date: Wednesday, February 29th, 2012
Comment: #4

This is awesome Mike and exactly what I was looking for.  Sometimes it really almost seems impossible to do until you break it down.

Picture of ThydayNeach

by ThydayNeach

Date: Wednesday, May 16th, 2012
Comment: #5

MJ is not a express issue any more than abortion is usually a state problem. If the particular feds forbid the profit and by using MJ, then whatever the people in Hartford do. If a Feds tend to enforce what the law states, the person and seller will not be protected because of the state legislation. Face them, lefties merely don’t wish to demand from them leaders the actual courage to complete the appropriate thing. Kinda like once you would ride the institution bus in the rain & looking at the wipers, waiting so they can sync. My cousin had this kind of tiny minor dog that may refuse to move near everyone except your ex owner. A two years ago, I was sticking to my auntie, and even though three weeks your new puppy would bolt to an alternative room for the sight connected with me. If My partner and i went way too near the girl, she would likely bark to high ecstasy until I went aside. Unfortunately, towards the final of our stay, I was sexually attacked. I go back to my aunt’s property, and proceeded to go into the girl room. I lay down and attempted to shut myself out of the world by way of pulling the duvet around my scalp, but I heard any noise beside the mattress and looked down pet had your ex two entrance paws high on the cargo area, looking on me. I pulled her up and your lover came beneath the duvet by himself and rested her deal with by acquire. When My partner and i sobbed, she licked this tears at a distance. The pet dog undoubtedly made it easier for me by means of that nights, I unquestionably didn’t sense so only. 
<a >vaporizer</a>
What a fantastic walk back in its history! My family members moved to Westport with 1954 and I nevertheless live in your house I went into while i was 9 in the Compo Beach front area. The cannons, Cedar Level (my pops owned and raced a good Atlantic), Longshore, Saugatuck College, Bedford Junior. High, Staples (I still know the words to the alma maters of each!), Miss Comer’s… yes, I don’t forget it properly. becoming a regular at the best food/drink site. its simply just so frigin awesome to check out the employees’ eys illuminate at a new familiar face the face. They telephone you through name along with know your current order, which makes the entire visit an enjoyable breeze. AWESOME!!! LOL, does it resemble a hobbit? Just end up being grateful. If we get yourself a dog, my daughter hopes to name this “Chicken Mc”. (because an example of our neighbours includes a dog referred to as “Nugget” as well as she thinks they could be friends). 
<a >vaporizers</a >

Add Your Comment

Comment on this Post

  

Unless otherwise stated all content is © Michael Boyink of Train-ee.com & Boyink Interactive. Please don't steal - I've got kids to feed...