Building your first Opencart 3 extension

Justinas Beinorius
Apr 16, 2018 · 5 min read
“Age Restriction” module will protect our website from under-aged audience.

Built on Version (tested and works with and


Some pages should be accessed by adults only. (Imagine online Tobacco shop or Casino).


We’ll engineer an OC3 extension that prompts user confirm his/her age and store answer inside a cookie. In the end we’ll have multiple pages protected by multiple independently configurable age filters.

Extensions are of various types. Because we want front-end functionality our extension will be of type module and reside inside admin/controller/extension/module directory.

Module type extensions can be used inside Design Layouts (see video).

Age Restriction v2.0 demo

We’ll use Bootstrap modals and jQuery (because they are part of Opencart toolbox) to display messages and employ OC3 native extension system to manage our data.

A working version of our extension can be downloaded here: (choose master branch) and follow instructions in

There are 7 files we need to consider here.

Structure of our extension.

We’ll start by creating an empty admin controller inside admin/controller/extension/module/age_restriction.php


Every extension needs a language file with at least 1 item. Create an empty file admin/language/en-gb/extension/module/age_restriction.php


If you visit extension manager and select Modules you’ll see our extension already listed there.

Now if you clicked a green button it will install module and also call install method of our controller class. Let’s make use of this click by initializing some primary data.

public function install() {
$this->model_setting_setting->editSetting('module_age_restriction', ['module_age_restriction_status'=>1]);

Install extension and refresh extension page. Notice it’s status changed to Enabled. Here is how (behind the scenes) system checks if extension is enabled or not.

$this->config->get(‘module_’ . $extension . ‘_status’)

Before leaving we’ll cleanup with uninstall. It's also called automatically by system.

public function uninstall() {

First time index method is called when Administrator clicks blue edit button. It has no module_id and so we’ll interpret this as signal to create new module. We’ll introduce two new methods here (addModule and editModule). They will improve code readability.

public function index() {  
if (!isset($this->request->get['module_id'])) {
$module_id = $this->addModule(); $this->response->redirect($this->url->link('extension/module/age_restriction','&user_token='.$this->session->data['user_token'].'&module_id='.$this->db->getLastId()));
} else {

Good thing modules are deleted automatically on extension removal and we don’t need to do that manually. Now our controller has more muscle.


Let’s test this! Click edit button. We get an error: Fatal error: Uncaught Twig_Error_Loader: Unable to find template “extension/module/age_restriction.twig”

Let’s create our view quickly.

Add these 3 lines to editModule method after declaration of $data and before declaration of $htmlOutput.

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

Now if you refresh you’ll see a page saying “It works!”.

Extension view in action.

It works, but does not do much. Let’s send it more data! (we’re working on editModule).

$this->load->model('setting/module');$module_setting = $this->model_setting_module->getModule($module_id);$data['name'] = $module_setting['name'];
$data['message'] = $module_setting['message'];
$data['age'] = $module_setting['age'];
$data['redirect_url'] = $module_setting['redirect_url'];
$data['status'] = $module_setting['status'];

And we have also forgotten to set a page title.


We’ll need more entries inside our language to display input form errors and placeholders and labels and buttons. So just overwrite admin/language/en-gb/extension/module/age_restriction.php with this.

Now let’s get back to view and remove Twig template comment literals {# and #}. Refresh page.

We’re improving.

If you don’t see result immediately probably your cache is enabled. Clear or disable by clicking gear icon inside Dashboard.

Disable or clear cache to see improvements. Click gear icon.

Let’s complicate things a little by updating our view file with more advanced form.

Refresh. Do you see a form? To handle it’s request we’ll again update editModule and add logic to validate method. Here we collect warnings also.

Final back-end controller.


Refresh, mark module enabled and save.

We’re done with back-end. 😂

4 more files…

Create empty controller catalog/controller/extension/module/age_restriction.php It’s index method will be called once we setup our module. $setting will have all data of our configuration.

Let’s add a view by creating an empty file inside catalog/view/theme/default/template/extension/module/ named age_restriction.twig.

Copy this to age_restriction.twig

<script type="text/javascript">console.log('Hello world');</script>

Let’s go back and add our module to HOME Layout like shown in video.

OC Layout System

If you refreshed homepage and open Developer Console by pressing F12 you’ll see message “Hello world”. It’s shown two times. Why I don’t know.

Let’s send our view more data and check if module is actually Enabled or not.

Let’s grab data passed and send it to Developer Console. Update view.

<script type="text/javascript">console.log("{{ message }}", "{{ age }}", "{{ redirect_url }}");</script>

Now we see something more important.

Showing real data.

Because we’re already getting data we can make some decisions. I want to show user a message asking to confirm his/her age. If user confirms we’ll initiate AJAX call and set a cookie with user age.

We’re changing age_restriction.twig to reflect our ideas. Final version.

Changing controller to reflect our intentions.

We’re using additional view to respond to AJAX requests. Create new file named age_restriction_session.twig inside catalog/view/theme/default/template/extension/module/ directory.

{% if success %}
{ "success": "1", "error": "0"}
{% else %}
{ "error": "1", "success": "0"}
{% endif %}

And last, but not least — language file. Save it to catalog/language/extension/module/age_restriction.php

<?php$_['modal_title'] = 'Attention';$_['modal_agree'] = 'Yes';
$_['modal_disagree'] = 'No';

Problem solved!

“Age Restriction” module in action.

If you have any questions leave a comment.

Justinas Beinorius

Written by

Full-Stack web developer

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade