30

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

Embed Size (px)

Citation preview

Developing a Sticker plug-in

Sticker plug-in for Magento 2

Best practice

Giorgio BignozziTechnical Manager | Marketing Informatico

https://www.marketinginformatico.it

@GiorgioBignozzi

Michele FantettiMagento 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 youchoose 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 willbe 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 fieldsyou 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 organizationin 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 onlyone 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 Mainf\Stickers\Plugin;

class ProductStickersPlugin extends \Mainf\Stickers\Model\Stickers{

const DISCOUNT_ACTIVATION = "stickers/stickers_discount_page/discount_activation";const LATEST_ACTIVATION = "stickers/stickers_latest_page/latest_activation";

public function beforeGetProductPrice(\Magento\Catalog\Block\Product\AbstractProduct $abstractProduct,\Magento\Catalog\Model\Product $product

) {$this->_product = $product;

}

public function afterGetProductPrice(\Magento\Catalog\Block\Product\AbstractProduct $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="Mainf\Stickers\Block\Discount"

template="Mainf_Stickers::categoryDiscount.phtml" cacheable="false" after="-" /><block name="category.latest.sticker" class="Mainf\Stickers\Block\Latest"

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>

<?phpendif;

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>Mainf\Stickers\Model\Config\Backend\StickerType</source_model>

app/code/Mainf/Stickers/Model/Config/Backend/StickerType.php<?phpnamespace Mainf\Stickers\Model\Config\Backend;

use Magento\Framework\Option\ArrayInterface;

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="Mainf\Stickers\Block\Config" 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="Mainf\Stickers\Model\Observer”

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:

[email protected]

[email protected]

Marketing InformaticoMilano | Bologna | Rimini | Bari

Any question?