Create a shipping extension in Opencart v4

In our previous blog post, we explored the process of creating a module in Opencart version 4. Now, we will learn to create a shipping extension in Opencart version 4. Shipping plays a vital role in the e-commerce website.

Gaining a comprehensive understanding of the shipping extension is crucial to fully grasp this aspect within the context of Opencart.

To begin, it is essential to familiarize ourselves with the folder structure of an extension.

Folder structure

Shipping extension backend code

Finally, we have our folder structure in place, let’s start creating an extension, we will show ”Webkul Shipping Rates” on the product checkout page.

Searching for an experienced
Opencart Company ?
Read More


admin/controller/shipping/example_shipping.php

<?php
/**
 * Extension name: Webkul Shipping
 * Descrption: Using this extension we will show shipping charges on the checkout page.
 * Author: Webkul Software Pvt. Ltd. 
 * 
 */
namespace OpencartAdminControllerExtensionExampleShippingShipping;

class ExampleShipping extends OpencartSystemEngineController {
	
	/**
	 * index
	 *
	 * @return void
	 */
	public function index(): void {
		
		$this->load->language('extension/example_shipping/shipping/example_shipping');

		$this->document->setTitle($this->language->get('heading_title'));

		$data['breadcrumbs'] = [];

		$data['breadcrumbs'][] = [
			'text' => $this->language->get('text_home'),
			'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'])
		];

		$data['breadcrumbs'][] = [
			'text' => $this->language->get('text_extension'),
			'href' => $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=shipping')
		];

		if (!isset($this->request->get['module_id'])) {
			$data['breadcrumbs'][] = [
				'text' => $this->language->get('heading_title'),
				'href' => $this->url->link('extension/example_shipping/shipping/example_shipping', 'user_token=' . $this->session->data['user_token'])
			];
		} else {
			$data['breadcrumbs'][] = [
				'text' => $this->language->get('heading_title'),
				'href' => $this->url->link('extension/example_shipping/shipping/example_shipping', 'user_token=' . $this->session->data['user_token'] . '&module_id=' . $this->request->get['module_id'])
			];
		}

		$data['save'] = $this->url->link('extension/example_shipping/shipping/example_shipping.save', 'user_token=' . $this->session->data['user_token']);
		$data['back'] = $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=shipping');

        // getting configuration from config
		$data['shipping_example_shipping_cost'] = $this->config->get('shipping_example_shipping_cost');
		$data['shipping_example_shipping_tax_class_id'] = $this->config->get('shipping_example_shipping_tax_class_id');

        // loading tax_class model
		$this->load->model('localisation/tax_class');

        // getting all tax classes
		$data['tax_classes'] = $this->model_localisation_tax_class->getTaxClasses();

		$data['shipping_example_shipping_geo_zone_id'] = $this->config->get('shipping_example_shipping_geo_zone_id');

        // loading geo_zone model
		$this->load->model('localisation/geo_zone');

        // getting all geo zones
		$data['geo_zones'] = $this->model_localisation_geo_zone->getGeoZones();

		$data['shipping_example_shipping_status'] = $this->config->get('shipping_example_shipping_status');
		$data['shipping_example_shipping_sort_order'] = $this->config->get('shipping_example_shipping_sort_order');

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

		$this->response->setOutput($this->load->view('extension/example_shipping/shipping/example_shipping', $data));
	}
	
	/**
	 * save method
	 *
	 * @return void
	 */
	public function save(): void {
        // loading example shipping language
		$this->load->language('extension/example_shipping/shipping/example_shipping');

		$json = [];

        // checking file modification permission
		if (!$this->user->hasPermission('modify', 'extension/example_shipping/shipping/example_shipping')) {
			$json['error']['warning'] = $this->language->get('error_permission');
		}

		if (!$json) {
			$this->load->model('setting/setting');

			$this->model_setting_setting->editSetting('shipping_example_shipping', $this->request->post);

			$json['success'] = $this->language->get('text_success');
		}

		$this->response->addHeader('Content-Type: application/json');
		$this->response->setOutput(json_encode($json));
	}

}

admin/language/en-gb/shipping/example_shipping.php

<?php
/**
 * Webkul Software
 * 
 * @category Webkul
 * @package Opencart Shipping Tutorial
 * @author [Webkul] <[<http://webkul.com/>]>
 * @copyright Copyright (c) Webkul Software Private Limited (https://webkul.com)
 * @license https://store.webkul.com/license.html
 */
