Cómo agregar un campo personalizado a las opciones en la extensión de opciones de productos avanzadas

Publicado: 2020-09-08

A partir de este artículo, aprenderá cómo crear un campo "GTIN" para las opciones personalizadas del producto, mostrarlo en el front-end de la página del producto y mostrarlo en el pedido.

Sin más preámbulos, procedamos a las pautas paso a paso.

Tabla de contenido

  • Paso 1. Crear nuevo módulo
  • Paso 2. Agregar nuestro nuevo campo a la base de datos
  • Paso 3. Agregar lógica para trabajar con backend
  • Paso 4. Mostrar nuestro campo en el front-end de la página del producto
  • Paso #5. Agregue nuestros datos de atributos a los detalles del pedido en la base de datos
  • Paso #6. Mostrar datos en la página de pedidos en el panel de administración

Paso 1. Crear nuevo módulo

Describimos en detalle cómo crear un módulo en este artículo. Por lo tanto, saltemos esta parte y pasemos directamente al código que necesitará para crear un complemento:

1.compositor.json

 { "name": "mageworx/module-optiongtin", "description": "N/A", "require": { "magento/framework" : ">=100.1.0 <101", "magento/module-catalog": ">=101.0.0 <104" }, "type": "magento2-module", "version": "1.0.0", "license": [ "OSL-3.0", "AFL-3.0" ], "autoload": { "files": [ "registration.php" ], "psr-4": { "VendorName\\OptionGtin\\": "" } } }

2.etc/módulo.xml

 <?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="VendorName_OptionGtin" setup_version="1.0.0"> <sequence> <module name="Magento_Catalog"/> <module name="MageWorx_OptionBase"/> </sequence> </module> </config>

3.registro.php

 <?php \Magento\Framework\Component\ComponentRegistrar::register( \Magento\Framework\Component\ComponentRegistrar::MODULE, 'VendorName_OptionGtin', __DIR__ );

Paso 2. Agregar nuestro nuevo campo a la base de datos

Después de haber creado un módulo vacío, es hora de crear el nuevo campo "GTIN" y agregarlo a la base de datos dentro de la tabla correspondiente. Como agregamos un campo para los valores de las opciones, necesitaremos la tabla "catalog_product_option".

Vamos a crear el siguiente archivo:

app/code/VendorName/OptionGtin/Setup/InstallSchema.php

 <?php namespace VendorName\OptionGtin\Setup; use Magento\Framework\Setup\InstallSchemaInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\SchemaSetupInterface; use Magento\Framework\DB\Ddl\Table; class InstallSchema implements InstallSchemaInterface { public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) { $setup->startSetup(); $setup->getConnection()->addColumn( $setup->getTable('catalog_product_option'), 'gtin', [ 'type' => Table::TYPE_TEXT, 'nullable' => true, 'default' => null, 'comment' => 'Gtin (added by VendorName Option Gtin)', ] ); $setup->endSetup(); } }

Paso 3. Agregar lógica para trabajar con backend

Usaremos el mecanismo modificador de grupo para agregar nuestro nuevo campo.

Ahora, agregue el siguiente archivo:

app/code/VendorName/OptionGtin/etc/adminhtml/di.xml

 <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <virtualType name="MageWorx\OptionBase\Ui\DataProvider\Product\Form\Modifier\Pool"> <arguments> <argument name="modifiers" xsi:type="array"> <item name="mageworx-option-gtin" xsi:type="array"> <item name="class" xsi:type="string">VendorName\OptionGtin\Ui\DataProvider\Product\Form\Modifier\OptionGtin</item> <item name="sortOrder" xsi:type="number">72</item> </item> </argument> </arguments> </virtualType> </config>

Aquí, agreguemos nuestro modificador al grupo compartido de la extensión Opciones avanzadas de productos: "MageWorx\OptionBase\Ui\DataProvider\Product\Form\Modifier\Pool". “VendorName\OptionGtin\Ui\DataProvider\Product\Form\Modifier\OptionGtin” es nuestro modificador de clase.

