The default OpenCart search is rather simple and can only search in the products’ names and descriptions. This limits the user in finding the desired product, which is a bad thing trade-wise. And this is where this article will come in handy, since there is nothing on the internet that even comes close to a tutorial on the subject.

Please note that:

  • at least some knowledge of OpenCart is required tor one to follow the tutorial.
  • all paths and file locations are specified relative to the path where OpenCart has been installed, unless specified otherwise.
  • the version used here is 1.5.1.3
  • PHP and JavaScript are not my primary programming languages, so I apologize for any “ugly” code I might be providing. But then, it works. Please report any problems/issues in the comments area, so I can address them ASAP.
  • a complete working installation is available from BitBucket’s repository at https://bitbucket.org/solidhosting/solid-hosting-opencart-search. All changes are framed by a starting “// CUSTOM SEARCH BEGINS” and a closing “// CUSTOM SEARCH ENDS”

First, we need to determine what new search options need to be implemented. This is a relatively easy task, since the options depend heavily on the types of products being searched. In this case we will implement search functions for the products’ dimensions:

  • Width
  • Height
  • Length

Since all these variables can assume only finite, predetermined values, they can be conveniently represented by the “SELECT” HTML tag. They can take on numerical values only, and the values are pretty much static in time, so we can simply hard code them – say from 1 to 10 (inches/centimeters/what have you).

These properties are already defined for each product, in the “product” table of OpenCart’s database, the “length”, “width” and “height” fields. So there will be no changes to the database.

Now that the search criteria has been determined, we are ready to proceed with the interface changes. Nothing complex here, just three SELECTs, organized in any way you want (or just let the designer make it up). These changes must be made to the Search page, and more precisely – the catalog/view/theme/default/template/product/search.tpl file. The language templates must also be updated, to include some static strings for the interface changes.

To sum up, we need to modify:

  1. the language file(s) to include the static text for the search page’s interface changes.
  2. the search page template
  3. the controller to search in the product dimensions
  4. the model to support this search

Now, let’s delve into the actual changes to the cart.

1. Modifying the language files

a. We’ll start with the changes to the language template, to accommodate for the titles of the search choices:

  • each of the installed languages will have its own folder in the “catalog/language/” one. In this case we will only be modifying the default, English language templates.
  • the file of interest is “product/search.php” under the language folder, in this case – “catalog/language/english/product/search.php”.
  • edit that file and insert the appropriate definitions at the end of the file, before the closing “?>” php tag:

// Custom search

$_[‘text_width’]    = ‘Width:';
$_[‘text_height’]    = ‘Height:';
$_[‘text_length’]    = ‘Length:';

  • save the file and close it, as no further changes will be made to it

b. Then we need to load these custom titles in the controller, so we can use them in the search.tpl template file. The file that needs to be changed is “catalog/controller/product/search.php”:

  • open that file and locate the end of the language strings’ loading, around the 155th line (that’s for version 1.5.1.3).
  • insert these lines in it:

$this->data[‘text_width’] = $this->language->get(‘text_width’);
$this->data[‘text_height’] = $this->language->get(‘text_height’);
$this->data[‘text_length’] = $this->language->get(‘text_length’);

  • save the file but keep it open.

2. Modifying the search page template

We are now ready to implement the changes to the Search page.

a. The interface will be kept as simple as possible, its design will be omitted for clarity. Only values between 1 (one) and 10 (ten) will be used. The three SELECT dropdown menus will be displayed horizontally, in one line, between the “Search in product descriptions” checkbox and the “Search” button:

  • open the aforementioned “catalog/view/theme/default/template/product/search.tpl” file
  • locate the end of the <div> that contains the search box, categories and the “Search in product description” checkbox, which is just after the lines

<label for=”description”><?php echo $entry_description; ?></label>
</div>

  • insert a new td and a div:

<td>
<div id=”extended_search” style=”display: block;”>
<table>
<tr>
<td>
<div><?php echo $text_length; ?></div>
<select name=”length” id=”length”>
<option value=”–“>–</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>
<option value=”6″>6</option>
<option value=”7″>7</option>
<option value=”8″ >8</option>
<option value=”9″>9</option>
<option value=”10″>10</option>
</select>
</td>
<td>
<div><?php echo $text_width; ?></div>
<select name=”width” id=”width”>
<option value=”–” >–</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>
<option value=”6″>6</option>
<option value=”7″>7</option>
<option value=”8″ >8</option>
<option value=”9″>9</option>
<option value=”10″>10</option>
</select>
</td>
<td>
<div><?php echo $text_height; ?></div>
<select name=”height” id=”height”>
<option value=”–” >–</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>
<option value=”6″>6</option>
<option value=”7″>7</option>
<option value=”8″ >8</option>
<option value=”9″>9</option>
<option value=”10″>10</option>
</select>
</td>
</tr>
</table>
</div>
</td>

  • finally, save the file (but keep it open) and load the search page – http://www.example.com/OPENCARTFOLDER/index.php?route=product/search – to test the changes. Remember to replace example.com and OPENCARTFOLDER with your domain name and OpenCart’s installation folder, respectively.

