Opencart 3 module development tutorial, multi-instance testimonial free

In this opencart tutorial, we are showing you how to create a multi-instance opencart 3 module step by step, we are making a testimonial module as an example, click to download this module for free. In our last two posts, we show you how to make the single instance module: Single Instance module, Form creation, validation, and submission to the database and Single Instance module frontend login module. Check the difference between the single instance and multi-instance opencart module. Similarly, one of our blog posts describes how to perform Opencart CRUD functionalities of testimonials, create an admin custom listing page, form, validate it and save in the database, now we will use those testimonials to show in the multi-instance module in the admin section and in next post we will show you the frontend section code.

Here are the files and folders structure of testimonial module:

  • admin/controller/extension/module/testimonial.php
  • admin/language/en-gb/extension/module/testimonial.php
  • admin/view/template/extension/module/testimonial.twig
  • catalog/controller/extension/module/testimonial.php
  • catalog/model/extension/module/testimonial.php
  • catalog/language/en-gb/extension/module/testimonial.php
  • catalog/view/theme/default/template/extension/module/testimonial.twig

In this post, we will show only admin code, in the next post we will show you the catalog or frontend code.

The code in admin/controller/extension/module/testimonial.php describes the controller code of the multi-instance opencart module. We describe the code in the comment:

<?php
/*** As our file is testimonial.php so Class name is ControllerExtensionModuleTestimonial which extends the Controller base class ***/
class ControllerExtensionModuleTestimonial extends Controller
{
	/*** Declaration of the private property 'error' so that we can get check if any error occurs in the whole class**/
	private $error = array();
	/*** Index method is called automatically or by default, if no parameters are passed, check this video tutorial for details https://www.youtube.com/watch?v=X6bsMmReT-4 . ***/
	public function index()
	{
		/*** Loads the language file admin/language/en-gb/extension/module/testimonial.php by which the varaibles of the language file are accessible in twig file. ***/
		$this->load->language('extension/module/testimonial');
		/*** Set the Document title ***/
		$this->document->setTitle($this->language->get('heading_title'));
		/*** Loads the model admin/model/setting/module.php so that we can use the methods defined there. The difference in single instance and multi-instance is here, in single instance we used to load  $this->load->model('setting/setting'); but here we load setting/module ***/
		$this->load->model('setting/module');
		/*** This is how we check if it is form submitted or not. When we submit the form then this block of code also run. Then it also validate the modify permission and other validation. ***/
		if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
			/*** Look at these lines of code, this code section which distinguishes from Single Instance to Multi-instance. If it is single instance then it will be like 	$this->model_setting_setting->editSetting('***', $this->request->post); This editSetting save the data to  oc_setting database table. But in multi-instance the code is like below it checks if the module_id is set if it is set then it get edit module data by editModule method, but if someone click Add button then no module_id is set and it adds new module data to the module database table. ***/
			if (!isset($this->request->get['module_id'])) {
				$this->model_setting_module->addModule('testimonial', $this->request->post);
			} else {
				$this->model_setting_module->editModule($this->request->get['module_id'], $this->request->post);
			}
			/*** This is to delete the cache of the testimonial. ***/
			$this->cache->delete('testimonial');
			/*** This set the success message in the session. ***/
			$this->session->data['success'] = $this->language->get('text_success');
			/*** This is to redirect to the extensions page. ***/
			$this->response->redirect($this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=module', true));
		}
		/*** This is to check if there are any warnings	 ***/	
		if (isset($this->error['warning'])) {
			$data['error_warning'] = $this->error['warning'];
		} else {
			$data['error_warning'] = '';
		}
		/*** As we are validating 'Module Name' in the validate method so if validate method returns name error then it is assigned here and the error is shown in the form field. ***/
		if (isset($this->error['name'])) {
			$data['error_name'] = $this->error['name'];
		} else {
			$data['error_name'] = '';
		}
		/*** This is also to set the error for the form field width ***/
		if (isset($this->error['width'])) {
			$data['error_width'] = $this->error['width'];
		} else {
			$data['error_width'] = '';
		}
		/*** This is also to set the error for the form field height ***/
		if (isset($this->error['height'])) {
			$data['error_height'] = $this->error['height'];
		} else {
			$data['error_height'] = '';
		}

		/*** Following are for breadcrumbs ***/
		$data['breadcrumbs'] = array();
		$data['breadcrumbs'][] = array(
			'text' => $this->language->get('text_home'),
			'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true)
		);
		$data['breadcrumbs'][] = array(
			'text' => $this->language->get('text_extension'),
			'href' => $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=module', true)
		);
		/*** Check this section of if else statement, we see the difference in single instance and multi-instance. Here it is checking if module_id is set then it has different href URl and if not set different URL. ***/
		if (!isset($this->request->get['module_id'])) {
			$data['breadcrumbs'][] = array(
				'text' => $this->language->get('heading_title'),
				'href' => $this->url->link('extension/module/testimonial', 'user_token=' . $this->session->data['user_token'], true)
			);
		} else {
			$data['breadcrumbs'][] = array(
				'text' => $this->language->get('heading_title'),
				'href' => $this->url->link('extension/module/testimonial', 'user_token=' . $this->session->data['user_token'] . '&module_id=' . $this->request->get['module_id'], true)
			);
		}
		/*** Form action URL as per the module edited or for new module ***/
		if (!isset($this->request->get['module_id'])) {
			$data['action'] = $this->url->link('extension/module/testimonial', 'user_token=' . $this->session->data['user_token'], true);
		} else {
			$data['action'] = $this->url->link('extension/module/testimonial', 'user_token=' . $this->session->data['user_token'] . '&module_id=' . $this->request->get['module_id'], true);
		}
		/*** Form cancel URL ***/
		$data['cancel'] = $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=module', true);
		/*** This is to get the module data, if module_id is set then it gets module data from database and set it to $module_info variable. ***/
		if (isset($this->request->get['module_id']) && ($this->request->server['REQUEST_METHOD'] != 'POST')) {
			$module_info = $this->model_setting_module->getModule($this->request->get['module_id']);
		}
		/*** This will check if it form filled and clicked save button and occurs some errors then it will set the name with POST name value. If it is edit then it will set the name value with the module detail. If it is add then empty is set. ***/
		if (isset($this->request->post['name'])) {
			$data['name'] = $this->request->post['name'];
		} elseif (!empty($module_info)) {
			$data['name'] = $module_info['name'];
		} else {
			$data['name'] = '';
		}
		/*** Same as above this will check if it form filled and clicked save button and occurs some errors then it will set the limit with POST limit value. If it is edit then it will set the limit value with the module detail. If it is add then empty is set. ***/
		if (isset($this->request->post['limit'])) {
			$data['limit'] = $this->request->post['limit'];
		} elseif (!empty($module_info)) {
			$data['limit'] = $module_info['limit'];
		} else {
			$data['limit'] = 5;
		}
		/*** Same as above this will check if it form filled and clicked save button and occurs some errors then it will set the width with POST width value. If it is edit then it will set the width value with the module detail. If it is add then default value is set to 200. ***/
		if (isset($this->request->post['width'])) {
			$data['width'] = $this->request->post['width'];
		} elseif (!empty($module_info)) {
			$data['width'] = $module_info['width'];
		} else {
			$data['width'] = 200;
		}
		/*** Same as above this will check if it form filled and clicked save button and occurs some errors then it will set the height with POST height value. If it is edit then it will set the height value with the module detail. If it is add then default value is set to 200. ***/
		if (isset($this->request->post['height'])) {
			$data['height'] = $this->request->post['height'];
		} elseif (!empty($module_info)) {
			$data['height'] = $module_info['height'];
		} else {
			$data['height'] = 200;
		}
		/*** Same as above this will check if it form filled and clicked save button and occurs some errors then it will set the status with POST status value. If it is edit then it will set the status value with the module detail. If it is add then default value is set to empty. ***/
		if (isset($this->request->post['status'])) {
			$data['status'] = $this->request->post['status'];
		} elseif (!empty($module_info)) {
			$data['status'] = $module_info['status'];
		} else {
			$data['status'] = '';
		}
		/*** This is how we load the header, column left and footer ***/
		$data['header'] = $this->load->controller('common/header');
		$data['column_left'] = $this->load->controller('common/column_left');
		$data['footer'] = $this->load->controller('common/footer');
		/*** This is to set output data variables to the view or twig files and twig file is loaded and html rendering is done with it. ***/
		$this->response->setOutput($this->load->view('extension/module/testimonial', $data));
	}
	/*** This is how validation is done, we check whether the user has permission to modify or not.***/
	/*** Here we validate name, width and height ***/
	/*** If there is error then $this->error['warning'] is set and warning are shown.***/
	protected function validate()
	{
		if (!$this->user->hasPermission('modify', 'extension/module/testimonial')) {
			$this->error['warning'] = $this->language->get('error_permission');
		}
		if ((utf8_strlen($this->request->post['name']) < 3) || (utf8_strlen($this->request->post['name']) > 64)) {
			$this->error['name'] = $this->language->get('error_name');
		}
		if (!$this->request->post['width']) {
			$this->error['width'] = $this->language->get('error_width');
		}
		if (!$this->request->post['height']) {
			$this->error['height'] = $this->language->get('error_height');
		}
		return !$this->error;
	}
}