El código que permite agregar nuestro campo al app/code/VendorName/OptionGtin/Ui/DataProvider/Product/Form/Modifier/OptionGtin.php se proporciona a continuación:

 <?php namespace VendorName\OptionGtin\Ui\DataProvider\Product\Form\Modifier; use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\AbstractModifier; use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\CustomOptions; use Magento\Ui\Component\Form\Element\Input; use Magento\Ui\Component\Form\Element\DataType\Number; use Magento\Ui\Component\Form\Field; use MageWorx\OptionBase\Ui\DataProvider\Product\Form\Modifier\ModifierInterface; class OptionGtin extends AbstractModifier implements ModifierInterface { /** * @var array */ protected $meta = []; /** * {@inheritdoc} */ public function modifyData(array $data) { return $data; } /** * {@inheritdoc} */ public function modifyMeta(array $meta) { $this->meta = $meta; $this->addFields(); return $this->meta; } /** * Adds fields to the meta-data */ protected function addFields() { $groupCustomOptionsName = CustomOptions::GROUP_CUSTOM_OPTIONS_NAME; $optionContainerName = CustomOptions::CONTAINER_OPTION; $commonOptionContainerName = CustomOptions::CONTAINER_COMMON_NAME; // Add fields to the option $optionFeaturesFields = $this->getOptionGtinFieldsConfig(); $this->meta[$groupCustomOptionsName]['children']['options']['children']['record']['children'] [$optionContainerName]['children'][$commonOptionContainerName]['children'] = array_replace_recursive( $this->meta[$groupCustomOptionsName]['children']['options']['children']['record']['children'] [$optionContainerName]['children'][$commonOptionContainerName]['children'], $optionFeaturesFields ); } /** * The custom option fields config * * @return array */ protected function getOptionGtinFieldsConfig() { $fields['gtin'] = $this->getGtinFieldConfig(); return $fields; } /** * Get gtin field config * * @return array */ protected function getGtinFieldConfig() { return [ 'arguments' => [ 'data' => [ 'config' => [ 'label' => __('GTIN'), 'componentType' => Field::NAME, 'formElement' => Input::NAME, 'dataType' => Number::NAME, 'dataScope' => 'gtin', 'sortOrder' => 65 ], ], ], ]; } /** * Check is current modifier for the product only * * @return bool */ public function isProductScopeOnly() { return false; } /** * Get sort order of modifier to load modifiers in the right order * * @return int */ public function getSortOrder() { return 32; } }

Ahora, intentemos instalar la extensión y verifiquemos que todo se muestre:

  • Módulo php bin/magento: habilitar VendorName_OptionGtin
  • Configuración de php bin/magento: actualizar
  • php bin/caché de magento: vaciar

Nuestro nuevo campo se ha agregado con éxito:

Cómo agregar un campo personalizado a las opciones avanzadas de productos | Blog

Paso 4. Mostrar nuestro campo en el front-end de la página del producto

La extensión Mageworx Advanced Product Options ya lo tiene todo para mostrar y trabajar con los atributos que agrega nuestro módulo. Todo lo que tenemos que hacer es agregar el nuevo atributo al conjunto de datos compartido.

Nuestro módulo MageWorx_OptionBase ya usa el método getExtendedOptionsConfig() . Recopila y muestra todos los atributos personalizados en un bloque en el front-end. Abra la clase app/code/MageWorx/OptionBase/Block/Product/View/Options.php para ver cómo se implementa.

Comencemos con la creación de un modelo con nuestro atributo:

app/code/VendorName/OptionGtin/Model/Attriburte/Option/Gtin.php

 <?php namespace VendorName\OptionGtin\Model\Attribute\Option; use MageWorx\OptionBase\Model\Product\Option\AbstractAttribute; class Gtin extends AbstractAttribute { /** * @return string */ public function getName() { return 'gtin'; } }

Ahora, use el mecanismo de "inyección de dependencia" y agregue nuestro atributo al conjunto de datos de atributos compartidos de la extensión Opciones avanzadas de productos.

app/code/VendorName/OptionGtin/etc/di.xml

 <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <!-- Data --> <type name="MageWorx\OptionBase\Model\Product\Option\Attributes"> <arguments> <argument name="data" xsi:type="array"> <item name="gtin" xsi:type="object">VendorName\OptionGtin\Model\Attribute\Option\Gtin</item> </argument> </arguments> </type> </config>

En otras palabras, al abrir la MageWorx\OptionBase\Model\Product\Option\Attributes , verá que simplemente recopila todos los objetos de atributo en el conjunto de datos compartido.

Para mostrar los datos de nuestro nuevo atributo "GTIN", hemos decidido usar la función firstrun() de app/code/MageWorx/OptionFeatures/view/base/web/js/catalog/product/features.js . Ya tiene toda la implementación requerida que se ajusta mejor a nuestro ejemplo. Para evitar sobrescribir todo el archivo, aplicaremos el mecanismo de "mixins de JavaScript", que nos ayudará a cambiar solo la función necesaria.

Cree el siguiente archivo y defina nuestra combinación allí: app/code/VendorName/OptionGtin/view/frontend/requirejs-config.js

 var config = { config: { mixins: { 'MageWorx_OptionFeatures/js/catalog/product/features': { 'VendorName_OptionGtin/js/catalog/product/features-gtin-mixin' : true } } } };

Aquí, MageWorx_OptionFeatures/js/catalog/product/features es la raíz de nuestro archivo, cuyo método necesitamos reescribir. VendorName_OptionGtin/js/catalog/product/features-gtin-mixin es el archivo, donde reescribiremos el método.

Entonces, vamos a crearlo: app/code/VendorName/OptionGtin/view/frontend/web/js/catalog/product/features-gtin-mixin.js

 define([ 'jquery', 'jquery/ui', 'mage/utils/wrapper' ], function ($, wrapper) { 'use strict'; return function (widget) { $.widget('mageworx.optionFeatures', widget, { /** * Triggers one time at first run (from base.js) * @param optionConfig * @param productConfig * @param base * @param self */ firstRun: function firstRun(optionConfig, productConfig, base, self) { //shareable link $('#mageworx_shareable_hint_icon').qtip({ content: { text: this.options.shareable_link_hint_text }, style: { classes: 'qtip-light' }, position: { target: false } }); $('#mageworx_shareable_link').on('click', function () { try { self.copyTextToClipboard(self.getShareableLink(base)); $('.mageworx-shareable-link-container').hide(); $('.mageworx-shareable-link-success-container').show(); setTimeout(function () { $('.mageworx-shareable-link-container').show(); $('.mageworx-shareable-link-success-container').hide(); }, 2000); } catch (error) { console.log('Something goes wrong. Unable to copy'); } }); setTimeout(function () { // Qty input $('.mageworx-option-qty').each(function () { $(this).on('change', function () { var optionInput = $("[data-selector='" + $(this).attr('data-parent-selector') + "']"); optionInput.trigger('change'); }); }); }, 500); // Option\Value Description & tooltip var extendedOptionsConfig = typeof base.options.extendedOptionsConfig != 'undefined' ? base.options.extendedOptionsConfig : {}; for (var option_id in optionConfig) { if (!optionConfig.hasOwnProperty(option_id)) { continue; } var description = extendedOptionsConfig[option_id]['description'], gtin = extendedOptionsConfig[option_id]['gtin'], gtinTitle = "Global Trade Item Number: ", $option = base.getOptionHtmlById(option_id); if (1 > $option.length) { console.log('Empty option container for option with id: ' + option_id); continue; } var $label = $option.find('label'); if(gtin != null && gtin.length > 0) { if ($label.length > 0) { $label .first() .after($('<p class="option-gtin-text"><span>' + gtinTitle + '</span>' + gtin + '</p>')); } else { $label = $option.find('span'); $label .first() .parent() .after($('<p class="option-gtin-text"><span>' + gtinTitle + '</span>' + gtin + '</p>')); } } if (this.options.option_description_enabled && !_.isEmpty(extendedOptionsConfig[option_id]['description'])) { if (this.options.option_description_mode == this.options.option_description_modes.tooltip) { var $element = $option.find('label span') .first(); if ($element.length == 0) { $element = $option.find('fieldset legend span') .first(); } $element.css('border-bottom', '1px dotted black'); $element.qtip({ content: { text: description }, style: { classes: 'qtip-light' }, position: { target: false } }); } else if (this.options.option_description_mode == this.options.option_description_modes.text) { if ($label.length > 0) { $label .first() .after($('<p class="option-description-text">' + description + '</p>')); } else { $label = $option.find('span'); $label .first() .parent() .after($('<p class="option-description-text">' + description + '</p>')); } } else { console.log('Unknown option mode'); } } if (this.options.value_description_enabled) { this._addValueDescription($option, optionConfig, extendedOptionsConfig); } } } }); return $.mageworx.optionFeatures; }; });

En general, podemos ejecutar los siguientes comandos ahora:

  • php bin/caché de magento: vaciar
  • configuración de php bin/magento: contenido estático: implementación (solo para el modo de producción)

y ver lo que tenemos. Pero primero, agregue algunos estilos a nuestro nuevo atributo y haga que se vea bien en la interfaz.

Cree un diseño y defina nuestro nuevo archivo de estilos allí: app/code/VendorName/OptionGtin/view/frontend/layout/catalog_product_view.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="VendorName_OptionGtin::css/gtin.css"/> </head> </page>

Es hora de crear un archivo de estilos: app/code/VendorName/OptionGtin/view/frontend/web/css/gtin.css

 .option-gtin-text span { color: #6cc308; font-weight: 700; }

Ahora, ejecutemos los comandos descritos anteriormente y verifiquemos los resultados:

Cómo agregar un campo personalizado a las opciones avanzadas de productos | Blog

Paso #5. Agregue nuestros datos de atributos a los detalles del pedido en la base de datos

Cuando un cliente realiza una compra, se crea un pedido. Los detalles sobre los artículos agregados se incluyen en la tabla sales_order_item . Esta tabla tiene el campo product_options que contiene información sobre los parámetros seleccionados de un artículo agregado. Ahí es donde debemos agregar los datos de nuestro nuevo atributo.

A medida que se crea un pedido, se activa el evento sales_quote_address_collect_totals_before . Lo usaremos para agregar nuestros datos a las opciones del producto.

Definamos el evento creando: app/code/VendorName/OptionGtin/etc/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="sales_quote_address_collect_totals_before"> <observer name="mageworx_optiongtin_add_gtin_to_order" instance="VendorName\OptionGtin\Observer\AddGtinToOrder" /> </event> </config>

Luego, crea nuestro observador: app/code/VendorName/OptionGtin/Observer/AddGtinToOrder.php

 <?php namespace VendorName\OptionGtin\Observer; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Catalog\Model\ProductRepository as ProductRepository; use MageWorx\OptionBase\Helper\Data as BaseHelper; class AddGtinToOrder implements ObserverInterface { /** * @var BaseHelper */ protected $baseHelper; protected $productRepository; /** * AddGtinToOrder constructor. * @param BaseHelper $baseHelper * @param ProductRepository $productRepository */ public function __construct( BaseHelper $baseHelper, ProductRepository $productRepository ) { $this->baseHelper = $baseHelper; $this->productRepository = $productRepository; } /** * Add product to quote action * Processing: gtin * * @param Observer $observer * @return $this */ public function execute(Observer $observer) { $quoteItems = $observer->getQuote()->getAllItems(); /** @var \Magento\Quote\Model\Quote\Item $quoteItem */ foreach ($quoteItems as $quoteItem) { $buyRequest = $quoteItem->getBuyRequest(); $optionIds = array_keys($buyRequest->getOptions()); $productOptions = $this->productRepository->getById($buyRequest->getProduct())->getOptions(); $quoteItemOptionGtins = []; $optionGtins = []; foreach ($productOptions as $option) { if ($option->getGtin()) { $quoteItemOptionGtins[$option->getOptionId()] = $option->getGtin(); } } foreach ($optionIds as $optionId) { $optionGtins[$optionId] = $optionId; } $optionGtins = array_intersect_key($quoteItemOptionGtins, $optionGtins); $infoBuyRequest = $quoteItem->getOptionByCode('info_buyRequest'); $buyRequest->setData('gtin', $optionGtins); $infoBuyRequest->setValue($this->baseHelper->encodeBuyRequestValue($buyRequest->getData())); $quoteItem->addOption($infoBuyRequest); } } }

Aquí, con la ayuda del observador, obtenemos la lista de todos los artículos en el pedido y agregamos los datos de nuestro atributo "GTIN" al llamado $infoBuyRequest .

Para comprobar que todo se ha realizado correctamente, crea un pedido con el producto, cuyas opciones tienen datos “GTIN”. Puede comprobar que los datos se han añadido en la base sales_order_item table -> campo product_options :

Cómo agregar un campo personalizado a las opciones avanzadas de productos | Blog

Paso #6. Mostrar datos en la página de pedidos en el panel de administración

Hay diferentes medios para mostrar la información requerida en la plantilla lista. Por ejemplo, usando "js". Trabajamos con "js" en este artículo. ¡Trabajemos con las plantillas en sí mismas para variar e intentemos reescribirlas!

Cambie la app/code/VendorName/OptionGtin/etc/adminhtml/di.xml agregando el complemento allí:

 <?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <virtualType name="MageWorx\OptionBase\Ui\DataProvider\Product\Form\Modifier\Pool"> <arguments> <argument name="modifiers" xsi:type="array"> <item name="mageworx-option-gtin" xsi:type="array"> <item name="class" xsi:type="string">VendorName\OptionGtin\Ui\DataProvider\Product\Form\Modifier\OptionGtin</item> <item name="sortOrder" xsi:type="number">72</item> </item> </argument> </arguments> </virtualType> <!-- Plugins--> <type name="Magento\Sales\Block\Adminhtml\Items\Column\DefaultColumn"> <plugin name="mageworx-optiongtin-add-default-column" type="VendorName\OptionGtin\Plugin\AddDefaultColumn" sortOrder="5" disabled="false" /> </type> </config>

Cree el complemento en sí:

app/code/VendorName/OptionGtin/Plugin/AddDefaultColumn.php

 <?php namespace VendorName\OptionGtin\Plugin; class AddDefaultColumn { /** * @param \Magento\Sales\Block\Adminhtml\Items\Column\DefaultColumn $subject * @param $result * @return array */ public function afterGetOrderOptions(\Magento\Sales\Block\Adminhtml\Items\Column\DefaultColumn $subject, $result) { if ($options = $subject->getItem()->getProductOptions()) { if (isset($result)) { foreach ($result as &$option) { if (array_key_exists($option['option_id'], $options['info_buyRequest']['gtin'])) { $option['gtin'] = $options['info_buyRequest']['gtin'][$option['option_id']]; } } } } return $result; } }

Este complemento agrega información sobre nuestro nuevo atributo para las opciones de pedido, para las cuales existen estos datos.

vendor/magento/module-sales/view/adminhtml/templates/items/column/name.phtml es responsable de mostrar información sobre las opciones de productos en la página de pedido en el panel de administración.

Reescribámoslo para mostrar nuestro "GTIN". Para eso, necesitamos reescribir el bloque “column_name”, o más bien su plantilla. Crear un diseño y una plantilla:

app/code/VendorName/OptionGtin/view/adminhtml/layout/sales_order_view.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"> <body> <referenceBlock name="column_name"> <action method="setTemplate"> <argument name="template" xsi:type="string">VendorName_OptionGtin::items/column/name.phtml</argument> </action> </referenceBlock> </body> </page>

app/code/VendorName/OptionGtin/view/adminhtml/templates/items/column/name.phtml

 <?php /* @var $block \Magento\Sales\Block\Adminhtml\Items\Column\Name */ ?> <?php if ($_item = $block->getItem()) : ?> <div class="product-title"> <?= $block->escapeHtml($_item->getName()) ?> </div> <div class="product-sku-block"> <span><?= $block->escapeHtml(__('SKU'))?>:</span> <?= /* @noEscape */ implode('<br />', $this->helper(\Magento\Catalog\Helper\Data::class)->splitSku($block->escapeHtml($block->getSku()))) ?> </div> <?php if ($block->getOrderOptions()) : ?> <dl class="item-options"> <?php foreach ($block->getOrderOptions() as $_option) : ?> <dt><?= $block->escapeHtml($_option['label']) ?>:</dt> <dd> <?php if (isset($_option['custom_view']) && $_option['custom_view']) : ?> <?= /* @noEscape */ $block->getCustomizedOptionValue($_option) ?> <?php else : ?> <?php $optionValue = $block->getFormattedOption($_option['value']); ?> <?php $dots = 'dots' . uniqid(); ?> <?php $ . uniqid(); ?> <?= $block->escapeHtml($optionValue['value'], ['a', 'br']) ?><?php if (isset($optionValue['remainder']) && $optionValue['remainder']) : ?> <span> ...</span> <span><?= $block->escapeHtml($optionValue['remainder'], ['a']) ?></span> <script> require(['prototype'], function() { $('<?= /* @noEscape */ $id; ?>').hide(); $('<?= /* @noEscape */ $id; ?>').up().observe('mouseover', function(){$('<?= /* @noEscape */ $id; ?>').show();}); $('<?= /* @noEscape */ $id; ?>').up().observe('mouseover', function(){$('<?= /* @noEscape */ $dots; ?>').hide();}); $('<?= /* @noEscape */ $id; ?>').up().observe('mouseout', function(){$('<?= /* @noEscape */ $id; ?>').hide();}); $('<?= /* @noEscape */ $id; ?>').up().observe('mouseout', function(){$('<?= /* @noEscape */ $dots; ?>').show();}); }); </script> <?php endif; ?> <?php endif; ?> </dd> <dt> <?php if (isset($_option['gtin']) && $_option['gtin']) : ?> <span>GTIN:</span> <?php endif; ?> </dt> <dd> <?php if (isset($_option['gtin']) && $_option['gtin']) : ?> <span> <?= $block->escapeHtml($_option['gtin']) ?></span> <?php endif; ?> </dd> <?php endforeach; ?> </dl> <?php endif; ?> <?= $block->escapeHtml($_item->getDescription()) ?> <?php endif; ?>

Si todo se ha realizado correctamente, borrado y compilado, verá el siguiente resultado:

Cómo agregar un campo personalizado a las opciones avanzadas de productos | Blog

Esperamos que encuentre útil este artículo. Si tiene alguna dificultad o problema, no dude en hacérnoslo saber en el campo de comentarios a continuación.

Reserve una demostración en vivo con Mageworx