How to Create a Custom "Gift Wrapping" Module in Magento 2

How to Create a Custom "Gift Wrapping" Module in Magento 2
Adding a gift-wrapping feature to your Magento 2 store can enhance the shopping experience, especially during holidays and special occasions. While some extensions offer this functionality, building a custom module gives you full control over the design, pricing, and conditions. In this guide, we’ll walk through creating a simple yet effective gift-wrapping module from scratch.
Why Build a Custom Gift Wrapping Module?
Before diving into the code, let’s quickly discuss why you might want a custom solution:
- Flexibility: Define your own rules (e.g., per-product, per-category, or cart-based wrapping).
- Cost Control: Set fixed or percentage-based fees.
- Unique Branding: Customize the UI to match your store’s theme.
- No Dependency: Avoid third-party extensions that may conflict with other modules.
Step 1: Module Setup
First, create the basic module structure. Place it under app/code/Magefine/GiftWrapping
.
1. Create registration.php
:
<?php
use Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(
ComponentRegistrar::MODULE,
'Magefine_GiftWrapping',
__DIR__
);
2. Define module.xml
in etc/
:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Magefine_GiftWrapping" setup_version="1.0.0">
<sequence>
<module name="Magento_Checkout"/>
</sequence>
</module>
</config>
Run bin/magento setup:upgrade
to activate the module.
Step 2: Database Setup
We’ll store gift-wrapping options in a custom table. Create Setup/InstallSchema.php
:
<?php
namespace Magefine\GiftWrapping\Setup;
use Magento\Framework\DB\Ddl\Table;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
class InstallSchema implements InstallSchemaInterface
{
public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
{
$installer = $setup;
$installer->startSetup();
$table = $installer->getConnection()->newTable(
$installer->getTable('magefine_giftwrapping_options')
)->addColumn(
'option_id',
Table::TYPE_INTEGER,
null,
['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true],
'Option ID'
)->addColumn(
'title',
Table::TYPE_TEXT,
255,
['nullable' => false],
'Gift Wrapping Title'
)->addColumn(
'price',
Table::TYPE_DECIMAL,
'12,4',
['nullable' => false],
'Price'
)->addColumn(
'is_active',
Table::TYPE_BOOLEAN,
null,
['nullable' => false, 'default' => 1],
'Is Active'
);
$installer->getConnection()->createTable($table);
$installer->endSetup();
}
}
Step 3: Admin Configuration
Let admins manage wrapping options via the backend. Create etc/adminhtml/system.xml
:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<tab id="magefine" translate="label" sortOrder="100">
<label>Magefine</label>
</tab>
<section id="giftwrapping" translate="label" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Gift Wrapping</label>
<tab>magefine</tab>
<resource>Magefine_GiftWrapping::config</resource>
<group id="settings" translate="label" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
<label>General Settings</label>
<field id="enabled" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
<label>Enable Gift Wrapping</label>
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
</field>
</group>
</section>
</system>
</config>
Step 4: Frontend Integration
Now, let’s add the gift-wrapping option to the checkout. Override the checkout_index_index.xml
layout:
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="checkout.root">
<arguments>
<argument name="jsLayout" xsi:type="array">
<item name="components" xsi:type="array">
<item name="checkout" xsi:type="array">
<item name="children" xsi:type="array">
<item name="steps" xsi:type="array">
<item name="children" xsi:type="array">
<item name="shipping-step" xsi:type="array">
<item name="children" xsi:type="array">
<item name="shippingAddress" xsi:type="array">
<item name="children" xsi:type="array">
<item name="gift-wrapping" xsi:type="array">
<item name="component" xsi:type="string">Magefine_GiftWrapping/js/view/gift-wrapping</item>
<item name="sortOrder" xsi:type="string">100</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</item>
</argument>
</arguments>
</referenceBlock>
</body>
</page>
Step 5: JavaScript Component
Create view/frontend/web/js/view/gift-wrapping.js
:
define([
'ko',
'uiComponent',
'Magento_Checkout/js/model/quote'
], function (ko, Component, quote) {
'use strict';
return Component.extend({
defaults: {
template: 'Magefine_GiftWrapping/gift-wrapping'
},
isVisible: ko.observable(true),
initialize: function () {
this._super();
},
getWrappingOptions: function () {
// Fetch options via AJAX or predefined config
return [
{ id: 1, title: 'Premium Wrapping', price: 5.00 },
{ id: 2, title: 'Standard Wrapping', price: 2.50 }
];
}
});
});
Step 6: Template File
Add view/frontend/web/template/gift-wrapping.html
:
<div class="gift-wrapping-options" data-bind="visible: isVisible">
<h3>Gift Wrapping</h3>
<!-- ko foreach: getWrappingOptions() -->
<div class="option">
<input type="radio" name="gift_wrapping" data-bind="attr: { id: 'wrapping_' + id, value: id }" />
<label data-bind="attr: { for: 'wrapping_' + id }">
<span data-bind="text: title"></span> (+<span data-bind="text: price"></span>)
</label>
</div>
<!-- /ko -->
</div>
Step 7: Save Selection to Quote
Create an observer to save the selected option to the quote. Add etc/frontend/events.xml
:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="checkout_cart_save_after">
<observer name="magefine_giftwrapping_save" instance="Magefine\GiftWrapping\Observer\SaveGiftWrapping"/>
</event>
</config>
Then, create the observer:
<?php
namespace Magefine\GiftWrapping\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
class SaveGiftWrapping implements ObserverInterface
{
public function execute(Observer $observer)
{
$cart = $observer->getEvent()->getCart();
$wrappingOption = $cart->getQuote()->getGiftWrappingOption();
// Save to quote or order
}
}
Final Thoughts
This custom module gives you full control over gift-wrapping logic in Magento 2. You can extend it further by:
- Adding per-product wrapping options.
- Integrating with payment gateways for dynamic pricing.
- Enabling gift messages alongside wrapping.
Need a pre-built solution? Check out Magefine’s Magento 2 extensions for optimized performance.