Apr 19, 2015

Ketan Patel

Opencart Custom Module Development : Part 2

custom module development


This tutorial is the second part of my previous tutorial : How to make custom module in opencart 2.x. In previous tutorial we learned how to make the custom module changes for the admin section, in this tutorial we'll see the changes required for the front end side. 

The Structure of Opencart Module


There are mainly six to eight files needs to be created for any module. The following screenshot shows the hierarchy of files and folders of an OpenCart module:




Creating the Front End side


Front End section will have three files:
  • Controller File
  • Language File
  • View File


Create a Controller File 
Path: catalog/controller/module/popular.php

Create a Language File 
Path: catalog/language/english/module/popular.php

Create a View File 
Path: catalog/view/template/module/popular.tpl



Controller File


Below is the complete controller file.


<?php
class ControllerModulePopular extends Controller {
 public function index($setting) {
  $this->load->language('module/popular');
  
  $data['heading_title']   = $this->language->get('heading_title');
  $data['text_tax']        = $this->language->get('text_tax');
  $data['button_cart']     = $this->language->get('button_cart');
  $data['button_wishlist'] = $this->language->get('button_wishlist');
  $data['button_compare']  = $this->language->get('button_compare');
  
  $this->load->model('catalog/product');
  $this->load->model('tool/image');
  
  $data['products'] = array();  
  $product_data     = array();
  
  if(isset($setting['limit']) && $setting['limit']!=''){
     $setting['limit'] = $setting['limit'];
  }
  else{
       $setting['limit'] = 4;
  }
  
  
  $query = $this->db->query("SELECT p.product_id FROM " . DB_PREFIX . "product p LEFT JOIN " . DB_PREFIX . "product_to_store p2s ON (p.product_id = p2s.product_id) WHERE p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "' ORDER BY p.viewed DESC LIMIT " . (int)$setting['limit']);
  
  
  
  foreach ($query->rows as $result) {   
   $product_data[$result['product_id']] = $this->model_catalog_product->getProduct($result['product_id']);
  }
          
  $results = $product_data;
  
  if ($results) {
  foreach ($results as $result) {
   if ($result['image']) {
    $image = $this->model_tool_image->resize($result['image'], $setting['width'], $setting['height']);
   } else {
    $image = $this->model_tool_image->resize('placeholder.png', $setting['width'], $setting['height']);
   }
   
   
   if (($this->config->get('config_customer_price') && $this->customer->isLogged()) || !$this->config->get('config_customer_price')) {
    $price = $this->currency->format($this->tax->calculate($result['price'], $result['tax_class_id'], $this->config->get('config_tax')));
   } else {
    $price = false;
   }
     
   if ((float)$result['special']) {
    $special = $this->currency->format($this->tax->calculate($result['special'], $result['tax_class_id'], $this->config->get('config_tax')));
   } else {
    $special = false;
   } 
   
   if ($this->config->get('config_tax')) {
    $tax = $this->currency->format((float)$result['special'] ? $result['special'] : $result['price']);
   } else {
    $tax = false;
   }
   
   
   if ($this->config->get('config_review_status')) {
    $rating = $result['rating'];
   } else {
    $rating = false;
   }
       
   $data['products'][] = array(
    'product_id'   => $result['product_id'],
    'thumb'        => $image,
    'name'         => $result['name'],
    'description'  => utf8_substr(strip_tags(html_entity_decode($result['description'], ENT_QUOTES, 'UTF-8')), 0, $this->config->get('config_product_description_length')) . '..',
    'price'        => $price,
    'special'      => $special,
    'tax'          => $tax,
    'rating'       => $rating,
    'href'         => $this->url->link('product/product', 'product_id=' . $result['product_id']),
   );
  }

   if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/popular.tpl')) {
    return $this->load->view($this->config->get('config_template') . '/template/module/popular.tpl', $data);
   } else {
   return $this->load->view('default/template/module/popular.tpl', $data);
     }
     }
 }
}


The below line will load the language file of our custom module "Popular Products" so that we can access the language variables defined in the language file.

$this->load->language('module/popular');


Now we are fetching the language variables and setting them in the $data variable so that they can be accessed in the view template files.

$data['heading_title']   = $this->language->get('heading_title');
$data['text_tax']        = $this->language->get('text_tax');
$data['button_cart']     = $this->language->get('button_cart');
$data['button_wishlist'] = $this->language->get('button_wishlist');
$data['button_compare']  = $this->language->get('button_compare');

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

Above lines will load the front end side product model so that we can use all the methods of it. The second one is used to fetch the product image.

if (isset($setting['limit']) && $setting['limit']!='') {
    $setting['limit'] = $setting['limit'];
}
else {
    $setting['limit'] = 4;
}

this is used to set the default limit of the product display. The below query is the heart of this module.

