Monday, December 19, 2011

Adding new page/layout in opencart 1.5.0.x

I have spent reasonable amount of time on Opencart(Its an open source e-commerce solutions written in PHP that's designed around the MVC) couple of days ago. One thing I would say about OpenCart is that it doesn't have the good documentation.
In this tutorial I want to demonstrate how to add a simple page(non-admin page) view to the many default ones OpenCart comes with. The view I want to add is a simple one. It displays all the categories with some number of products from each category all on one page. That's a view that OpenCart doesn't come with by default.
I will be demonstrating on a default installation of OpenCart 1.5.0. Before you start, make a copy of the default theme, under /catalog/view/theme/default. I'll call it default-backup.
Before start modifying, first understand the Opencart file structure.

Opencart file structure

Here is the default Opencart file structure:
 /opencart
 ---- /admin
 ---- /catalog
 ---- /download
 ---- /image
 ---- /system
 ---- config.php
 ---- index.php
 ---- php.ini
 ---- .htaccess.txt

Since we're only adding a new view, the catalog folder is the only we're concerned with. That folder contains:

 /opencart/catalog
 ---- /controller
 ---- /language
 ---- /model
 ---- /view
 
OpenCart follows an MVC+L design, the L represented by the language folder above. Again, since we're only adding a new layout, we won't be doing anything with the model or language files, so we're only concerned with the controller and view folders.
Catalog Controllers
There are many folders inside /catalog/contollers:
  /opencart/catalog/controllers
 ---- /account
 ---- /affliate
 ---- /checkout
 ---- /common
 ---- /error
 ---- /feed
 ---- /information 
 ---- /module
 ---- /payment
 ---- /product
 ---- /total
All these folders will represents their own functionality. For instance, account contains controller files relevant to customer accounts, checkout contains controller files relevant to the shopping checkout process, and so on.
The product folder contains:
 /opencart/catalog/controllers/product
 ---- category.php
 ---- compare.php
 ---- manufacturer.php
 ---- product.php
 ---- search.php
 ---- special.php
This is the place, we need to add our new controller. I called this as categories.php. Now the view...
Catalog Views
The categories.php controller will retrieve whatever data it requires from the relevant models and send them to the appropriate view. View files are written inside /catalog/view, which looks like:
 /opencart/catalog/view/theme/default_copy/template
 ------------ /account
 ----------- /affiliate
 ----------- /checkout
 ----------- /common
 ----------- /error
 ----------- /information
 ----------- /mail
 ----------- /module
 ----------- /payment
 ----------- /product
 ----------- /total
Except for the mail folder, there is a 1-to-1 correspondence between the folders under /catalog/controller and /catalog/view/theme/default-copy/template. It makes intuitive sense that since we added a new controller under /controller/product, we'll add a corresponding view file under /template/products.
The /template/products folder contains the following template files:
 /template/products
 - category.tpl
 - compare.tpl
 - manufacturer_info.tpl
 - manufacturer_list.tpl
 - product.tpl
 - review.tpl
 - search.tpl
 - special.tpl 
Similar to how we added a categories.php controller, we'll add a new view file here (call it categories.tpl), containing the HTML markup and embedded PHP to display the data categories.php is sending it.
Categories.php controller
Now, we need to write code to get all the categories and some products for each category. Check sample code below:
<?php 
class ControllerProductCategories extends Controller {  
  public function index() { 
    $this->language->load('product/category');
    $this->load->model('catalog/category');
    $this->load->model('catalog/product');
    $this->load->model('tool/image'); 
    $this->data['breadcrumbs'] = array();
    $this->data['breadcrumbs'][] = array(
        'text'      => $this->language->get('text_home'),
        'href'      => $this->url->link('common/home'),
        'separator' => false
    ); 
   
    $categories = $this->model_catalog_category->getCategories(0);
        
    foreach ($categories as $category){
      $products_data = array();
   
      $data = array(
         'filter_category_id' => $category['category_id'], 
         'start'              => 0,
         'limit'              => 3
       );
    
       $product_total = $this->model_catalog_product->getTotalProducts($data); 
       $results = $this->model_catalog_product->getProducts($data);
   
       foreach ($results as $result) {
         if ($result['image']) {
           $image = $this->model_tool_image->resize(
                       $result['image'], 
                       $this->config->get('config_image_product_width'), 
                       $this->config->get('config_image_product_height'));
          } else {
            $image = false;
          }
    
          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 = (int)$result['rating'];
           } else {
             $rating = false;
           }
        
            $products_data[] = array(
                     'product_id'  => $result['product_id'],
                     'thumb'       => $image,
                     'name'        => $result['name'],
                     'href'        => $this->url->link(
                                        'product/product', 
                                        'path=' . $category['category_id'] . '&product_id=' . $result['product_id'])
            );
       }
            
       $this->data['categories'][] = array(
                         'category_id' => $category['category_id'],
                         'name'        => $category['name'] . ' (' . $product_total . ')',
                         'products'    => $products_data,
                         'href'        => $this->url->link('product/category', 'path=' . $category['category_id'])
       );            
    }

     if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/product/categories.tpl')) {
       $this->template = $this->config->get('config_template') . '/template/product/categories.tpl';
     } else {
       $this->template = 'default/template/product/categories.tpl';
     }
   
     $this->children = array(
               'common/column_left',
               'common/column_right',
               'common/content_top',
               'common/content_bottom',
               'common/footer',
               'common/header'
          );
    
  $this->response->setOutput($this->render());
  }
}
?>
categories.tpl
sample code for view
<?php echo $header; ?>
<?php echo $column_left; ?>
<?php echo $column_right; ?>
<div id="content">
  <?php echo $content_top; ?>
  <?php if ($categories) { ?>
      lt;?php foreach ($categories as $category) { ?>
      <h2><?php echo $category['name']; ?></h2>
      <?php $products = $category['products'];
        if ($products) { ?>
          <div class="product-grid">
             <?php foreach ($products as $product) { ?>
               <div>
                 <?php if ($product['thumb']) { ?>
                   <div class="image">
                     <a href="<?php echo $product['href']; ?>">
                       <img src="<?php echo $product['thumb']; ?>" title="<?php echo $product['name']; ?>" alt="<?php echo $product['name']; ?>" />
                     </a>
                   </div>
                 <?php } ?>
                 <div class="name">
                   <a href="<?php echo $product['href']; ?>">
                     <?php echo $product['name']; ?>
                   </a>
                 </div>
               </div>
             <?php } ?>
          </div>
          <a style="float: right; width: 100%; text-align: right; padding-bottom: 20px; margin-top: -10px; margin-right: 40px;" href="<?php echo $category['href']; ?>">view more</a>

        <?php } ?>
      <?php } ?>
  <?php } ?>
  <?php echo $content_bottom; ?>
