Modifying Shopping Cart: "Sort by Letter" in Categories
In the Interspire Shopping Cart Control Panel, we allow you to break down products and customers by those beginning with a specific letter (A-Z). Today we'll be looking at implementing a modification that allows you to bring this functionality to the front end of your store when viewing a list of products in a particular category. Essentially you'll be able to click a letter in a predefined list and view a listing of all products beginning with that specific letter.
The end result of our modification will be similar to the following:

We'll be diving right in to the Interspire Shopping Cart code to make these modifications, so there's an assumption that you have a small about of technical knowledge of PHP/HTML, but even if you don't have the experience, you should be able to progress.
The first thing to do is make sure you have a backup copy of the files we'll be editing in case anything goes wrong.
Open: includes/classes/class.category.php
Find:
$query = " SELECT p.*, floor(prodratingtotal/prodnumratings) AS prodavgrating, imageisthumb, imagefile, ".GetProdCustomerGroupPriceSQL()." FROM idn_products p INNER JOIN idn_categoryassociations ca ON (p.productid = ca.productid) LEFT JOIN idn_product_images pi ON (p.productid=pi.imageprodid) WHERE ca.categoryid='".(int)$this->GetId()."' AND p.prodvisible='1' AND (imageisthumb=1 OR ISNULL(imageisthumb)) ORDER BY ".$this->GetSortField().", p.prodname ASC ";
Replace it with:
$query = "
SELECT p.*, floor(prodratingtotal/prodnumratings) AS prodavgrating, imageisthumb, imagefile, ".GetProdCustomerGroupPriceSQL()."
FROM idn_products p
INNER JOIN idn_categoryassociations ca ON (p.productid = ca.productid)
LEFT JOIN idn_product_images pi ON (p.productid=pi.imageprodid)
WHERE ca.categoryid='".(int)$this->GetId()."' AND p.prodvisible='1' AND (imageisthumb=1 OR ISNULL(imageisthumb))
";
if(isset($_REQUEST['letter']) && $_REQUEST['letter'] != '') {
$letter = chr(ord($_REQUEST['letter']));
if($_REQUEST['letter'] == '0-9') {
$query .= " AND p.prodname NOT REGEXP('^[a-zA-Z]')";
}
else if(isc_strlen($letter) == 1) {
$query .= " AND p.prodname LIKE '".$GLOBALS['ISC_CLASS_DB']->Quote($letter)."%'";
}
}
$query .= "ORDER BY ".$this->GetSortField().", p.prodname ASC";
Find:
$query = " SELECT COUNT(p.productid) AS numproducts FROM idn_products p INNER JOIN idn_categoryassociations ca ON (p.productid = ca.productid) WHERE ca.categoryid='".(int)$this->GetId()."' and p.prodvisible='1' ";
Replace it with:
$query = "
SELECT COUNT(p.productid) AS numproducts
FROM idn_products p
INNER JOIN idn_categoryassociations ca ON (p.productid = ca.productid)
WHERE ca.categoryid='".(int)$this->GetId()."' and p.prodvisible='1'
";
if(isset($_REQUEST['letter']) && $_REQUEST['letter'] != '') {
$letter = chr(ord($_REQUEST['letter']));
if($_REQUEST['letter'] == '0-9') {
$query .= " AND p.prodname NOT REGEXP('^[a-zA-Z]') ";
}
else if(isc_strlen($letter) == 1) {
$query .= " AND p.prodname LIKE '".$GLOBALS['ISC_CLASS_DB']->Quote($letter)."%' ";
}
}
Now we need to modify a few of the panels that handle the next/previous and sorting options to ensure that the selected letter is also included. We'll also add some code to build our letter list and highlight the active item (fun times).
Open: includes/display/CategoryContent.php
Find:
// Should we hide the comparison button?
if(GetConfig('EnableProductComparisons') == 0 || $GLOBALS['ISC_CLASS_CATEGORY']->GetNumProducts() < 2) {
$GLOBALS['HideCompareItems'] = "none";
}
Under it add:
if($GLOBALS['ISC_CLASS_CATEGORY']->GetNumProducts() == 0 && !isset($_REQUEST['letter'])) {
$GLOBALS['HideLetterList'] = 'display: none';
}
else {
$letters = '0-9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z';
$letters = explode(',', $letters);
$GLOBALS['LetterList'] = '';
if(!isset($_REQUEST['letter'])) {
$GLOBALS['AllActive'] = 'ActiveLetter';
}
$GLOBALS['AllLettersLink'] = CatLink($GLOBALS['CatId'], $GLOBALS['ISC_CLASS_CATEGORY']->GetName(), false);
foreach($letters as $letter) {
$active = '';
if(isset($_REQUEST['letter']) && $_REQUEST['letter'] == $letter) {
$active = 'ActiveLetter';
}
$link = CatLink($GLOBALS['CatId'], $GLOBALS['ISC_CLASS_CATEGORY']->GetName(), false, array(
'letter' => $letter
));
$GLOBALS['LetterList'] .= '<li class="'.$active.'"><a href="'.$link.'">'.isc_html_escape($letter).'</a></li>';
}
}
Find:
$start = max($GLOBALS['ISC_CLASS_CATEGORY']->GetPage()-$num_pages_either_side_of_current,1); $end = min($GLOBALS['ISC_CLASS_CATEGORY']->GetPage()+$num_pages_either_side_of_current, $GLOBALS['ISC_CLASS_CATEGORY']->GetNumPages());
Under it add:
$linkOptions = array(
'sort' => $GLOBALS['ISC_CLASS_CATEGORY']->GetSort()
);
if(isset($_REQUEST['letter']) && (isc_strlen($_REQUEST['letter']) == 1 || $_REQUEST['letter'] == '0-9')) {
$linkOptions['letter'] = $_REQUEST['letter'];
}
Open: includes/display/CategoryContent.php
Find:
$GLOBALS['PageLink'] = CatLink($GLOBALS['CatId'], $GLOBALS['ISC_CLASS_CATEGORY']->GetName(), false, array("page" => $page, "sort" => $GLOBALS['ISC_CLASS_CATEGORY']->GetSort()));
Replace with:
$GLOBALS['PageLink'] = CatLink($GLOBALS['CatId'], $GLOBALS['ISC_CLASS_CATEGORY']->GetName(), false, array_merge($linkOption, array('page' => $page)));
Find:
$GLOBALS['PrevLink'] = CatLink($GLOBALS['CatId'], $GLOBALS['ISC_CLASS_CATEGORY']->GetName(), false, array("page" => $GLOBALS['ISC_CLASS_CATEGORY']->GetPage()-1, "sort" => $GLOBALS['ISC_CLASS_CATEGORY']->GetSort()));
Replace with:
$GLOBALS['PrevLink'] = CatLink($GLOBALS['CatId'], $GLOBALS['ISC_CLASS_CATEGORY']->GetName(), false, array_merge($linkOption, array('page' => $GLOBALS['ISC_CLASS_CATEGORY']->GetPage()-1)));
Find:
$GLOBALS['NextLink'] = CatLink($GLOBALS['CatId'], $GLOBALS['ISC_CLASS_CATEGORY']->GetName(), false, array("page" => $GLOBALS['ISC_CLASS_CATEGORY']->GetPage()+1, "sort" => $GLOBALS['ISC_CLASS_CATEGORY']->GetSort()));
Replace with:
$GLOBALS['NextLink'] = CatLink($GLOBALS['CatId'], $GLOBALS['ISC_CLASS_CATEGORY']->GetName(), false, array_merge($linkOption, array('page' => $GLOBALS['ISC_CLASS_CATEGORY']->GetPage()+1)));
Open: includes/display/CategoryHeading.php
if($GLOBALS['EnableSEOUrls'] == 1) {
$GLOBALS['URL'] = CatLink($GLOBALS['CatId'], $GLOBALS['ISC_CLASS_CATEGORY']->GetName(), false);
}
else {
$GLOBALS['URL'] = $GLOBALS['ShopPath']."/categories.php";
$GLOBALS['HiddenSortField'] = "<input type=\"hidden\" name=\"category\" value=\"".$catPath."\" />";
}</pre>
Replace it with:
<pre name="code" class="php">if($GLOBALS['EnableSEOUrls'] == 1) {
$linkOptions = array();
if(isset($_REQUEST['letter']) && (isc_strlen($_REQUEST['letter']) == 1 || $_REQUEST['letter'] == '0-9')) {
$linkOptions['letter'] = $_REQUEST['letter'];
}
$GLOBALS['URL'] = CatLink($GLOBALS['CatId'], $GLOBALS['ISC_CLASS_CATEGORY']->GetName(), false);
}
else {
$GLOBALS['URL'] = $GLOBALS['ShopPath']."/categories.php";
$GLOBALS['HiddenSortField'] = "<input type=\"hidden\" name=\"category\" value=\"".$catPath."\" />";
if(isset($_REQUEST['letter']) && (isc_strlen($_REQUEST['letter']) == 1 || $_REQUEST['letter'] == '0-9')) {
$GLOBALS['HiddenSortField'] .= "<input type=\"hidden\" name=\"letter\" value=\"".isc_html_escape($_REQUEST['letter'])."\" />";
}
}
That's the end of the modifications we need to make to the PHP to get this all happening. Next up, we'll be implementing the modification in to your store design.
Open: templates/[name of the template you're using]/Panels/CategoryContent.html
Insert the HTML below where you'd like the list to appear:
<ul class="LetterSort" style="%%GLOBAL_HideLetterList%%"> <li class="%%GLOBAL_AllActive%%"><a href="%%GLOBAL_AllLettersLink%%">All</a></li> %%GLOBAL_LetterList%% </ul>
Open: templates/[name of the template you're using]/Styles/styles.css:
Add the following to the bottom of the stylesheet. (Adjust the layout, colours etc so it appears how you'd like it to)
.LetterSort, .LetterSort li {
list-style: none;
margin: 0;
padding: 0;
}
.LetterSort {
border: 1px solid #b9cfda;
background: #dcf0f5;
padding: 4px;
text-align: center;
}
.LetterSort li {
display: inline;
}
.LetterSort a {
padding: 0 3px;
}
.LetterSort li.ActiveLetter a {
font-weight: bold;
text-decoration: none;
}
If you save all of the changes we've made, and upload the new files to your store you should have a listing of the letters A through Z and the 'All' and '0-9' links on the category views. Clicking these letters will show you products beginning with the selected letter.
If there are any questions, or you can't get this to work correctly on your store simply leave a comment.