// Heading
$_['heading_title']    = 'Webkul Shipping';

// Text
$_['text_shipping']    = 'Shipping';
$_['text_success']     = 'Success: You have modified Webkul Shipping!';
$_['text_edit']        = 'Edit Webkul Shipping';

// Entry
$_['entry_tax_class']  = 'Tax Class';
$_['entry_geo_zone']   = 'Geo Zone';
$_['entry_status']     = 'Status';
$_['entry_sort_order'] = 'Sort Order';
$_['entry_cost']       = 'Shipping Cost';

// Error
$_['error_permission'] = 'Warning: You do not have permission to modify Webkul Shipping!';

admin/view/template/shipping/example_shipping.twig

{{ header }}{{ column_left }}
<div id="content">
	<div class="page-header">
		<div class="container-fluid">
			<div class="float-end">
				<button type="submit" form="form-shipping" data-bs-toggle="tooltip" title="{{ button_save }}" class="btn btn-primary">
					<i class="fa-solid fa-save"></i>
				</button>
				<a href="{{ back }}" data-bs-toggle="tooltip" title="{{ button_back }}" class="btn btn-light">
					<i class="fa-solid fa-reply"></i>
				</a>
			</div>
			<h1>{{ heading_title }}</h1>
			<ol class="breadcrumb">
				{% for breadcrumb in breadcrumbs %}
					<li class="breadcrumb-item">
						<a href="{{ breadcrumb.href }}">{{ breadcrumb.text }}</a>
					</li>
				{% endfor %}
			</ol>
		</div>
	</div>
	<div class="container-fluid">
		<div class="card">
			<div class="card-header">
				<i class="fa-solid fa-pencil"></i>
				{{ text_edit }}</div>
			<div class="card-body">
				<form id="form-shipping" action="{{ save }}" method="post" data-oc-toggle="ajax">
					<div class="row mb-3">
						<label for="input-cost" class="col-sm-2 col-form-label">{{ entry_cost }}</label>
						<div class="col-sm-10">
							<input type="text" name="shipping_example_shipping_cost" value="{{ shipping_example_shipping_cost }}" placeholder="{{ entry_cost }}" id="input-cost" class="form-control"/>
						</div>
					</div>
					<div class="row mb-3">
						<label for="input-tax-class" class="col-sm-2 col-form-label">{{ entry_tax_class }}</label>
						<div class="col-sm-10">
							<select name="shipping_example_shipping_tax_class_id" id="input-tax-class" class="form-select">
								<option value="0">{{ text_none }}</option>
								{% for tax_class in tax_classes %}
									<option value="{{ tax_class.tax_class_id }}" {% if tax_class.tax_class_id == shipping_example_shipping_tax_class_id %} selected {% endif %}>{{ tax_class.title }}</option>
								{% endfor %}
							</select>
						</div>
					</div>
					<div class="row mb-3">
						<label for="input-geo-zone" class="col-sm-2 col-form-label">{{ entry_geo_zone }}</label>
						<div class="col-sm-10">
							<select name="shipping_example_shipping_geo_zone_id" id="input-geo-zone" class="form-select">
								<option value="0">{{ text_all_zones }}</option>
								{% for geo_zone in geo_zones %}
									<option value="{{ geo_zone.geo_zone_id }}" {% if geo_zone.geo_zone_id == shipping_example_shipping_geo_zone_id %} selected {% endif %}>{{ geo_zone.name }}</option>
								{% endfor %}
							</select>
						</div>
					</div>
					<div class="row mb-3">
						<label for="input-status" class="col-sm-2 col-form-label">{{ entry_status }}</label>
						<div class="col-sm-10">
							<div class="form-check form-switch form-switch-lg">
								<input type="hidden" name="shipping_example_shipping_status" value="0"/>
								<input type="checkbox" name="shipping_example_shipping_status" value="1" id="input-status" class="form-check-input" {% if shipping_example_shipping_status %} checked {% endif %}/>
							</div>
						</div>
					</div>
					<div class="row mb-3">
						<label for="input-sort-order" class="col-sm-2 col-form-label">{{ entry_sort_order }}</label>
						<div class="col-sm-10">
							<input type="text" name="shipping_example_shipping_sort_order" value="{{ shipping_example_shipping_sort_order }}" placeholder="{{ entry_sort_order }}" id="input-sort-order" class="form-control"/>
						</div>
					</div>
				</form>
			</div>
		</div>
	</div>