</div>

<?php echo $footer; ?>
One last thing
Since we've added a new layout to our OpenCart project, we should add it to the database, which keeps a list of layouts, so we can specify modules that we want to display in our layout.
There are two places to add an entry
1. The first is in the table called layout. Notice the last entry in the screenshot below, which represents the new layout.
2. You also need an entry in layout_route, as shown below (the last entry):
Now we need to enable our new layout using OpenCart admin panel.
Thats it!

7 comments:

  1. Thanks to significant, important and Useful information about adding new page layout. It seems to be useful one. I will definitely try it and hope that it will work great for me as well..
    Free Social Bookmarking

    ReplyDelete
  2. I agree that this topic has little to no documentation. I created some simple notes based on using this page for my own needs. Consider including it in your post so we can add to the limited documentation of OpenCart. http://developmentshed.blogspot.com/2012/02/opencart-adding-pages.html

    ReplyDelete
  3. thanks for this tutorial , but if i want to add new model page, so what i have to do..

    ReplyDelete
  4. Thank you for the tutorial. Is there any tutorial about how we could manage the page content from admin?

    ReplyDelete
  5. thanks bro for such agreat help

    ReplyDelete
  6. Wonderful Blogs, Such a great list. Thanks for sharing all these blogs all are very useful to every one.
    opencart development and opencart developer

    ReplyDelete
  7. Thanks for the insight.
    btw there is a typo in the template you posted on line 7 -
    'lt;' should be '<'

    ReplyDelete