I searched the OpenCart forums for a long time and didn’t find a solution I was happy with. All the solutions I found involved creating new modules and/or editing source code to include them in the header. Finally, with only a basic knowledge of PHP, I decided to jump in and try and write my own solution, and after a lot of trial and error (and many, many error messages) I got it working and it seems to work without any issues.
I started with the getCategories function from catalog/controller/module/category.php. Here it is:
protected function getCategories($parent_id, $current_path = '') {
$category_id = array_shift($this->path);
$output = '';
$results = $this->model_catalog_category->getCategories($parent_id);
if ($results) {
$output .= '<ul>';
}
foreach ($results as $result) {
if (!$current_path) {
$new_path = $result['category_id'];
} else {
$new_path = $current_path . '_' . $result['category_id'];
}
$output .= '<li>';
$children = '';
if ($category_id == $result['category_id']) {
$children = $this->getCategories($result['category_id'], $new_path);
}
if ($this->category_id == $result['category_id']) {
$output .= '<a href="' . $this->model_tool_seo_url->rewrite(HTTP_SERVER . 'index.php?route=product/category&path=' . $new_path) . '"><b>' . $result['name'] . '</b></a>';
} else {
$output .= '<a href="' . $this->model_tool_seo_url->rewrite(HTTP_SERVER . 'index.php?route=product/category&path=' . $new_path) . '">' . $result['name'] . '</a>';
}
$output .= $children;
$output .= '</li>';
}
if ($results) {
$output .= '</ul>';
}
return $output;
}
I put this in the header template file, header.tpl, and ran it but it threw up a lot of errors. I then went through it bit by bit and stripped it right down. I could detail the whole process but that would be dull. In the end, the code that worked was this:
<?php
$this->load->model('tool/seo_url');
$results = $this->model_catalog_category->getCategories();
if ($results) {$output = '<ul>';}
foreach ($results as $result) {
$output .= '<li>';
$new_path = $result['category_id'];
$unrewritten = HTTP_SERVER.'index.php?route=product/category&path='.$new_path;
$rewritten = $this->model_tool_seo_url->rewrite($unrewritten);
$output .= '<a href="'.str_replace('&', '&', $rewritten).'">'.$result['name'].'</a>';
$output .= '</li>';
}
if ($results) {$output .= '</ul>';}
echo $output;
?>
And that’s all you need. No extra modules or adding code to four or five files. Just put the above code in your header and it will list your top-level categories. It works with both the default URL structure and with the SEO friendly URL option. If you want to create a navigation bar that also displays sub-categories, in drop-downs for example, you’ll probably have to do something different, but I’m happy with this solution. It’s light, doesn’t affect the OpenCart source code, and I’m not a huge fan of drop-downs anyway.