Creación de nuestro widget personalizado en Magento 2
Para añadir nuestro custom widget tenemos que crear el archivo etc/widget.xml. Este archivo incluye, entre otra información la class Block que gestionará el widget, y la definición de los parámetros de configuración del propio widget. En nuestro caso los parámetros que vamos a configurar cuando creemos un widget van a ser los siguientes:
- selector del static-content block que contendrá el contenido del popup
- campo para definir una clase CSS específica por popup
- campo para definir el popupInitTime específico por popup
- una opción para que el popup incluya o no un enlace a otra página
- campo para añadir la url del enlace (si procede)
Creamos el archivo etc/widget.xml con el siguiente contenido:
<widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Widget:etc/widget.xsd">
<widget class="Pablobae\SimplePopupWidget\Block\Widget\SimplePopup" id="simplepopupwidget">
<label>Simple PopUp</label>
<description>Simple and Flexible popup widget</description>
<parameters>
<parameter name="block_id" xsi:type="block" visible="true" required="true" sort_order="20">
<label translate="true">Block</label>
<block class="Magento\Cms\Block\Adminhtml\Block\Widget\Chooser">
<data>
<item name="button" xsi:type="array">
<item name="open" xsi:type="string" translate="true">Select Block...</item>
</item>
</data>
</block>
</parameter>
<parameter name="specificCssClass" xsi:type="text" visible="true" sort_order="20">
<label translate="true">Specific CSS Class</label>
<description translate="true">Override the default CSS Class value</description>
</parameter>
<parameter name="specificPopupInitTime" xsi:type="text" visible="true" sort_order="20">
<label translate="true">Specific Popup Init Time</label>
<description translate="true">Override the default Popup Init Time value (seconds)</description>
</parameter>
<parameter name="addLink" xsi:type="select" visible="true" required="true" sort_order="30">
<label translate="true">Add Link</label>
<options>
<option name="no" value="0">
<label translate="true">No</label>
</option>
<option name="yes" value="1">
<label translate="true">Yes</label>
</option>
</options>
</parameter>
<parameter name="linkText" xsi:type="text" visible="true" sort_order="40">
<label translate="true">Link Text</label>
<depends>
<parameter name="addLink" value="1"/>
</depends>
</parameter>
<parameter name="link" xsi:type="text" visible="true" sort_order="50">
<label translate="true">URL</label>
<depends>
<parameter name="addLink" value="1"/>
</depends>
</parameter>
</parameters>
</widget>
</widgets>
En la linea tres hemos definido la class Block que gestionará el widget: Pablobae\SimplePopupWidget\Block\Widget\SimplePopup. Añadimos el archivo Block/WidgetSimplePopup.php con el siguiente contenido:
<?php
declare(strict_types=1);
namespace Pablobae\SimplePopupWidget\Block\Widget;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\View\Element\Template;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Widget\Block\BlockInterface;
use Pablobae\SimplePopupWidget\Helper\Configuration as HelperConfiguration;
/**
* Class SimplePopup widget
*/
class SimplePopup extends Template implements BlockInterface
{
const WIDGET_OPTION_BLOCK = 'block_id';
protected $_template = "widget/simplepopup.phtml";
/**
* @var HelperConfiguration
*/
private $helperConfiguration;
/**
* @var StoreManagerInterface
*/
private $storeManager;
/**
* Constructor
*
* @param HelperConfiguration $helperConfiguration
* @param StoreManagerInterface $storeManager
* @param Template\Context $context
* @param array $data
*/
public function __construct(
HelperConfiguration $helperConfiguration,
StoreManagerInterface $storeManager,
Template\Context $context,
array $data = []
)
{
$this->helperConfiguration = $helperConfiguration;
$this->storeManager = $storeManager;
parent::__construct($context, $data);
}
/**
* Retrieve if the extension is enabled by configuration
*
* @return bool
*/
public function isExtensionEnabled(): bool
{
return $this->helperConfiguration->isEnabled();
}
/**
* Retrieve extension config value for CustomCSS Class
* @return string
*/
public function getDefaultCustomCSSClass(): string
{
return $this->helperConfiguration->getCustomCssClass();
}
/**
* Retrieve extension config value for PopupInitTime
* @return string
*/
public function getDefaultPopupInitTime(): string
{
return $this->helperConfiguration->getPopupInitTime();
}
/**
* Retrieve popup cms static block content
* @return string
*/
public function getPopupBlockContent(): string
{
$blockId = $this->getWidgetPopupBlockContentId();
if ($blockId != '') {
try {
return $this->getLayout()
->createBlock('Magento\Cms\Block\Block')
->setBlockId($blockId)
->toHtml();
} catch (LocalizedException $e) {
$this->_logger->error(__("Popup Block not found."));
}
}
return '';
}
/**
* Retrieve popup Block content ID
* @return string
*/
protected function getWidgetPopupBlockContentId(): string
{
return $this->getData(self::WIDGET_OPTION_BLOCK);
}
}
Esta clase define la variable $_template con la ubicación del archivo phtml que utilizará como plantilla nuestro widget. También incluye los métodos necesarios para obtener los valores de configuración específicos de nuestro widget (blockId, clase CSS y popupInittime específico, …) y, a través de la clase Helper/Configuration.php, obtiene los valores de configuración por defecto de la extensión. Toda esta información será utilizada en la plantilla para mostrar nuestro widget.
Creamos el archivo de plantilla view/frontend/templates/widget/simplepopup.phtml con el siguiente código:
<?php
declare(strict_types=1);
use Pablobae\SimplePopupWidget\Block\Widget\SimplePopup;
/* @var SimplePopup $block */
if ($block->isExtensionEnabled()) {
$popupInitTime = $block->escapeHtml($block->getData('specificPopupInitTime'));
if ($popupInitTime === null || $popupInitTime == "") {
$popupInitTime = $block->getDefaultPopupInitTime();
}
$staticBlockId = $block->getBlockId();
$hasLink = false;
if ($block->escapeHtml($block->getData('addLink')) == 1) {
$hasLink = true;
} ?>
<!-- SIMPLE POPUP -->
<div class="simplepopup <?= $staticBlockId;?>">
<div class="simplepopup-content">
<!-- CLOSING BUTTON-->
<span class="close">×</span>
<!-- END CLOSING BUTTON-->
<?php if ($hasLink) { ?>
<a class="simplepopup-link" href="<?= $block->escapeHtml($block->getData('link')) ?>"
title="<?= $block->escapeHtml($block->getData('linkText')) ?>">
<?php } ?>
<div
class="simplepopup-block-content <?= $block->getDefaultCustomCSSClass() . ' ' . $block->escapeHtml($block->getData('specificCssClass')) ?>">
<!-- POPUP CONTENT -->
<?= $block->getPopupBlockContent(); ?>
<!-- END POPUP CONTENT -->
</div>
<?php if ($hasLink) { ?>
</a>
<?php } ?>
<!-- DON'T SHOW AGAIN BUTTON -->
<div class="dontShowFeature">
<form>
<input type="checkbox" id="dontShow"/> <label
for="dontShow"><?php echo __("Don't show again"); ?></label>
</form>
</div>
<!-- END DON'T SHOW AGAIN BUTTON -->
</div>
</div>
<!-- END SIMPLE POPUP -->
<div
data-mage-init='{"simplepopup": {"popupInitTime": "<?= $popupInitTime ?>", "blockId": "<?= $staticBlockId; ?>" }}'></div>
<?php
} ?>
El template básicamente lo que hace comprobar que la extensión está activa y en caso de estarlo, obtiene el contenido del static content que se mostrará en el popup, las clases css, el valor de popupinittime, el enlace… y crea el código html de nuestro popup. La ventana del popup incluirá, además de nuestro contenido, un botón para cerrarlo, y un checkbox para permitir que el usuario decida si quiere o no seguir viendo el popup la próxima vez que visite la página.
Además, inicializa también el componente javascript simplepopup que se va a encargar de mostrar el popup en el momento configurado.
Añadimos a continuación el componente JS, creando el archivo view/frontend/web/requirejs-config.js con el siguiente contenido:
var config = {
map: {
'*': {
simplepopup: 'Pablobae_SimplePopupWidget/js/simplepopup',
}
}
}
Y creamos ahora el archivo view/frontend/web/js/simplepopup.js con el contenido:
define([
"jquery",
"jquery/jquery.cookie"
], function ($) {
"use strict";
return function (config, element) {
let options = {
blockId: config.blockId,
cookieName: 'simplepopupblock' + config.blockId,
popupInitTime: config.popupInitTime
};
function hidePopup() {
$('.simplepopup.' + options.blockId).hide();
}
function showPopup() {
$('.simplepopup.' + options.blockId).show();
}
function createCookie(cookieName) {
$.cookie(cookieName, 'dontShow', {expires: 15, path: '/'});
}
function removeCookie(cookieName) {
$.cookie(cookieName, 'dontShow', {expires: -1, path: '/'});
}
function initPopup() {
let dontShowCookie = $.cookie(options.cookieName);
if (!dontShowCookie) {
$('.simplepopup.' + options.blockId + ' .close').on('click', hidePopup);
$('#dontShow').change(function () {
if (this.checked) {
createCookie(options.cookieName);
} else {
removeCookie(options.cookieName);
}
})
setTimeout(showPopup, options.popupInitTime * 1000)
}
}
initPopup();
}
})
El componente javascript SimplePopup va a recibir el ID del bloque estático seleccionado en el widget, y el valor de popupinittime. Este último se utiliza para establecer la cuenta atrás que hará que se muestre el popup.
El ID del bloque se utiliza para poder tener más de un popup distinto en la misma página: permite crear el contenido de cada popup de forma independiente, y además, crear una cookie específica por cada uno de ellos.
Llegados a este punto solo nos queda crear dos archivos: view/frontend/layout/default.xml y view/frontend/web/css/simplepopup.css.
Creamos el primero con el siguiente contenido:
<?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="Pablobae_SimplePopupWidget::css/simplepopup.css"/>
</head>
<body>
<referenceContainer name="before.body.end">
<container name="simple.popup.container" label="Simple Popup Container"/>
</referenceContainer>
</body>
</page>
En este archivo lo que hacemos es decirle a Magento que incluya el archivo CSS básico de la extensión, con los ajustes de estilos necesarios para nuestro popup, y también se crea el contenedor Simple Popup Container: cuando se crea un widget tenemos que asignarle un bloque o contenedor donde queremos que se muestre, y nosotros utilizaremos el que acabamos de crear.
Por último, creamos el archivo view/frontend/web/css/simplepopup.css con el siguiente contenido:
.simplepopup {
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.4);
display:none;
}
.simplepopup .simplepopup-content {
background-color: #fefefe;
margin: 15% auto;
border: 1px solid #888;
max-width: 80%;
width: max-content;
overflow: hidden;
word-wrap: break-word;
position: relative;
}
/* The Close Button */
.simplepopup .close {
color: #aaa;
font-size: 28px;
font-weight: bold;
position: absolute;
top: -10px;
right: 0;
}
.simplepopup .close:hover,
.simplepopup .close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
/* The block content */
.simplepopup .simplepopup-content .simplepopup-block-content {
margin: 2rem;
}
/** The don't show checkbox */
.simplepopup .dontShowFeature {
position:absolute;
bottom:0.5rem;
left:2rem;
}