b. Now we must incorporate the new parameters in the search procedure. We need to change the JavaScript function at the end of the search template to include the new parameters – if selected – in the URL, as GET parameters:

  • return to the “catalog/view/theme/default/template/product/search.tpl” file
  • insert these lines just before the last line in the “#button-search” function:

var filter_width = $(‘#content select[name=\’width\’]’).attr(‘value’);

if (filter_width!=’–‘) {
url += ‘&width=’ + encodeURIComponent(filter_width);
}

var filter_height = $(‘#content select[name=\’height\’]’).attr(‘value’);

if (filter_height!=’–‘) {
url += ‘&height=’ + encodeURIComponent(filter_height);
}

var filter_length = $(‘#content select[name=\’length\’]’).attr(‘value’);

if (filter_length!=’–‘) {
url += ‘&length=’ + encodeURIComponent(filter_length);
}

  • save and again test the changes by reloading the search page and choosing a value in one (or more) of the new SELECTs. Hit the “Search” button and the selected option(s) should appear in the URL.

c. Let’s reflect the selected values by marking the appropriate options in the SELECTs as “selected”. The way to do this is as follows:

  1. examine the GET parameters in the search controller to see whether any of the dimensions have been specified and if yes, create the appropriate PHP variables and initialize them
  2. check the dimension variables in the search template and if set, mark the appropriate options in the SELECT dropdowns as “selected”

Point 1. is easily achieved:

  • open the search controller file, catalog/controller/product/search.php, and locate the initialization of the “breadcrumbs” array, around line 74:

$this->data[‘breadcrumbs’] = array();

  • and insert these lines just before it:

if (isset($this->request->get[‘length’])) {
$this->data[‘length’] = $this->request->get[‘length’];
} else {
$this->data[‘length’] = ”;
}

if (isset($this->request->get[‘width’])) {
$this->data[‘width’] = $this->request->get[‘width’];
} else {
$this->data[‘width’] = ”;
}

if (isset($this->request->get[‘height’])) {
$this->data[‘height’] = $this->request->get[‘height’];
} else {
$this->data[‘height’] = ”;
}

  • (some housekeeping here) scroll down to the next assignment of the $this->data[‘breadcrumbs’][] variable (around line 138):

$this->data[‘breadcrumbs’][] = array( …

  • and insert these lines just above it:

if (isset($this->request->get[‘length’])) {
$url .= ‘&length=’ . $this->request->get[‘length’];
}

if (isset($this->request->get[‘width’])) {
$url .= ‘&width=’ . $this->request->get[‘width’];
}

if (isset($this->request->get[‘height’])) {
$url .= ‘&height=’ . $this->request->get[‘height’];
}

  • save the file, still keeping it open, and move on to the search template.

Point 2. Now we will have $length, $width and $height as variables in the search template, either set to the previously selected values, or empty, if no selection has been made. We have two ways to set the appropriate options in the SELECT elements as “selected” – JavaScript and PHP code. Both will be discussed here, starting with PHP:

  • just test whether the value of the option matches the variable, as in:

<select name=”length” id=”length”>
<option value=”–“>–</option>
<option value=”1″ <?php if ($length == 1) echo “selected=\”selected\””; ?>>1</option>
<option value=”2″ <?php if ($length == 2) echo “selected=\”selected\””; ?>>2</option>
<option value=”3″ <?php if ($length == 3) echo “selected=\”selected\””; ?>>3</option>

  • or use a for(…) loop from 1 to 10 (inclusive), to print the value of each option, eventually set the “selected” attribute, and print the text of the option, like the categories loops above.

I like the JavaScript way of changing the SELECTs better – just check whether any of the variables are set, and print the appropriate JavaScript to change the SELECT selected option:

  • insert these lines at the very end of the search.tpl file:

<?php
if ($height || $width || $length) { ?>

<script type=”text/javascript”>
<!–

function SetSelectOption(id, opt) {
var selectmenu=document.getElementById(id);
for( i = 0; i < selectmenu.length; i++ ) {
if (selectmenu.options[i].value == opt) {
selectmenu.options[i].selected = true;
return;
}
}
}

<?php
if ($length) {
?>
SetSelectOption(“length”, <?php echo $length ?>);
<?php
}
if ($width) {
?>
SetSelectOption(“width”, <?php echo $width ?>);
<?php
}
if ($height) {
?>
SetSelectOption(“height”, <?php echo $height ?>);
<?php
}
?>

//–>
</script>

<?php
}
?>

and it works like a charm. This is the last change you need to make in the Search template, so you can close search.tpl.

3. Modifying the controller to search in the product dimensions

a. For the sake of completeness and compliance, we have to alter the Search controller to add the variables to the Sort and Show page modifiers. See the problem by searching for “samsung” in the Search textbox, in “All Categories”, checking the “Search in product descriptions” checkbox, and setting random values for the dimensions’ parameters. All will be fine until you sort the search results by any criteria other than “Default” – then the dimension parameters disappear. The same goes for the “results per page” limit, set via the “Show” dropdown. The changes are similar to the housekeeping changes before the $this->data[‘breadcrumbs’] variable above, so they will be omitted here – examine the modified files to see the changes, if you wish. The changes must be made to the “catalog/controller/product/search.php” file, before the initialization of both the “$this->data[‘sorts’]” array (on line 319 at this point of coding) and the “$this->data[‘limits’]” array (on line 417 at this moment). The same goes for the pagination, which is just below the “$this->data[‘limits’]” populating.

b. The last thing we have to do is check the products’ dimensions against the newly introduced parameters, if set. An important decision has to be made here – whether the newly introduced search parameters will be restrictive, or if they could be enhancing. In other words, whether the search results by keyword will be further restricted by the specified dimension(s), or one could search by only the dimensions, without a keyword. The second option will require more modifications, and is more complex. Only the first option will be covered in detail here, and instructions on how to implement the second one will be provided along the way.

c. The Search controller (catalog/controller/product/search.php) places all search criteria in a named array, that is passed to the Catalog Product model search functions getTotalProducts(…) and getProducts(…). This is executed only if the “filter_name” or the “filter_tag” parameters have been set (that is, if a keyword has been entered in the search field). If one needs to implement the second option then s/he will need to modify the condition of the search to be true even if only one of the dimensions parameters has been set, i.e. the line

if (isset($this->request->get[‘filter_name’]) || isset($this->request->get[‘filter_tag’])) {

becomes something like:

if (isset($this->request->get[‘filter_name’]) || isset($this->request->get[‘filter_tag’]) || isset($this->request->get[‘height’]) || isset($this->request->get[‘width’]) || isset($this->request->get[‘length’])) {

d. Regardless of whether you make that change or not, we need to include the dimensions in the data array. Make the following changes to the controller file just after the aforementioned condition, inserting them before the closing bracket of the $data initialization (the entire $data initialization is shown here, the new code lines are the last three, and don’t forget the comma after the $limit variable):

$data = array(
‘filter_name’         => $filter_name,
‘filter_tag’          => $filter_tag,
‘filter_description’  => $filter_description,
‘filter_category_id’  => $filter_category_id,
‘filter_sub_category’ => $filter_sub_category,
‘sort’                => $sort,
‘order’               => $order,
‘start’               => ($page – 1) * $limit,
‘limit’               => $limit,
‘height’              => isset($this->request->get[‘height’]) ? $this->request->get[‘height’] : ”,
‘width’               => isset($this->request->get[‘width’]) ? $this->request->get[‘width’] : ”,
‘length’              => isset($this->request->get[‘length’]) ? $this->request->get[‘length’] : ”
);

These are the last modifications that will be made to the Search controller, so close the catalog/controller/product/search.php file and move to the model changes.

4. Modifying the model to support this search

The Catalog Product model class is located in the catalog/model/catalog/product.php file.

a. We will first change the getTotalProducts(…) function. Locate it near the bottom of the file, around line 480, and find the actual execution of the constructed query near its end:

  • $query = $this->db->query($sql);

Insert the amendment to the SQL statement just above it:

if (!empty($data[‘length’])) {
$sql .= ” AND p.length = ‘” . (int)$data[‘length’] . “‘”;
}

if (!empty($data[‘width’])) {
$sql .= ” AND p.width = ‘” . (int)$data[‘width’] . “‘”;
}

if (!empty($data[‘height’])) {
$sql .= ” AND p.height = ‘” . (int)$data[‘height’] . “‘”;
}

This alteration works in both options, mentioned above – the restricting and enhancing ones. If you wish to truly go for the restrictive one only (option one) then place the alteration in the

if (!empty($data[‘filter_name’]) || !empty($data[‘filter_tag’])) {

clause.

b. Then:

  • locate the getProducts(…) function – near the top of the file – and find the GROUP BY addition, i.e. this line:

$sql .= ” GROUP BY p.product_id”;

  • insert the SQL modification just above it:

if (!empty($data[‘length’])) {
$sql .= ” AND p.length = ‘” . $data[‘length’] . “‘”;
}

if (!empty($data[‘width’])) {
$sql .= ” AND p.width = ‘” . $data[‘width’] . “‘”;
}

if (!empty($data[‘height’])) {
$sql .= ” AND p.height = ‘” . $data[‘height’] . “‘”;
}

  • save the file and set out for testing.

All you have to do now is access the admin interface and set the dimensions for several products, then test the search with entering a keyword and a dimension or two.

Now, notice that the dimensions are not shown when you access a product’s description, and we must show them if we can search by them. But that is the topic of another article, which will be coming soon.

Enjoy!