For language we create testimonail.php file at admin/language/en-gb/extension/module/ and paste the following code. We defined required language variables and assign them the text of that language.

<?php
// Heading
$_['heading_title']    = 'Testimonial';
// Text
$_['text_extension']   = 'Extensions';
$_['text_success']     = 'Success: You have modified Testimonial module!';
$_['text_edit']        = 'Edit Testimonial Module';
// Entry
$_['entry_name']       = 'Module Name';
$_['entry_limit']      = 'Limit';
$_['entry_width']      = 'Width';
$_['entry_height']     = 'Height';
$_['entry_status']     = 'Status';
// Error
$_['error_permission'] = 'Warning: You do not have permission to modify Testimonial module!';
$_['error_name']       = 'Module Name must be between 3 and 64 characters!';
$_['error_width']      = 'Width required!';
$_['error_height']     = 'Height required!';

For the form page, we create testimonial.twig at admin/view/template/extension/module/ and add the following lines of code, they are self-explanatory, let us know in the comment is you didn’t understand anything.

{{ header }}{{ column_left }}
<div id="content">
  <div class="page-header">
    <div class="container-fluid">
      <div class="pull-right">
        <button type="submit" form="form-module" data-toggle="tooltip" title="{{ button_save }}" class="btn btn-primary"><i class="fa fa-save"></i></button>
        <a href="{{ cancel }}" data-toggle="tooltip" title="{{ button_cancel }}" class="btn btn-default"><i class="fa fa-reply"></i></a></div>
      <h1>{{ heading_title }}</h1>
      <ul class="breadcrumb">
        {% for breadcrumb in breadcrumbs %}
        <li><a href="{{ breadcrumb.href }}">{{ breadcrumb.text }}</a></li>
        {% endfor %}
      </ul>
    </div>
  </div>
  <div class="container-fluid">
    {% if error_warning %}
    <div class="alert alert-danger alert-dismissible"><i class="fa fa-exclamation-circle"></i> {{ error_warning }}
      <button type="button" class="close" data-dismiss="alert">×</button>
    </div>
    {% endif %}
    <div class="panel panel-default">
      <div class="panel-heading">
        <h3 class="panel-title"><i class="fa fa-pencil"></i> {{ text_edit }}</h3>
      </div>
      <div class="panel-body">
        <form action="{{ action }}" method="post" enctype="multipart/form-data" id="form-module" class="form-horizontal">
          <div class="form-group">
            <label class="col-sm-2 control-label" for="input-name">{{ entry_name }}</label>
            <div class="col-sm-10">
              <input type="text" name="name" value="{{ name }}" placeholder="{{ entry_name }}" id="input-name" class="form-control" />
              {% if error_name %}
              <div class="text-danger">{{ error_name }}</div>
              {% endif %}
            </div>
          </div>
          <div class="form-group">
            <label class="col-sm-2 control-label" for="input-limit">{{ entry_limit }}</label>
            <div class="col-sm-10">
              <input type="text" name="limit" value="{{ limit }}" placeholder="{{ entry_limit }}" id="input-limit" class="form-control" />
            </div>
          </div>
          <div class="form-group">
            <label class="col-sm-2 control-label" for="input-width">{{ entry_width }}</label>
            <div class="col-sm-10">
              <input type="text" name="width" value="{{ width }}" placeholder="{{ entry_width }}" id="input-width" class="form-control" />
              {% if error_width %}
              <div class="text-danger">{{ error_width }}</div>
              {% endif %}
            </div>
          </div>
          <div class="form-group">
            <label class="col-sm-2 control-label" for="input-height">{{ entry_height }}</label>
            <div class="col-sm-10">
              <input type="text" name="height" value="{{ height }}" placeholder="{{ entry_height }}" id="input-height" class="form-control" />
              {% if error_height %}
              <div class="text-danger">{{ error_height }}</div>
              {% endif %}
            </div>
          </div>
          <div class="form-group">
            <label class="col-sm-2 control-label" for="input-status">{{ entry_status }}</label>
            <div class="col-sm-10">
              <select name="status" id="input-status" class="form-control">
                {% if status %}
                <option value="1" selected="selected">{{ text_enabled }}</option>
                <option value="0">{{ text_disabled }}</option>
                {% else %}
                <option value="1">{{ text_enabled }}</option>
                <option value="0" selected="selected">{{ text_disabled }}</option>
                {% endif %}
              </select>
            </div>
          </div>
        </form>
      </div>
    </div>
  </div>
</div>
{{ footer }}

In our next post, we will create the frontend section of the multi-instance testimonial module and show it in different layouts.

Like this way we create a testimonial module setting form in Opencart admin, validate the form, submit the form data to the database, list out the multiple instances of the module in the module listing page, edit each module and update it, and we can perform the delete from the module listing page, like this we create admin section of the multi-instance module in Opencart.

Hope you liked this post, let us know if you have any questions or suggestions, please subscribe to our YouTube Channel for Opencart video tutorials. You can also find us on Twitter and Facebook. Enjoy!

Previous articleSingle Instance module frontend login module, Opencart 3 documentation
Next articleFree checkout all orders are going to missing orders in Opencart 3.0.2.0
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