How to create a custom page in Opencart 3 – Category listing Part 2

In the previous opencart tutorial, we show a basic way to create a custom page in OpenCart 3. Here we are showing you by creating the categories listing custom page in Opencart 3.0.3.2, we create a controller page, language page, model page for the database, and twig page for the view.

Previously the file and folders structure was like below:

Opencart custom page creation

We will make the changes in the above files and add the model file at model/catalog/categories.php where we will write code for all the database queries. The files and folders hierarchies will become like below:

Opencart custom page

Now let’s start with the language file catalog/language/en-gb/product/categorieslist.php. We will comment most of the line of code and describe what is happening there, you can download all the code below:

Language section

Open /catalog/language/en-gb/product/categorieslist.php

<?php
// Text
$_['title']        = 'All Categories';
$_['meta_title']        = 'All Categories';
$_['meta_description']  = 'All Categories';
$_['meta_keyword']      = 'All Categories';
$_['categories_text']   = 'This is categories list page 2';

In the language file, we set the Text to a variable. For example, $_[‘meta_title’] is a variable and met_title will be accessible in the twig file and we can get the value. Likewise in the controller, we first load the file and then get the values. Here in this file, we define every translatable text that is needed in the view.

Controller section

Now, Open catalog/controller/product/categorieslist.php

<?php
class ControllerProductCategorieslist extends Controller
{
    public function index()
    {
        $this->load->language('product/categorieslist');
        
        $this->document->setTitle($this->language->get('meta_title'));
        $this->document->setDescription($this->language->get('meta_description'));
        $this->document->setKeywords($this->language->get('meta_keyword'));

        $data['breadcrumbs'] = array();
		$data['breadcrumbs'][] = array(
			'text' => $this->language->get('text_home'),
			'href' => $this->url->link('common/home')
        );
        $data['breadcrumbs'][] = array(
			'text' => $this->language->get('title'),
			'href' => $this->url->link('product/categorieslist')
        );
        
        $category_id = 0;
        $data['categories'] = array();
        
        $this->load->model('catalog/category');
        $results = $this->model_catalog_category->getCategories($category_id);

        $this->load->model('tool/image');

        foreach ($results as $result) {
            $categories = $this->imageCategory($result['name'], $result['image'], $result['category_id']);
            $data['categories'][]= $categories;

            $data['subcategories']=$this->model_catalog_category->getCategories($result['category_id']);
            if(!empty($data['subcategories'])){
                foreach($data['subcategories'] as $category){
                    $subcategories = $this->imageCategory($category['name'], $category['image'], $category['category_id']);
                    $data['categories'][]= $subcategories;
                }
            }
        }

        $data['column_left'] = $this->load->controller('common/column_left');
        $data['column_right'] = $this->load->controller('common/column_right');
        $data['content_top'] = $this->load->controller('common/content_top');
        $data['content_bottom'] = $this->load->controller('common/content_bottom');
        $data['footer'] = $this->load->controller('common/footer');
        $data['header'] = $this->load->controller('common/header');

        $this->response->setOutput($this->load->view('product/categorieslist', $data));
    }

Following are the details of the code:

class ControllerProductCategorieslist extends Controller {

While creating the Class name follow the folder structure, as our folder structure is catalog/controller/product/catgorieslist.php so the name of the class is ControllerProductCategorieslist. Do not use – and _. They give Fatal error: Uncaught Error: Class ‘Controllerproductcategorieslist’ not found. Then extends the Opencart base Controller

