SlideShare a Scribd company logo
Developing a Sticker plug-in
Sticker plug-in for Magento 2
Best practice
Giorgio Bignozzi
Technical Manager | Marketing Informatico
https://www.marketinginformatico.it
@GiorgioBignozzi
Michele Fantetti
Magento Developer at Maggioli Editore
http://www.fantetti.net
@WaP_oNe
Who we are
Abstract:
Our aim was to create an extension that adds the classical label to the product image in the
different layouts concerning products (product page, category page, related products,
upsell products, cross-sell products, widget, search results).
Goals:
• To create two labels (“Discount” and “New”) with different shapes and positions
• To have a separate graphic management of these labels (custom label or image). If you
choose a custom label, you can set two labels with a configurable text, text colour and
background colour
• To display the label on sale products or products associated to certain categories
(“Discount”)
• To display the label on products associated to certain categories (“New”)
• To enable/disable automatically (with programmable date and time) one or both the
stickers.
Our project: Stickers
Desiderata: category page
Desiderata: product page
Desiderata: widget
Desiderata: related / cross-sell / upsell
Desiderata: search results
• ISSUE #1: how to add the label (HTML code) without modifying layout files in
multiple pages and making the plugin independent
• SOLUTION #1: when rendering product attributes, upload HTML code that will
be completed lately via script JS.
• ISSUE #2: how and where to insert this HTML code
• SOLUTION #2: thanks to Magento 2 PLUGIN, beforeGetProductPrice() and
afterGetProductPrice().
Development: problems and solutions (1)
• ISSUE #3: how to insert extra code to this HTML code
• SOLUTION #3: requireJS
• ISSUE #4: enable/disable some configurable fields depending on which fields
you have valued before
• SOLUTION #4: upload a JS in the layout of the configuration page of the plugin
Development: problems and solutions (2)
File System: M1 VS M2
Differences in file
system organization
in M1 e M2
(Vanilla installation)
• registration.php
• etc/module.xml
Development: M1 vs M2 structure for plug-in registration
In M2 we need to modify only
one folder (app/code)
app/code/Mainf/Stickers/Model/Stickers.php
It manages every feature of the sticker (isInCategory(), isDiscounted(),
getDiscountAmount() etc.) in addition to inserting HTML code:
protected function _getHTML($stickerLayoutType, $class, $firstLabel = '', $secondLabel = '') {
switch ($stickerLayoutType) {
case self::STICKER_IMAGE:
$html = "<input type='hidden' class='".$class."' value='1' />";
break;
case self::STICKER_AREA:
$html = "<input type='hidden' class='".$class."' value='" . $this->getConfigValue($firstLabel) . "<br
/>" . $this->getConfigValue($secondLabel) . "' />";
break;
case self::STICKER_CALCULATED:
$html = "<input type='hidden' class='".$class."' value='" . $this->getDiscountAmount() . "' />";
break;
default:
$html = "<input type='hidden' class='".$class."' value='1' />";
break;
}
return $html;
}
Development : model class Stickers
app/code/Mainf/Stickers/Plugin/ProductStickersPlugin.php
namespace MainfStickersPlugin;
class ProductStickersPlugin extends MainfStickersModelStickers
{
const DISCOUNT_ACTIVATION = "stickers/stickers_discount_page/discount_activation";
const LATEST_ACTIVATION = "stickers/stickers_latest_page/latest_activation";
public function beforeGetProductPrice(
MagentoCatalogBlockProductAbstractProduct $abstractProduct,
MagentoCatalogModelProduct $product
) {
$this->_product = $product;
}
public function afterGetProductPrice(MagentoCatalogBlockProductAbstractProduct $product, $result)
{
if($this->isStickerActive(self::DISCOUNT_ACTIVATION)) {
$result .= $this->_setDiscountStickerHTML();
}
if($this->isStickerActive(self::LATEST_ACTIVATION)) {
$result .= $this->_setLatestStickerHTML();
}
return $result;
}
}
Development : PLUGIN (Dependency Injection)
app/code/Mainf/Stickers/view/frontend/layout/default.xml
<?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">
<head>
<css src="Mainf_Stickers::css/mainf-stickers.css"/>
<link src="https://fonts.googleapis.com/css?family=Oswald:400,700,300" rel="stylesheet" type="text/css"
src_type="url" />
</head>
<body>
<referenceContainer name="content">
<block name="category.discount.sticker" class="MainfStickersBlockDiscount"
template="Mainf_Stickers::categoryDiscount.phtml" cacheable="false" after="-" />
<block name="category.latest.sticker" class="MainfStickersBlockLatest"
template="Mainf_Stickers::categoryLatest.phtml" cacheable="false" after="-" />
</referenceContainer>
</body>
</page>
Other layout files: catalog_product_view.xml e checkout_cart_index.xml
Development: layout
app/code/Mainf/Stickers/view/frontend/templates/categoryDiscount.phtml
if($block->isDiscountActive()):
$discountImage = "<div class='mainf-sticker-wrapper top-right'>";
$discountImage .= "<img class='categoryDiscountImage' alt='".__('Discount')."' src='".$this-
>getUrl('pub/media')."mainf/stickers/images/".$block->getStickerImage()."' />";
$discountImage .= "</div>";
$discountArea = "<div class='mainf-sticker-wrapper top-right'>";
$discountArea .= "<div class='mainf-sticker discount-product' style='background-color: #".$block->getStickerBackground()."; color: #".$block-
>getStickerText().";'></div>";
$discountArea .= "</div>";
?>
Development: template
<script type="text/x-magento-init">
{
"*":{
"categoryPageDiscount":{
"imageTag": {
"discountImage": "<?php /* @escapeNotVerified */ echo $discountImage; ?>",
"discountArea": "<?php /* @escapeNotVerified */ echo $discountArea; ?>"
}}}}
</script>
<?php
endif;
app/code/Mainf/Stickers/view/frontend/requirejs-config.js
var config = {
map: {
'*': {
categoryPageDiscount: 'Mainf_Stickers/js/categoryPageDiscount',
categoryPageLatest: 'Mainf_Stickers/js/categoryPageLatest',
viewPageDiscount: 'Mainf_Stickers/js/viewPageDiscount',
viewPageLatest: 'Mainf_Stickers/js/viewPageLatest'
}
}
};
Development: RequireJS (1)
app/code/Mainf/Stickers/view/frontend/web/js/categoryPageDiscount.js
define(
['jquery'],
function ($) {
$.widget(
'mainf.categoryPageStickers',
{
_create: function () {
var self = this;
$(".categoryPageDiscount").each(function () {
if ($(this).val() == 1) {
$($(this).parent().parent().find("a").find("span").find("span"))
.prepend(self.options.imageTag.discountImage);
} else {
var discountAmount = $(this).val();
$($(this).parent().parent().find("a").find("span").find("span"))
.prepend(self.options.imageTag.discountArea);
$(".discount-product").html(discountAmount);
}
});
}
}
);
return $.mainf.categoryPageStickers;
}
);
Development: RequireJS (2)
Backend: module configuration & customization (1)
Backend: module configuration & customization (2)
app/code/Mainf/Stickers/etc/adminhtml/system.xml
<system>
<tab>..</tab>
<section><group><field>..</field></ group></section>
</system>
<source_model>MainfStickersModelConfigBackendStickerType</source_model>
app/code/Mainf/Stickers/Model/Config/Backend/StickerType.php
<?php
namespace MainfStickersModelConfigBackend;
use MagentoFrameworkOptionArrayInterface;
class StickerType implements ArrayInterface
{
public function toOptionArray()
{
$stickerTypes = array();
$stickerTypes[] = ['value' => 'image','label' => __('Image')];
$stickerTypes[] = ['value' => 'custom','label' => __('Custom Label')];
return $stickerTypes;
}
}
Development: module configuration & source model
Issue: to create a hierarchy when enabling/disabling fields
Solution: to upload a template in the layout of the configuration page
(adminhtml_system_config_edit.xml):
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="footer">
<block class="MainfStickersBlockConfig" template="Mainf_Stickers::js.phtml"/>
</referenceContainer>
</body>
</page>
In js.phtml template insert the JS code:
<script type="text/javascript">
require(
['jquery'],
function($) {
$(function() {
..
});
}
);
</script>
Development: module configuration & customization
• crontab.xml file creation (new!):
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
<group id="default">
<job name="mainf_stickers_activation" instance="MainfStickersModelObserver”
method="checkStickersActivation">
<schedule>*/5 * * * *</schedule>
</job>
</group>
</config>
• Observer.php file creation:
control of the status of the sticker (enabled/disabled)
comparison of date
enabling/disabling the sticker
flush of date field
Development: Observer
Basic CSS:
.product.media .mainf-sticker-wrapper.top-right {
top: 13px;
right: 13px;
}
.product.media .mainf-sticker-wrapper.top-left {
bottom: 200px;
}
.mainf-sticker.discount-product {
width: 66px;
border: #FFF 2px solid;
border-radius: 50%;
box-shadow: 2px 2px 2px #CCC;
text-align: center;
height: 60px;
padding: 10px 5px;
}
.mainf-sticker.latest-product {
min-width: 66px;
max-width: 130px;
min-height: 76px;
padding: 5px;
border: #FFF 2px solid;
box-shadow: 2px 2px 2px #CCC;
text-align:left;
}
Graphic changes
Basic CSS 1° option:
.product.media .mainf-sticker-wrapper.top-right {
top: 150px;
right: 150px;
}
Graphic changes
Basic CSS 2° option:
.product.media .mainf-sticker-wrapper.top-right {
top: 400px;
right: 150px;
}
.product.media .mainf-sticker-wrapper.top-left {
bottom: 600px;
}
.mainf-sticker.latest-product {
min-width: 66px;
max-width: 130px;
width: 150px;
min-height: 76px;
padding: 5px;
border: #FFF 2px solid;
box-shadow: 2px 2px 2px #CCC;
text-align:left;
}
Graphic changes
• Structural improvements for the development of extensions:
all files for each extension in the same folder;
substitution of controllers/ folder with Controller/ ;
use of XML Style Definition (XSD) within xml file;
split of config.xml in multiple xml files, each with a precise task (module.xml,
routes.xml, crontab.xml etc.) ;
one file for each action;
bin/magento
• Lots of bugs still open (1695 in GitHub, our is #8370), community not ready
as it is for M1 and a lot of doubts.
Conclusions
You can download the extension “Stickers” here:
https://github.com/WaPoNe/module-stickers
Or you can buy the extension “Stickers Pro” here:
http://www.magentostoremanager.it/module-stickers-
pro.html
Discount coupon for you: MMIT17
Reference
Write us at:
giorgio.bignozzi@marketinginformatico.it
michele.fantetti@maggioli.it
Marketing Informatico
Milano | Bologna | Rimini | Bari
Any question?

More Related Content

Viewers also liked

Angelo Coletta - Dalla Mass production alla mass customization
Angelo Coletta - Dalla Mass production alla mass customizationAngelo Coletta - Dalla Mass production alla mass customization
Angelo Coletta - Dalla Mass production alla mass customization
Meet Magento Italy
 

Viewers also liked (20)

Alessandro La Ciura - Live Chat ed Ecommerce: (ma) la chat vende veramente di...
Alessandro La Ciura - Live Chat ed Ecommerce: (ma) la chat vende veramente di...Alessandro La Ciura - Live Chat ed Ecommerce: (ma) la chat vende veramente di...
Alessandro La Ciura - Live Chat ed Ecommerce: (ma) la chat vende veramente di...
 
Giovanni Cappellotto - Come gestire le recommendation e le personalizzazioni ...
Giovanni Cappellotto - Come gestire le recommendation e le personalizzazioni ...Giovanni Cappellotto - Come gestire le recommendation e le personalizzazioni ...
Giovanni Cappellotto - Come gestire le recommendation e le personalizzazioni ...
 
Oleksii Korshenko - Magento 2 Backwards Compatible Policy
Oleksii Korshenko - Magento 2 Backwards Compatible PolicyOleksii Korshenko - Magento 2 Backwards Compatible Policy
Oleksii Korshenko - Magento 2 Backwards Compatible Policy
 
Gian Mario Infelici - Marketing automation e omnicanalità: come unire i canal...
Gian Mario Infelici - Marketing automation e omnicanalità: come unire i canal...Gian Mario Infelici - Marketing automation e omnicanalità: come unire i canal...
Gian Mario Infelici - Marketing automation e omnicanalità: come unire i canal...
 
Max Pronko - Best practices for checkout customisation in Magento 2
Max Pronko - Best practices for checkout customisation in Magento 2Max Pronko - Best practices for checkout customisation in Magento 2
Max Pronko - Best practices for checkout customisation in Magento 2
 
R.Grassi - P.Sardo - One integration: every wat to pay
R.Grassi - P.Sardo - One integration: every wat to payR.Grassi - P.Sardo - One integration: every wat to pay
R.Grassi - P.Sardo - One integration: every wat to pay
 
Piotr Karwatka - Managing IT project with no doubts. How to work with Agency,...
Piotr Karwatka - Managing IT project with no doubts. How to work with Agency,...Piotr Karwatka - Managing IT project with no doubts. How to work with Agency,...
Piotr Karwatka - Managing IT project with no doubts. How to work with Agency,...
 
Alejandro Cordero - Secure Electronic Commerce New Business and Repeat Busine...
Alejandro Cordero - Secure Electronic Commerce New Business and Repeat Busine...Alejandro Cordero - Secure Electronic Commerce New Business and Repeat Busine...
Alejandro Cordero - Secure Electronic Commerce New Business and Repeat Busine...
 
Igor Bondarenko - Magento2 Performance Bottlenecks: How to avoid it
Igor Bondarenko - Magento2 Performance Bottlenecks: How to avoid itIgor Bondarenko - Magento2 Performance Bottlenecks: How to avoid it
Igor Bondarenko - Magento2 Performance Bottlenecks: How to avoid it
 
Dirk Pinamonti - User Experience, Mobile, Cross Border: grow your business wi...
Dirk Pinamonti - User Experience, Mobile, Cross Border: grow your business wi...Dirk Pinamonti - User Experience, Mobile, Cross Border: grow your business wi...
Dirk Pinamonti - User Experience, Mobile, Cross Border: grow your business wi...
 
Alan Rhode: Ecommerce export: IVA, dazi doganali, accise e altri importanti t...
Alan Rhode: Ecommerce export: IVA, dazi doganali, accise e altri importanti t...Alan Rhode: Ecommerce export: IVA, dazi doganali, accise e altri importanti t...
Alan Rhode: Ecommerce export: IVA, dazi doganali, accise e altri importanti t...
 
Eugene Shakhsuvarov - Improving enterprise store scalability using AMQP and A...
Eugene Shakhsuvarov - Improving enterprise store scalability using AMQP and A...Eugene Shakhsuvarov - Improving enterprise store scalability using AMQP and A...
Eugene Shakhsuvarov - Improving enterprise store scalability using AMQP and A...
 
Angelo Coletta - Dalla Mass production alla mass customization
Angelo Coletta - Dalla Mass production alla mass customizationAngelo Coletta - Dalla Mass production alla mass customization
Angelo Coletta - Dalla Mass production alla mass customization
 
Vitalyi Golomoziy - Integration tests in Magento 2
Vitalyi Golomoziy - Integration tests in Magento 2Vitalyi Golomoziy - Integration tests in Magento 2
Vitalyi Golomoziy - Integration tests in Magento 2
 
William Sbarzaglia - Le buyer personas nell'e-commerce
William Sbarzaglia - Le buyer personas nell'e-commerceWilliam Sbarzaglia - Le buyer personas nell'e-commerce
William Sbarzaglia - Le buyer personas nell'e-commerce
 
Iacopo Pecchi - Aprire un E-commerce in CINA dalla A alla Z
Iacopo Pecchi - Aprire un E-commerce in CINA dalla A alla ZIacopo Pecchi - Aprire un E-commerce in CINA dalla A alla Z
Iacopo Pecchi - Aprire un E-commerce in CINA dalla A alla Z
 
Francesca Bazzi - Lo scenario e-commerce in Italia e nel mondo: dati, trend e...
Francesca Bazzi - Lo scenario e-commerce in Italia e nel mondo: dati, trend e...Francesca Bazzi - Lo scenario e-commerce in Italia e nel mondo: dati, trend e...
Francesca Bazzi - Lo scenario e-commerce in Italia e nel mondo: dati, trend e...
 
Improved Layered Navigation: Magento Extension by Amasty. User Guide.
Improved Layered Navigation: Magento Extension by Amasty. User Guide.Improved Layered Navigation: Magento Extension by Amasty. User Guide.
Improved Layered Navigation: Magento Extension by Amasty. User Guide.
 
Building with Virtual Development Environments
Building with Virtual Development EnvironmentsBuilding with Virtual Development Environments
Building with Virtual Development Environments
 
User Experience
User ExperienceUser Experience
User Experience
 

Similar to Giorgio Bignozzi - How to develop a Sticker plug-in for Magento 2: best practice

4 coding101 fewd_lesson4_j_query_and_buttons 20210105
4 coding101 fewd_lesson4_j_query_and_buttons 202101054 coding101 fewd_lesson4_j_query_and_buttons 20210105
4 coding101 fewd_lesson4_j_query_and_buttons 20210105
John Picasso
 
WordCamp ABQ 2013: Making the leap from Designer to Designer/Developer
WordCamp ABQ 2013: Making the leap from Designer to Designer/DeveloperWordCamp ABQ 2013: Making the leap from Designer to Designer/Developer
WordCamp ABQ 2013: Making the leap from Designer to Designer/Developer
my easel
 
Rp 6 session 2 naresh bhatia
Rp 6  session 2 naresh bhatiaRp 6  session 2 naresh bhatia
Rp 6 session 2 naresh bhatia
sapientindia
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
Chris Alfano
 
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docx
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docxPRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docx
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docx
harrisonhoward80223
 

Similar to Giorgio Bignozzi - How to develop a Sticker plug-in for Magento 2: best practice (20)

4 coding101 fewd_lesson4_j_query_and_buttons 20210105
4 coding101 fewd_lesson4_j_query_and_buttons 202101054 coding101 fewd_lesson4_j_query_and_buttons 20210105
4 coding101 fewd_lesson4_j_query_and_buttons 20210105
 
Wordcamp abq cf-cpt
Wordcamp abq cf-cptWordcamp abq cf-cpt
Wordcamp abq cf-cpt
 
Building Potent WordPress Websites
Building Potent WordPress WebsitesBuilding Potent WordPress Websites
Building Potent WordPress Websites
 
WordCamp ABQ 2013: Making the leap from Designer to Designer/Developer
WordCamp ABQ 2013: Making the leap from Designer to Designer/DeveloperWordCamp ABQ 2013: Making the leap from Designer to Designer/Developer
WordCamp ABQ 2013: Making the leap from Designer to Designer/Developer
 
Code Generation in Magento 2
Code Generation in Magento 2Code Generation in Magento 2
Code Generation in Magento 2
 
Extend sdk
Extend sdkExtend sdk
Extend sdk
 
Rp 6 session 2 naresh bhatia
Rp 6  session 2 naresh bhatiaRp 6  session 2 naresh bhatia
Rp 6 session 2 naresh bhatia
 
Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011Jarv.us Showcase — SenchaCon 2011
Jarv.us Showcase — SenchaCon 2011
 
Introduction to Mangento
Introduction to Mangento Introduction to Mangento
Introduction to Mangento
 
Mangento
MangentoMangento
Mangento
 
Odoo Experience 2018 - From a Web Controller to a Full CMS
Odoo Experience 2018 - From a Web Controller to a Full CMSOdoo Experience 2018 - From a Web Controller to a Full CMS
Odoo Experience 2018 - From a Web Controller to a Full CMS
 
Benefits of Google Tag Manager
Benefits of Google Tag ManagerBenefits of Google Tag Manager
Benefits of Google Tag Manager
 
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docx
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docxPRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docx
PRG 420 Week 3 Individual Assignment Netbeans Project (annual co.docx
 
Miva ReadyThemes for Store Owners
Miva ReadyThemes for Store OwnersMiva ReadyThemes for Store Owners
Miva ReadyThemes for Store Owners
 
Custom PrimeFaces components
Custom PrimeFaces componentsCustom PrimeFaces components
Custom PrimeFaces components
 
Fragments: Why, How, What For?
Fragments: Why, How, What For?Fragments: Why, How, What For?
Fragments: Why, How, What For?
 
How to-create-a-simple-module-in-magento-2.0
How to-create-a-simple-module-in-magento-2.0How to-create-a-simple-module-in-magento-2.0
How to-create-a-simple-module-in-magento-2.0
 
Refactor Large apps with Backbone
Refactor Large apps with BackboneRefactor Large apps with Backbone
Refactor Large apps with Backbone
 
Refactor Large applications with Backbone
Refactor Large applications with BackboneRefactor Large applications with Backbone
Refactor Large applications with Backbone
 
Refactoring Large Web Applications with Backbone.js
Refactoring Large Web Applications with Backbone.jsRefactoring Large Web Applications with Backbone.js
Refactoring Large Web Applications with Backbone.js
 

More from Meet Magento Italy

Giulio Gargiullo - Strategie di marketing digitale per avviare l’e-commerce i...
Giulio Gargiullo - Strategie di marketing digitale per avviare l’e-commerce i...Giulio Gargiullo - Strategie di marketing digitale per avviare l’e-commerce i...
Giulio Gargiullo - Strategie di marketing digitale per avviare l’e-commerce i...
Meet Magento Italy
 

More from Meet Magento Italy (20)

Dirk Pinamonti - Come affrontare la sfida del nuovo mercato multicanale e del...
Dirk Pinamonti - Come affrontare la sfida del nuovo mercato multicanale e del...Dirk Pinamonti - Come affrontare la sfida del nuovo mercato multicanale e del...
Dirk Pinamonti - Come affrontare la sfida del nuovo mercato multicanale e del...
 
Vinai Kopp - How i develop M2 modules
Vinai Kopp - How i develop M2 modules Vinai Kopp - How i develop M2 modules
Vinai Kopp - How i develop M2 modules
 
Eugene Shaksuvarov - Tuning Magento 2 for Maximum Performance
Eugene Shaksuvarov - Tuning Magento 2 for Maximum PerformanceEugene Shaksuvarov - Tuning Magento 2 for Maximum Performance
Eugene Shaksuvarov - Tuning Magento 2 for Maximum Performance
 
Muliadi jeo - How to sell online in Indonesia
Muliadi jeo - How to sell online in IndonesiaMuliadi jeo - How to sell online in Indonesia
Muliadi jeo - How to sell online in Indonesia
 
Max Pronko - 10 migration mistakes from Magento 1 to Magento 2
Max Pronko - 10 migration mistakes from Magento 1 to Magento 2Max Pronko - 10 migration mistakes from Magento 1 to Magento 2
Max Pronko - 10 migration mistakes from Magento 1 to Magento 2
 
Alessandro La Ciura - Progettare la migliore integrazione tra live chat ed e-...
Alessandro La Ciura - Progettare la migliore integrazione tra live chat ed e-...Alessandro La Ciura - Progettare la migliore integrazione tra live chat ed e-...
Alessandro La Ciura - Progettare la migliore integrazione tra live chat ed e-...
 
Bodin - Hullin & Potencier - Magento Performance Profiling and Best Practices
Bodin - Hullin & Potencier - Magento Performance Profiling and Best PracticesBodin - Hullin & Potencier - Magento Performance Profiling and Best Practices
Bodin - Hullin & Potencier - Magento Performance Profiling and Best Practices
 
Giulio Gargiullo - Strategie di marketing digitale per avviare l’e-commerce i...
Giulio Gargiullo - Strategie di marketing digitale per avviare l’e-commerce i...Giulio Gargiullo - Strategie di marketing digitale per avviare l’e-commerce i...
Giulio Gargiullo - Strategie di marketing digitale per avviare l’e-commerce i...
 
Vinai Kopp - FPC Hole punching in Magento 2
Vinai Kopp - FPC Hole punching in Magento 2Vinai Kopp - FPC Hole punching in Magento 2
Vinai Kopp - FPC Hole punching in Magento 2
 
Jacopo Nardiello - From CI to Prod: Running Magento at scale with Kubernetes
Jacopo Nardiello - From CI to Prod: Running Magento at scale with KubernetesJacopo Nardiello - From CI to Prod: Running Magento at scale with Kubernetes
Jacopo Nardiello - From CI to Prod: Running Magento at scale with Kubernetes
 
James Zetlen - PWA Studio Integration…With You
James Zetlen - PWA Studio Integration…With YouJames Zetlen - PWA Studio Integration…With You
James Zetlen - PWA Studio Integration…With You
 
Talesh Seeparsan - The Hound of the Malwarevilles
Talesh Seeparsan - The Hound of the MalwarevillesTalesh Seeparsan - The Hound of the Malwarevilles
Talesh Seeparsan - The Hound of the Malwarevilles
 
Miguel Balparda - A day in support
Miguel Balparda - A day in supportMiguel Balparda - A day in support
Miguel Balparda - A day in support
 
Volodymyr Kublytskyi - Develop Product, Design Platform
Volodymyr Kublytskyi - Develop Product, Design PlatformVolodymyr Kublytskyi - Develop Product, Design Platform
Volodymyr Kublytskyi - Develop Product, Design Platform
 
Rosario Toscano - Processi di ottimizzazione per una crescita continua
Rosario Toscano - Processi di ottimizzazione per una crescita continuaRosario Toscano - Processi di ottimizzazione per una crescita continua
Rosario Toscano - Processi di ottimizzazione per una crescita continua
 
Henrik Feld Jakobsen - How to sell online Scandinavia
Henrik Feld Jakobsen - How to sell online ScandinaviaHenrik Feld Jakobsen - How to sell online Scandinavia
Henrik Feld Jakobsen - How to sell online Scandinavia
 
Rabia Qureshi - How to sell online in UK
Rabia Qureshi - How to sell online in UKRabia Qureshi - How to sell online in UK
Rabia Qureshi - How to sell online in UK
 
Matteo Schuerch - How to sell online in Switzerland
Matteo Schuerch - How to sell online in SwitzerlandMatteo Schuerch - How to sell online in Switzerland
Matteo Schuerch - How to sell online in Switzerland
 
Il data-driven nell’e-commerce: il caso studio Alessi
Il data-driven nell’e-commerce: il caso studio AlessiIl data-driven nell’e-commerce: il caso studio Alessi
Il data-driven nell’e-commerce: il caso studio Alessi
 
Philippe Bernou - Seamless omnichannel solutions with Magento order management
Philippe Bernou - Seamless omnichannel solutions with Magento order managementPhilippe Bernou - Seamless omnichannel solutions with Magento order management
Philippe Bernou - Seamless omnichannel solutions with Magento order management
 

Recently uploaded

527598851-ppc-due-to-various-govt-policies.pdf
527598851-ppc-due-to-various-govt-policies.pdf527598851-ppc-due-to-various-govt-policies.pdf
527598851-ppc-due-to-various-govt-policies.pdf
rajpreetkaur75080
 
Introduction of Biology in living organisms
Introduction of Biology in living organismsIntroduction of Biology in living organisms
Introduction of Biology in living organisms
soumyapottola
 

Recently uploaded (14)

Getting started with Amazon Bedrock Studio and Control Tower
Getting started with Amazon Bedrock Studio and Control TowerGetting started with Amazon Bedrock Studio and Control Tower
Getting started with Amazon Bedrock Studio and Control Tower
 
Hi-Tech Industry 2024-25 Prospective.pptx
Hi-Tech Industry 2024-25 Prospective.pptxHi-Tech Industry 2024-25 Prospective.pptx
Hi-Tech Industry 2024-25 Prospective.pptx
 
Eureka, I found it! - Special Libraries Association 2021 Presentation
Eureka, I found it! - Special Libraries Association 2021 PresentationEureka, I found it! - Special Libraries Association 2021 Presentation
Eureka, I found it! - Special Libraries Association 2021 Presentation
 
527598851-ppc-due-to-various-govt-policies.pdf
527598851-ppc-due-to-various-govt-policies.pdf527598851-ppc-due-to-various-govt-policies.pdf
527598851-ppc-due-to-various-govt-policies.pdf
 
Writing Sample 2 -Bridging the Divide: Enhancing Public Engagement in Urban D...
Writing Sample 2 -Bridging the Divide: Enhancing Public Engagement in Urban D...Writing Sample 2 -Bridging the Divide: Enhancing Public Engagement in Urban D...
Writing Sample 2 -Bridging the Divide: Enhancing Public Engagement in Urban D...
 
Introduction of Biology in living organisms
Introduction of Biology in living organismsIntroduction of Biology in living organisms
Introduction of Biology in living organisms
 
05232024 Joint Meeting - Community Networking
05232024 Joint Meeting - Community Networking05232024 Joint Meeting - Community Networking
05232024 Joint Meeting - Community Networking
 
0x01 - Newton's Third Law: Static vs. Dynamic Abusers
0x01 - Newton's Third Law:  Static vs. Dynamic Abusers0x01 - Newton's Third Law:  Static vs. Dynamic Abusers
0x01 - Newton's Third Law: Static vs. Dynamic Abusers
 
Oracle Database Administration I (1Z0-082) Exam Dumps 2024.pdf
Oracle Database Administration I (1Z0-082) Exam Dumps 2024.pdfOracle Database Administration I (1Z0-082) Exam Dumps 2024.pdf
Oracle Database Administration I (1Z0-082) Exam Dumps 2024.pdf
 
Sharpen existing tools or get a new toolbox? Contemporary cluster initiatives...
Sharpen existing tools or get a new toolbox? Contemporary cluster initiatives...Sharpen existing tools or get a new toolbox? Contemporary cluster initiatives...
Sharpen existing tools or get a new toolbox? Contemporary cluster initiatives...
 
Pollinator Ambassador Earth Steward Day Presentation 2024-05-22
Pollinator Ambassador Earth Steward Day Presentation 2024-05-22Pollinator Ambassador Earth Steward Day Presentation 2024-05-22
Pollinator Ambassador Earth Steward Day Presentation 2024-05-22
 
The Canoga Gardens Development Project. PDF
The Canoga Gardens Development Project. PDFThe Canoga Gardens Development Project. PDF
The Canoga Gardens Development Project. PDF
 
Acorn Recovery: Restore IT infra within minutes
Acorn Recovery: Restore IT infra within minutesAcorn Recovery: Restore IT infra within minutes
Acorn Recovery: Restore IT infra within minutes
 
123445566544333222333444dxcvbcvcvharsh.pptx
123445566544333222333444dxcvbcvcvharsh.pptx123445566544333222333444dxcvbcvcvharsh.pptx
123445566544333222333444dxcvbcvcvharsh.pptx
 

Giorgio Bignozzi - How to develop a Sticker plug-in for Magento 2: best practice

  • 1.
  • 2. Developing a Sticker plug-in Sticker plug-in for Magento 2 Best practice
  • 3. Giorgio Bignozzi Technical Manager | Marketing Informatico https://www.marketinginformatico.it @GiorgioBignozzi Michele Fantetti Magento Developer at Maggioli Editore http://www.fantetti.net @WaP_oNe Who we are
  • 4. Abstract: Our aim was to create an extension that adds the classical label to the product image in the different layouts concerning products (product page, category page, related products, upsell products, cross-sell products, widget, search results). Goals: • To create two labels (“Discount” and “New”) with different shapes and positions • To have a separate graphic management of these labels (custom label or image). If you choose a custom label, you can set two labels with a configurable text, text colour and background colour • To display the label on sale products or products associated to certain categories (“Discount”) • To display the label on products associated to certain categories (“New”) • To enable/disable automatically (with programmable date and time) one or both the stickers. Our project: Stickers
  • 8. Desiderata: related / cross-sell / upsell
  • 10. • ISSUE #1: how to add the label (HTML code) without modifying layout files in multiple pages and making the plugin independent • SOLUTION #1: when rendering product attributes, upload HTML code that will be completed lately via script JS. • ISSUE #2: how and where to insert this HTML code • SOLUTION #2: thanks to Magento 2 PLUGIN, beforeGetProductPrice() and afterGetProductPrice(). Development: problems and solutions (1)
  • 11. • ISSUE #3: how to insert extra code to this HTML code • SOLUTION #3: requireJS • ISSUE #4: enable/disable some configurable fields depending on which fields you have valued before • SOLUTION #4: upload a JS in the layout of the configuration page of the plugin Development: problems and solutions (2)
  • 12. File System: M1 VS M2 Differences in file system organization in M1 e M2 (Vanilla installation)
  • 13. • registration.php • etc/module.xml Development: M1 vs M2 structure for plug-in registration In M2 we need to modify only one folder (app/code)
  • 14. app/code/Mainf/Stickers/Model/Stickers.php It manages every feature of the sticker (isInCategory(), isDiscounted(), getDiscountAmount() etc.) in addition to inserting HTML code: protected function _getHTML($stickerLayoutType, $class, $firstLabel = '', $secondLabel = '') { switch ($stickerLayoutType) { case self::STICKER_IMAGE: $html = "<input type='hidden' class='".$class."' value='1' />"; break; case self::STICKER_AREA: $html = "<input type='hidden' class='".$class."' value='" . $this->getConfigValue($firstLabel) . "<br />" . $this->getConfigValue($secondLabel) . "' />"; break; case self::STICKER_CALCULATED: $html = "<input type='hidden' class='".$class."' value='" . $this->getDiscountAmount() . "' />"; break; default: $html = "<input type='hidden' class='".$class."' value='1' />"; break; } return $html; } Development : model class Stickers
  • 15. app/code/Mainf/Stickers/Plugin/ProductStickersPlugin.php namespace MainfStickersPlugin; class ProductStickersPlugin extends MainfStickersModelStickers { const DISCOUNT_ACTIVATION = "stickers/stickers_discount_page/discount_activation"; const LATEST_ACTIVATION = "stickers/stickers_latest_page/latest_activation"; public function beforeGetProductPrice( MagentoCatalogBlockProductAbstractProduct $abstractProduct, MagentoCatalogModelProduct $product ) { $this->_product = $product; } public function afterGetProductPrice(MagentoCatalogBlockProductAbstractProduct $product, $result) { if($this->isStickerActive(self::DISCOUNT_ACTIVATION)) { $result .= $this->_setDiscountStickerHTML(); } if($this->isStickerActive(self::LATEST_ACTIVATION)) { $result .= $this->_setLatestStickerHTML(); } return $result; } } Development : PLUGIN (Dependency Injection)
  • 16. app/code/Mainf/Stickers/view/frontend/layout/default.xml <?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"> <head> <css src="Mainf_Stickers::css/mainf-stickers.css"/> <link src="https://fonts.googleapis.com/css?family=Oswald:400,700,300" rel="stylesheet" type="text/css" src_type="url" /> </head> <body> <referenceContainer name="content"> <block name="category.discount.sticker" class="MainfStickersBlockDiscount" template="Mainf_Stickers::categoryDiscount.phtml" cacheable="false" after="-" /> <block name="category.latest.sticker" class="MainfStickersBlockLatest" template="Mainf_Stickers::categoryLatest.phtml" cacheable="false" after="-" /> </referenceContainer> </body> </page> Other layout files: catalog_product_view.xml e checkout_cart_index.xml Development: layout
  • 17. app/code/Mainf/Stickers/view/frontend/templates/categoryDiscount.phtml if($block->isDiscountActive()): $discountImage = "<div class='mainf-sticker-wrapper top-right'>"; $discountImage .= "<img class='categoryDiscountImage' alt='".__('Discount')."' src='".$this- >getUrl('pub/media')."mainf/stickers/images/".$block->getStickerImage()."' />"; $discountImage .= "</div>"; $discountArea = "<div class='mainf-sticker-wrapper top-right'>"; $discountArea .= "<div class='mainf-sticker discount-product' style='background-color: #".$block->getStickerBackground()."; color: #".$block- >getStickerText().";'></div>"; $discountArea .= "</div>"; ?> Development: template <script type="text/x-magento-init"> { "*":{ "categoryPageDiscount":{ "imageTag": { "discountImage": "<?php /* @escapeNotVerified */ echo $discountImage; ?>", "discountArea": "<?php /* @escapeNotVerified */ echo $discountArea; ?>" }}}} </script> <?php endif;
  • 18. app/code/Mainf/Stickers/view/frontend/requirejs-config.js var config = { map: { '*': { categoryPageDiscount: 'Mainf_Stickers/js/categoryPageDiscount', categoryPageLatest: 'Mainf_Stickers/js/categoryPageLatest', viewPageDiscount: 'Mainf_Stickers/js/viewPageDiscount', viewPageLatest: 'Mainf_Stickers/js/viewPageLatest' } } }; Development: RequireJS (1)
  • 19. app/code/Mainf/Stickers/view/frontend/web/js/categoryPageDiscount.js define( ['jquery'], function ($) { $.widget( 'mainf.categoryPageStickers', { _create: function () { var self = this; $(".categoryPageDiscount").each(function () { if ($(this).val() == 1) { $($(this).parent().parent().find("a").find("span").find("span")) .prepend(self.options.imageTag.discountImage); } else { var discountAmount = $(this).val(); $($(this).parent().parent().find("a").find("span").find("span")) .prepend(self.options.imageTag.discountArea); $(".discount-product").html(discountAmount); } }); } } ); return $.mainf.categoryPageStickers; } ); Development: RequireJS (2)
  • 20. Backend: module configuration & customization (1)
  • 21. Backend: module configuration & customization (2)
  • 22. app/code/Mainf/Stickers/etc/adminhtml/system.xml <system> <tab>..</tab> <section><group><field>..</field></ group></section> </system> <source_model>MainfStickersModelConfigBackendStickerType</source_model> app/code/Mainf/Stickers/Model/Config/Backend/StickerType.php <?php namespace MainfStickersModelConfigBackend; use MagentoFrameworkOptionArrayInterface; class StickerType implements ArrayInterface { public function toOptionArray() { $stickerTypes = array(); $stickerTypes[] = ['value' => 'image','label' => __('Image')]; $stickerTypes[] = ['value' => 'custom','label' => __('Custom Label')]; return $stickerTypes; } } Development: module configuration & source model
  • 23. Issue: to create a hierarchy when enabling/disabling fields Solution: to upload a template in the layout of the configuration page (adminhtml_system_config_edit.xml): <?xml version="1.0"?> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> <body> <referenceContainer name="footer"> <block class="MainfStickersBlockConfig" template="Mainf_Stickers::js.phtml"/> </referenceContainer> </body> </page> In js.phtml template insert the JS code: <script type="text/javascript"> require( ['jquery'], function($) { $(function() { .. }); } ); </script> Development: module configuration & customization
  • 24. • crontab.xml file creation (new!): <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd"> <group id="default"> <job name="mainf_stickers_activation" instance="MainfStickersModelObserver” method="checkStickersActivation"> <schedule>*/5 * * * *</schedule> </job> </group> </config> • Observer.php file creation: control of the status of the sticker (enabled/disabled) comparison of date enabling/disabling the sticker flush of date field Development: Observer
  • 25. Basic CSS: .product.media .mainf-sticker-wrapper.top-right { top: 13px; right: 13px; } .product.media .mainf-sticker-wrapper.top-left { bottom: 200px; } .mainf-sticker.discount-product { width: 66px; border: #FFF 2px solid; border-radius: 50%; box-shadow: 2px 2px 2px #CCC; text-align: center; height: 60px; padding: 10px 5px; } .mainf-sticker.latest-product { min-width: 66px; max-width: 130px; min-height: 76px; padding: 5px; border: #FFF 2px solid; box-shadow: 2px 2px 2px #CCC; text-align:left; } Graphic changes
  • 26. Basic CSS 1° option: .product.media .mainf-sticker-wrapper.top-right { top: 150px; right: 150px; } Graphic changes
  • 27. Basic CSS 2° option: .product.media .mainf-sticker-wrapper.top-right { top: 400px; right: 150px; } .product.media .mainf-sticker-wrapper.top-left { bottom: 600px; } .mainf-sticker.latest-product { min-width: 66px; max-width: 130px; width: 150px; min-height: 76px; padding: 5px; border: #FFF 2px solid; box-shadow: 2px 2px 2px #CCC; text-align:left; } Graphic changes
  • 28. • Structural improvements for the development of extensions: all files for each extension in the same folder; substitution of controllers/ folder with Controller/ ; use of XML Style Definition (XSD) within xml file; split of config.xml in multiple xml files, each with a precise task (module.xml, routes.xml, crontab.xml etc.) ; one file for each action; bin/magento • Lots of bugs still open (1695 in GitHub, our is #8370), community not ready as it is for M1 and a lot of doubts. Conclusions
  • 29. You can download the extension “Stickers” here: https://github.com/WaPoNe/module-stickers Or you can buy the extension “Stickers Pro” here: http://www.magentostoremanager.it/module-stickers- pro.html Discount coupon for you: MMIT17 Reference
  • 30. Write us at: giorgio.bignozzi@marketinginformatico.it michele.fantetti@maggioli.it Marketing Informatico Milano | Bologna | Rimini | Bari Any question?