$query = $this->db->query("SELECT p.product_id FROM " . DB_PREFIX . "product p LEFT JOIN " . DB_PREFIX . "product_to_store p2s ON (p.product_id = p2s.product_id) WHERE p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "' ORDER BY p.viewed DESC LIMIT " . (int)$setting['limit']);

Now we are getting the information of all the products fetched from the above query.

foreach ($query->rows as $result) {   
 $product_data[$result['product_id']] = $this->model_catalog_product->getProduct($result['product_id']);
 }
$results = $product_data;



and then after we are loop through the $results array and fetch the product image,price,special price, tax etc data and then we pass all these into product array so that they can be accessible in the view file.

$data['products'][] = array(
  'product_id'   => $result['product_id'],
  'thumb'        => $image,
  'name'         => $result['name'],
  'description'  => utf8_substr(strip_tags(html_entity_decode($result['description'], ENT_QUOTES, 'UTF-8')), 0, $this->config->get('config_product_description_length')) . '..',
  'price'        => $price,
  'special'      => $special,
  'tax'          => $tax,
  'rating'       => $rating,
  'href'         => $this->url->link('product/product', 'product_id=' . $result['product_id']),
 );


At last we are checking the existence of the template file and loading the template file for this custom module.

if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/popular.tpl')) {
 return $this->load->view($this->config->get('config_template') . '/template/module/popular.tpl', $data);
} else {
 return $this->load->view('default/template/module/popular.tpl', $data);
}

Language file


As described, language file will contains the language variables which describes what will be displayed in view file. In language file constant name is used which never changes, only the values according to the language will be changed.

If the current selected language is other than English then the variables will be loaded from that language’s folder file.

<?php
// Heading
$_['heading_title'] = 'Popular Products';

// Text
$_['text_reviews']  = 'Based on %s reviews.';

// Tax
$_['text_tax']      = 'Ex Tax:';

View File


View file refers to the template file having .tpl extension. It will display all the set variables of the controller.in view file we loop through the $products array and display the products.

<h3><?php echo $heading_title; ?></h3>
<div class="row">
  <?php foreach ($products as $product) { ?>
  <div class="col-lg-3 col-md-3 col-sm-6 col-xs-12">
    <div class="product-thumb transition">
      <div class="image"><a href="<?php echo $product['href']; ?>"><img src="<?php echo $product['thumb']; ?>" alt="<?php echo $product['name']; ?>" title="<?php echo $product['name']; ?>" class="img-responsive" /></a></div>
      <div class="caption">
        <h4><a href="<?php echo $product['href']; ?>"><?php echo $product['name']; ?></a></h4>
        <p><?php echo $product['description']; ?></p>
        <?php if ($product['rating']) { ?>
        <div class="rating">
          <?php for ($i = 1; $i <= 5; $i++) { ?>
          <?php if ($product['rating'] < $i) { ?>
          <span class="fa fa-stack"><i class="fa fa-star-o fa-stack-2x"></i></span>
          <?php } else { ?>
          <span class="fa fa-stack"><i class="fa fa-star fa-stack-2x"></i><i class="fa fa-star-o fa-stack-2x"></i></span>
          <?php } ?>
          <?php } ?>
        </div>
        <?php } ?>
        <?php if ($product['price']) { ?>
        <p class="price">
          <?php if (!$product['special']) { ?>
          <?php echo $product['price']; ?>
          <?php } else { ?>
          <span class="price-new"><?php echo $product['special']; ?></span> <span class="price-old"><?php echo $product['price']; ?></span>
          <?php } ?>
          <?php if ($product['tax']) { ?>
          <span class="price-tax"><?php echo $text_tax; ?> <?php echo $product['tax']; ?></span>
          <?php } ?>
        </p>
        <?php } ?>
      </div>
      <div class="button-group">
        <button type="button" onclick="cart.add('<?php echo $product['product_id']; ?>');"><i class="fa fa-shopping-cart"></i> <span class="hidden-xs hidden-sm hidden-md"><?php echo $button_cart; ?></span></button>
        <button type="button" data-toggle="tooltip" title="<?php echo $button_wishlist; ?>" onclick="wishlist.add('<?php echo $product['product_id']; ?>');"><i class="fa fa-heart"></i></button>
        <button type="button" data-toggle="tooltip" title="<?php echo $button_compare; ?>" onclick="compare.add('<?php echo $product['product_id']; ?>');"><i class="fa fa-exchange"></i></button>
      </div>
    </div>
  </div>
  <?php } ?>
</div>



In this part of article, we completed the front end side of our opencart custom module Popular products. It’s easy to modify the OpenCart modules if you know the basic core concepts of MVC.


Download Module

Ketan Patel

About Ketan Patel -

I have developed a wide range of websites using CorePHP, Opencart, CakePHP and CodeIgniter including sites for startup companies and small businesses. Apart from my blogging life, I like to read Novels, Listening music and Net surfing.

Subscribe to this Blog via Email :