 public function index() {

Now start creating method, let’s start with the index method, this method is called whenever the main controller ControllerProductCategorieslist is called through route URL. Learn more about OpenCart framework detail and request and response in OpenCart.

$this->load->language('product/categorieslist');

With this line, you can now get the values set in the language file. Here our language file is catalog/language/en-gb/product/categorieslist.php. As the above code in language we set $_[‘meta_title’] =”All Categories”, now we can get that value in controller by $this->language->get(‘meta_title’). In this way, you can get any text set in the language file.

$this->document->setTitle($this->language->get('meta_title'));
$this->document->setDescription($this->language->get('meta_description'));
$this->document->setKeywords($this->language->get('meta_keyword'));

In a document or say webpage you can set and get Title, Description, Keywords, Links, Styles, and Scripts. You can learn more about the Opencart 3 library global objects method in this video. Here you get the text from the language file and set title, description, and keywords of the webpage, these are important for SEO.

$data['breadcrumbs'] = array();
$data['breadcrumbs'][] = array(
    'text' => $this->language->get('text_home'),
    'href' => $this->url->link('common/home')
);
$data['breadcrumbs'][] = array(
    'text' => $this->language->get('title'),
    'href' => $this->url->link('product/categorieslist')
);

This code is set in the breadcrumbs which we will show in the view.

$category_id = 0;
$data['categories'] = array();

We set the category_id to zero to get the top-level categories and assign an empty array to $data[‘categories’].

$this->load->model('catalog/category');
$results = $this->model_catalog_category->getCategories($category_id);

Here we load the catalog/model/catalog/category.php so that we can get access to the method like $this->model_catalog_category->getCategories. You will get the query access and get the query results and assign them in $results.

public function getCategories($parent_id = 0) {
    $query = $this->db->query("SELECT * FROM " . DB_PREFIX . "category c LEFT JOIN " . DB_PREFIX . "category_description cd ON (c.category_id = cd.category_id) LEFT JOIN " . DB_PREFIX . "category_to_store c2s ON (c.category_id = c2s.category_id) WHERE c.parent_id = '" . (int)$parent_id . "' AND cd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND c2s.store_id = '" . (int)$this->config->get('config_store_id') . "'  AND c.status = '1' ORDER BY c.sort_order, LCASE(cd.name)");

    return $query->rows;
}

With this, you can get all the top-level categories.

foreach ($results as $result) {
    if ($result['image']) {
        $image = $this->model_tool_image->resize($result['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_height'));
    } else {
        $image = $this->model_tool_image->resize('placeholder.png', $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_height'));
    }
    $data['categories'][] = array(
        'name' => $result['name'] ,
        'href' => $this->url->link('product/category', 'path=' . $result['category_id']),
        'image' => $image,
    );
}

This will assign all the top-level categories to the $data[‘categories’] array. Now, let’s pull the sub-categories as well. The above code will get modified as:

foreach ($results as $result) {
    if ($result['image']) {
        $image = $this->model_tool_image->resize($result['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_height'));
    } else {
        $image = $this->model_tool_image->resize('placeholder.png', $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_height'));
    }
    $data['categories'][] = array(
        'name' => $result['name'] ,
        'href' => $this->url->link('product/category', 'path=' . $result['category_id']),
        'image' => $image,
    );

    $data['subcategories']=$this->model_catalog_category->getCategories($result['category_id']);
    if(!empty($data['subcategories'])){
        foreach($data['subcategories'] as $category){
            if ($category['image']) {
                $image = $this->model_tool_image->resize($category['image'], $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_height'));
            } else {
                $image = $this->model_tool_image->resize('placeholder.png', $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_height'));
            }
            $data['categories'][] = array(
                'name' => $category['name'] ,
                'href' => $this->url->link('product/category', 'path=' . $category['category_id']),
                'image' => $image,
            );
        }
    }
}

This assigns all the categories in the $data[‘categories’]. But there is repeating code so let’s fix like below:

Let’s define one extra method

 public function imageCategory($name, $category_image, $category_id){
    if ($category_image) {
        $image = $this->model_tool_image->resize($category_image, $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_height'));
    } else {
        $image = $this->model_tool_image->resize('placeholder.png', $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_width'), $this->config->get('theme_' . $this->config->get('config_theme') . '_image_product_height'));
    }
    $categories = array(
        'name' => $name ,
        'href' => $this->url->link('product/category', 'path=' . $category_id),
        'image' => $image,
    );
    return $categories;
}

Then we can change the previous for each code to get all categories like below:

foreach ($results as $result) {
    $categories = $this->imageCategory($result['name'], $result['image'], $result['category_id']);
    $data['categories'][]= $categories;

    $data['subcategories']=$this->model_catalog_category->getCategories($result['category_id']);
    if(!empty($data['subcategories'])){
        foreach($data['subcategories'] as $category){
            $subcategories = $this->imageCategory($category['name'], $category['image'], $category['category_id']);
            $data['categories'][]= $subcategories;
        }
    }
}

This removed the repeated code.

Now we call all the controllers to load the layouts:

$data['column_left'] = $this->load->controller('common/column_left');
$data['column_right'] = $this->load->controller('common/column_right');
$data['content_top'] = $this->load->controller('common/content_top');
$data['content_bottom'] = $this->load->controller('common/content_bottom');
$data['footer'] = $this->load->controller('common/footer');
$data['header'] = $this->load->controller('common/header');

Now, in the end, we set output response to the catalog/view/theme/default/template/product/categorieslist.twig and pass the $data variable so we have access to all data in the twig file.

$this->response->setOutput($this->load->view('product/categorieslist', $data));

Template section

Now let’s work in view part, open catalog/view/theme/default/template/product/categorieslist.twig

{{ header }}
{{ column_left }}
{{ column_right }}
{{ content_top}}
{{ content_bottom }}
{{ footer }} 

This will give you all the layout

{{ header }}
{{ column_left }}
{{ column_right }}
<div class="container">
    <ul class="breadcrumb">
        {% for breadcrumb in breadcrumbs %}
            <li><a href="{{ breadcrumb.href }}">{{ breadcrumb.text }}</a></li>
        {% endfor %}
    </ul>
    <div class="col-sm-12">
        {% for category in categories %}
            <div class="col-sm-4 col-xs-12">
                <div class="col-xs-12 text-center">
                    <a href="{{ category.href }}">
                        <img src="{{ category.image }}" alt="{{ category.name }}" title="{{ category.name }}" class="img-responsive" />
                    </a>
                    <h4><a href="{{ category.href }}">{{ category.name }}</a></h4>
                </div>
            </div>
        {% endfor %}
    </div>
</div>
{{ content_top}}
{{ content_bottom }}
{{ footer }} 

With the above code you will be able to see all the categories listed below:

List out all categories Opencart

You can download the code here:

Let us know if you have any suggestions.

Previous articlePHP Docs – The easiest way for documenting your PHP Projects with PHPDoc
Next articleA/B testing on Opencart with Google optimize for free
Author of three Opencart book. The recent Opencart 4 book is at https://amzn.to/4dOlbOR

LEAVE A REPLY

Please enter your comment!
Please enter your name here