</div>
{{ footer }}

Now, let’s initiate the development of the frontend code to display the shipping rates on the checkout page.

Frontend code

catalog/model/shipping/example_shipping.php

<?php
/**
 * Extension name: Webkul Shipping
 * Descrption: Using this extension we will show shipping charges on the checkout page.
 * Author: Webkul Software Pvt. Ltd. 
 * 
 */
namespace OpencartCatalogModelExtensionExampleShippingShipping;

class ExampleShipping extends OpencartSystemEngineModel {
    	
	/**
	 * getQuote
	 *
	 * @param  array $address
	 * @return array
	 */
	function getQuote(array $address): array {
		$this->load->language('extension/example_shipping/shipping/example_shipping');
		
        // getting geozone lists
		$query = $this->_getGeoZone($address);

		if (!$this->config->get('shipping_example_shipping_geo_zone_id')) {
			$status = true;
		} elseif ($query->num_rows) {
			$status = true;
		} else {
			$status = false;
		}

		$method_data = [];

		if ($status) {
			$quote_data = [];

            // shipping data
			$quote_data['example_shipping'] = [
				'code'         => 'example_shipping.example_shipping',
				'name'         => $this->language->get('text_description'),
				'cost'         => $this->config->get('shipping_example_shipping_cost'),
				'tax_class_id' => $this->config->get('shipping_example_shipping_tax_class_id'),
				'text'         => $this->currency->format($this->tax->calculate($this->config->get('shipping_example_shipping_cost'), $this->config->get('shipping_example_shipping_tax_class_id'), $this->config->get('config_tax')), $this->session->data['currency'])
			];

            // shipping charges array data
			$method_data = [
				'code'       => 'example_shipping',
				'name'       => $this->language->get('heading_title'),
				'quote'      => $quote_data,
				'sort_order' => $this->config->get('shipping_example_shipping_sort_order'),
				'error'      => false
			];
		}

        // return shipping data
		return $method_data;
	}
    
    /**
     * _getGeoZone
     *
     * @param  array $address
     * @return array
     */
    protected function _getGeoZone($address = array()) {

        return $this->db->query("
            SELECT * FROM `" . DB_PREFIX . "zone_to_geo_zone`
                WHERE `geo_zone_id` = '" . (int)$this->config->get('shipping_example_shipping_geo_zone_id') . "'
                    AND `country_id` = '" . (int)$address['country_id'] . "'
                    AND (`zone_id` = '" . (int)$address['zone_id'] . "'
                    OR `zone_id` = '0')"
        );
    }
}

catalog/language/en-gb/shipping/example_shipping.php

<?php
/**
 * Webkul Software
 * 
 * @category Webkul
 * @package Opencart Shipping Tutorial
 * @author [Webkul] <[<http://webkul.com/>]>
 * @copyright Copyright (c) Webkul Software Private Limited (https://webkul.com)
 * @license https://store.webkul.com/license.html
 */

// Heading
$_['heading_title']    = 'Webkul Shipping Rate';

// Text
$_['text_description'] = 'Webkul Shipping Rate';

Once you have created the extension, you will need to include some information within the module’s “install.json” file. This file supports the following keys: name, version, author, and link.

{
  "name": "Webkul Shipping Extension",
  "version": "1.0",
  "author": "Webkul Software Pvt. Ltd.",
  "link": "https://www.webkul.com",
  "instruction": ""
}

Once install.json is inside the directory, you can zip it and name it that ends with .ocmod.zip, then uploads it from the Opencart extension installer.

extension-installer

Upon successful installation of the extension, you can locate it by navigating to “Extensions > Extensions > Shipping” where it will be listed for further configuration and customization.

webkul-Extensions
shipping-configurtaion

Once the configuration is complete, the “Webkul Shipping” shipping method will become visible on the checkout page for you to select and proceed with your order.

checkout-shipping

These instructions will guide you through the process of creating a shipping module for Opencart.

If you need custom Opencart Development services then feel free to reach us and also explore our exclusive range of Opencart Addons.


Source link