I am working on a module to add a product custom option input type (Derivated from file type).
In the backend under catalog / product / custom options, my new option is present in the "input type" list but when I select it, the associated fields are not displayed (Price, price type, sky, compatible file extension, etc).
I do not manage to find what is going on…
Thank you for your help,
My files :
app/code/A/Custoptiontype/etc/module.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="A_Custoptiontype" setup_version="1.0.0">
<sequence>
<module name="Magento_Catalog"/>
</sequence>
</module>
</config>
app/code/A/Custoptiontype/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">
<preference for="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Options\Option" type="A\Custoptiontype\Block\Adminhtml\Product\Edit\Tab\Options\Option"/>
<preference for="Magento\Catalog\Model\Product\Option" type="A\Custoptiontype\Model\Catalog\Product\Option"/>
</config>
app/code/A/Custoptiontype/etc/product_options.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Catalog:etc/product_options.xsd">
<option name="xfile" label="X File" renderer="A\Custoptiontype\Block\Adminhtml\Product\Edit\Tab\Options\Type\Xfile">
<inputType name="xfile" label="X File" />
</option>
</config>
app/code/A/Custoptiontype/Block/Adminhtml/Product/Edit/Tab/Options/Option.php
<?php
namespace A\Custoptiontype\Block\Adminhtml\Product\Edit\Tab\Options;
class Option extends \Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Options\Option
{
protected $_template = 'A_Custoptiontype::catalog/product/edit/options/option.phtml';
/**
* Class constructor
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Config\Model\Config\Source\Yesno $configYesNo,
\Magento\Catalog\Model\Config\Source\Product\Options\Type $optionType,
\Magento\Catalog\Model\Product $product,
\Magento\Framework\Registry $registry,
\Magento\Catalog\Model\ProductOptions\ConfigInterface $productOptionConfig,
array $data = []
)
{
parent::__construct(
$context,
$configYesNo,
$optionType,
$product,
$registry,
$productOptionConfig,
$data
);
}
/**
* Retrieve html templates for different types of product custom options
*
* @return string
*/
public function getTemplatesHtml()
{
$canEditPrice = $this->getCanEditPrice();
$canReadPrice = $this->getCanReadPrice();
$this->getChildBlock('xfile_option_type')
->setCanReadPrice($canReadPrice)
->setCanEditPrice($canEditPrice);
$templates = parent::getTemplatesHtml() . "\n" .
$this->getChildHtml('xfile_option_type');
return $templates;
}
}
app/code/A/Custoptiontype/Block/Adminhtml/Product/Edit/Tab/Options/Type/Xfile.php
<?php
namespace A\Custoptiontype\Block\Adminhtml\Product\Edit\Tab\Options\Type;
class Xfile extends \Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Options\Type\AbstractType
{
/**
* @var string
*/
protected $_template = 'A_Custoptiontype::catalog/product/edit/options/type/xfile.phtml';
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Catalog\Model\Config\Source\Product\Options\Price $optionPrice,
array $data = []
) {
$this->_optionPrice = $optionPrice;
parent::__construct($context, $optionPrice, $data);
}
}
app/code/A/Custoptiontype/view/adminhtml/templates/catalog/product/edit/options/option.phtml
<?php
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
// @codingStandardsIgnoreFile
?>
<?php /** @var $block \A\Custoptiontype\Catalog\Block\Adminhtml\Product\Edit\Tab\Options\Option */ ?>
<?php echo $block->getTemplatesHtml() ?>
<script id="custom-option-base-template" type="text/x-magento-template">
<div class="fieldset-wrapper admin__collapsible-block-wrapper opened" id="option_<%- data.id %>">
<div class="fieldset-wrapper-title">
<strong
class="admin__collapsible-title"
data-toggle="collapse"
data-target="#<%- data.id %>-content">
<span id="option_<%- data.id %>_header_title"><%- data.title %></span>
</strong>
<div class="actions">
<button type="button" title="<?php /* @escapeNotVerified */ echo __('Delete Custom Option'); ?>" class="action-delete" id="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>_delete">
<span><?php /* @escapeNotVerified */ echo __('Delete Custom Option'); ?></span>
</button>
</div>
<div id="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>_move" data-role="draggable-handle" class="draggable-handle"
title="<?php /* @escapeNotVerified */ echo __('Sort Custom Options'); ?>"></div>
</div>
<div class="fieldset-wrapper-content in collapse" id="<%- data.id %>-content">
<fieldset class="fieldset">
<fieldset class="fieldset-alt" id="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>">
<input id="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>_is_delete" name="<?php /* @escapeNotVerified */ echo $block->getFieldName() ?>[<%- data.id %>][is_delete]" type="hidden" value=""/>
<input id="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>_previous_type" name="<?php /* @escapeNotVerified */ echo $block->getFieldName() ?>[<%- data.id %>][previous_type]" type="hidden" value="<%- data.type %>"/>
<input id="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>_previous_group" name="<?php /* @escapeNotVerified */ echo $block->getFieldName() ?>[<%- data.id %>][previous_group]" type="hidden" value=""/>
<input id="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>_id" name="<?php /* @escapeNotVerified */ echo $block->getFieldName() ?>[<%- data.id %>][id]" type="hidden" value="<%- data.id %>"/>
<input id="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>_option_id" name="<?php /* @escapeNotVerified */ echo $block->getFieldName() ?>[<%- data.id %>][option_id]" type="hidden" value="<%- data.option_id %>"/>
<input name="<?php /* @escapeNotVerified */ echo $block->getFieldName() ?>[<%- data.id %>][sort_order]" type="hidden" value="<%- data.sort_order %>"/>
<div class="field field-option-title required">
<label class="label" for="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>_title">
<?php /* @escapeNotVerified */ echo __('Option Title') ?>
</label>
<div class="control">
<input id="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>_title"
name="<?php /* @escapeNotVerified */ echo $block->getFieldName() ?>[<%- data.id %>][title]"
class="required-entry input-text"
type="text"
value="<%- data.title %>"
data-store-label="<%- data.title %>"
<% if (typeof data.scopeTitleDisabled != 'undefined' && data.scopeTitleDisabled != null) { %> disabled="disabled" <% } %>
>
<%- data.checkboxScopeTitle %>
</div>
</div>
<div class="field field-option-input-type required">
<label class="label" for="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>_title">
<?php /* @escapeNotVerified */ echo __('Input Type') ?>
</label>
<div class="control opt-type">
<?php echo $block->getTypeSelectHtml() ?>
</div>
</div>
<div class="field field-option-req">
<div class="control">
<input id="<?php /* @escapeNotVerified */ echo $block->getFieldId() ?>_<%- data.id %>_required" class="is-required" type="checkbox" checked="checked"/>
<label for="field-option-req">
<?php /* @escapeNotVerified */ echo __('Required')?>
</label>
<span style="display:none"><?php echo $block->getRequireSelectHtml() ?></span>
</div>
</div>
</fieldset>
</fieldset>
</div>
</div>
</script>
<div id="import-container" style="display: none;"></div>
<?php if (!$block->isReadonly()): ?>
<div><input type="hidden" name="affect_product_custom_options" value="1"/></div>
<?php endif; ?>
<script>
require([
"jquery",
"Magento_Catalog/js/custom-options"
], function(jQuery){
jQuery(function ($) {
var fieldSet = $('[data-block=product-custom-options]');
fieldSet.customOptions(<?php /* @escapeNotVerified */ echo $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode(
[
'fieldId' => $block->getFieldId(),
'productGridUrl' => $block->getProductGridUrl(),
'formKey' => $block->getFormKey(),
'customOptionsUrl' => $block->getCustomOptionsUrl(),
'isReadonly' => $block->isReadonly(),
'itemCount' => $block->getItemCount(),
'currentProductId' => $block->getCurrentProductId(),
]
)?>);
//adding data to templates
<?php /** @var $_value \Magento\Framework\DataObject */ ?>
<?php foreach ($block->getOptionValues() as $_value): ?>
fieldSet.customOptions('addOption', <?php /* @escapeNotVerified */ echo $_value->toJson() ?>);
<?php endforeach; ?>
});
});
</script>
app/code/A/Custoptiontype/view/adminhtml/templates/catalog/product/edit/options/type/xfile.phtml
<?php
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
// @codingStandardsIgnoreFile
?>
<?php /** @var $block \A\Custoptiontype\Block\Adminhtml\Product\Edit\Tab\Options\Type\Xfile */ ?>
<h1>TOTOTOTOTO</h1>
<script id="custom-option-xfile-type-template" type="text/x-magento-template">
<div id="product_option_<%- data.option_id %>_type_<%- data.group %>" class="fieldset">
<table class="data-table">
<thead>
<tr>
<?php if ($block->getCanReadPrice() !== false) : ?>
<th><?php /* @escapeNotVerified */ echo __('Price'); ?></th>
<th><?php /* @escapeNotVerified */ echo __('Price Type'); ?></th>
<?php endif; ?>
<th><?php /* @escapeNotVerified */ echo __('SKU'); ?></th>
<th><?php /* @escapeNotVerified */ echo __('Compatible File Extensions'); ?></th>
<th><?php /* @escapeNotVerified */ echo __('Maximum Image Size'); ?></th>
</tr>
</thead>
<tr>
<?php if ($block->getCanReadPrice() !== false) : ?>
<td class="opt-price">
<input name="product[options][<%- data.option_id %>][price]" data-store-label="<%- data.price %>"
class="input-text validate-zero-or-greater" type="text" value="<%- data.price %>"
<?php if ($block->getCanEditPrice() === false) : ?>
disabled="disabled"
<?php endif; ?>>
</td>
<td class="opt-price-type"><?php echo $block->getPriceTypeSelectHtml('data-attr="price-type"') ?><%- data.checkboxScopePrice %></td>
<?php else : ?>
<input name="product[options][<%- data.option_id %>][price]" type="hidden">
<input id="product_option_<%- data.option_id %>_price_type" name="product[options][<%- data.option_id %>][price_type]" type="hidden">
<?php endif; ?>
<td>
<input name="product[options][<%- data.option_id %>][sku]" class="input-text" type="text" value="<%- data.sku %>">
</td>
<td>
<input name="product[options][<%- data.option_id %>][file_extension]" class="input-text" type="text" value="<%- data.file_extension %>">
</td>
<td class="col-file"><?php /* @escapeNotVerified */ echo __('%1 <span>x</span> %2 <span>px.</span>',
'<input class="input-text" type="text" name="product[options][<%- data.option_id %>][image_size_x]" value="<%- data.image_size_x %>">',
'<input class="input-text" type="text" name="product[options][<%- data.option_id %>][image_size_y]" value="<%- data.image_size_y %>">') ?>
<div class="note"><?php /* @escapeNotVerified */ echo __('Please leave blank if it is not an image.') ?></div>
</td>
</tr>
</table>
</div>
</script>
Best Answer
This is what I did to create a custom option type in Magento 2. For the new option type, I retained using the sku field but renamed it.
app/code/Testvendor/CustomOptions/etc/di.xml
app/code/Testvendor/CustomOptions/etc/product_options.xml
app/code/Testvendor/CustomOptions/Ui/DataProvider/Catalog/Product/Form/Modifier/CustomOptions.php
After this... I went in the bin directory and ran
./magento setup:upgrade ./magento setup:di:compile ./magento cache:flush ./magento cache:clean