---- EDIT #3 :
Please ignore the code in this question. The template tier.phtml
is not used by Magento 2.2.x (see edit #2)
The working code can be found here: Extra column in catalog_product_entity_tier_price not saving/updating in observer
---- EDIT #2 :
The problem I have found is that the tier.phtml doesn't seem to be used to create the advanced prices. Probably due to the following fact:
In Magento version 2.1, the product creation form was completely refactored and implemented using the form UI component.
see: https://devdocs.magento.com/guides/v2.2/howdoi/customize_product.html
It is instead created via the /module-catalog/Ui/DataProvider/Product/Form/Modifier/AdvancedPricing.php
, specifically the getTierPriceStructure
method. This is the reason none of the below codes ever worked. No var_dump() or die()'s ever had any effect anywhere. I've not found out where the tier.phtml is ever used.
I'll post an answer once I was able to modify the form.
// ---- END EDIT #2 :
I'm trying to overwrite the following template in the adminhtml backend:
module-catalog/view/adminhtml/templates/catalog/product/edit/price/tier.phtml
I first tried overwriting the template in a single module, this however did not work as expected. I then found the following post: How to override adminhtml phtml in magento 2?
which claims a custom admin theme is required, hence my code is as follows:
What I've done is the following on a clean install of Magento 2.2.3
- Create a custom module under
app/code/Vendor/CustomModule/
app/code/Vendor/CustomModule/registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Vendor_CustomModule',
__DIR__
);
Make sure my module is loaded after the theme in
app/code/Vendor/CustomModule/etc/module.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="Vendor_CustomModule" setup_version="1.0.0">
<sequence>
<module name="Magento_Theme"/>
</sequence>
</module>
</config>
Overwrite the Tier.php to set my custom template path:
app/code/Vendor/CustomModule/Block/Adminhtml/Product/Edit/Tab/Price/Tier.php
<?php
namespace Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab\Price;
/**
* Adminhtml tier price item renderer
*/
class Tier extends \Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Price\Tier
{
/**
* @var string
*/
protected $_template = 'Vendor_CustomModule::catalog/product/edit/price/tier.phtml';
}
Set preference in my di.xml and set my custom admin theme (created in point 2.)
app/code/Vendor/CustomModule/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">
<preference for="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Price\Tier"
type="Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab\Price\Tier" />
<!-- Admin theme. Start -->
<type name="Magento\Theme\Model\View\Design">
<arguments>
<argument name="themes" xsi:type="array">
<item name="adminhtml" xsi:type="string">Vendor/CustomAdminTheme</item>
</argument>
</arguments>
</type>
<!-- Admin theme. End -->
</config>
- Create a custom admin theme
app/design/adminhtml/Vendor/CustomAdminTheme/registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::THEME,
'adminhtml/Vendor/CustomAdminTheme',
__DIR__
);
app/design/adminhtml/Vendor/CustomAdminTheme/theme.xml
<theme xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Config/etc/theme.xsd">
<title>Vendor Custom Admin Theme</title>
<parent>Magento/backend</parent>
</theme>
and create my custom tier-price template for testing:
app/design/adminhtml/Vendor/CustomAdminTheme/Magento_Catalog/templates/catalog/product/edit/price/tier.phtml
<?php
// @codingStandardsIgnoreFile
/* @var $block \Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Price\Tier */
$element = $block->getElement();
?>
// THIS IS A TEST TEMPLATE!!
I have set 'MAGE_MODE' => 'developer'
and run setup:upgrade
and setup:di:compile
, yet my backend 'advanced pricing' template in Catalog -> new Product does not update.
Any ideas where I went wrong?
Official Documentation Used:
- http://devdocs.magento.com/guides/v2.2/frontend-dev-guide/themes/admin_theme_create.html
- http://devdocs.magento.com/guides/v2.2/frontend-dev-guide/themes/admin_theme_apply.html
---- EDIT ----
As per @murtuza-zabuawala I've removed the custom admin theme, created a Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab\Price.php
,Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab\Attributes
, Vendor\CustomModule\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes
and overwritten the hardcoded class name to use mine instead:
Vendor/CustomModule/Block/Adminhtml/Product/Edit/Tab/Price.php
<?php
namespace Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab;
class Price extends \Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Price
{
/**
* @throws \Magento\Framework\Exception\LocalizedException
*/
protected function _prepareForm()
{
$product = $this->_coreRegistry->registry('product');
/** @var \Magento\Framework\Data\Form $form */
$form = $this->_formFactory->create();
$fieldset = $form->addFieldset('tiered_price', ['legend' => __('Tier Pricing')]);
$fieldset->addField(
'default_price',
'label',
[
'label' => __('Default Price'),
'title' => __('Default Price'),
'name' => 'default_price',
'bold' => true,
'value' => $product->getPrice()
]
);
$fieldset->addField(
'tier_price',
'text',
['name' => 'tier_price', 'class' => 'requried-entry', 'value' => $product->getData('tier_price')]
);
$form->getElement(
'tier_price'
)->setRenderer(
$this->getLayout()->createBlock(\Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab\Price\Tier::class)
);
$this->setForm($form);
}
}
Vendor/CustomModule/Block/Adminhtml/Product/Edit/Tab/Attributes.php
<?php
namespace Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab;
/**
* @SuppressWarnings(PHPMD.DepthOfInheritance)
*/
class Attributes extends \Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Attributes
{
protected function _prepareForm()
{
/** @var $group \Magento\Eav\Model\Entity\Attribute\Group */
$group = $this->getGroup();
if ($group) {
/** @var \Magento\Framework\Data\Form $form */
$form = $this->_formFactory->create();
$product = $this->_coreRegistry->registry('product');
$isWrapped = $this->_coreRegistry->registry('use_wrapper');
if (!isset($isWrapped)) {
$isWrapped = true;
}
$isCollapsable = $isWrapped && $group->getAttributeGroupCode() == 'product-details';
$legend = $isWrapped ? __($group->getAttributeGroupName()) : null;
// Initialize product object as form property to use it during elements generation
$form->setDataObject($product);
$fieldset = $form->addFieldset(
'group-fields-' . $group->getAttributeGroupCode(),
['class' => 'user-defined', 'legend' => $legend, 'collapsable' => $isCollapsable]
);
$attributes = $this->getGroupAttributes();
$this->_setFieldset($attributes, $fieldset, ['gallery']);
$tierPrice = $form->getElement('tier_price');
if ($tierPrice) {
$tierPrice->setRenderer(
$this->getLayout()->createBlock(\Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab\Price\Tier::class)
);
}
// Add new attribute controls if it is not an image tab
if (!$form->getElement(
'media_gallery'
) && $this->_authorization->isAllowed(
'Magento_Catalog::attributes_attributes'
) && $isWrapped
) {
$attributeCreate = $this->getLayout()->createBlock(
\Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Attributes\Create::class
);
$attributeCreate->getConfig()->setAttributeGroupCode(
$group->getAttributeGroupCode()
)->setTabId(
'group_' . $group->getId()
)->setGroupId(
$group->getId()
)->setStoreId(
$form->getDataObject()->getStoreId()
)->setAttributeSetId(
$form->getDataObject()->getAttributeSetId()
)->setTypeId(
$form->getDataObject()->getTypeId()
)->setProductId(
$form->getDataObject()->getId()
);
$attributeSearch = $this->getLayout()->createBlock(
\Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Attributes\Search::class
)->setGroupId(
$group->getId()
)->setGroupCode(
$group->getAttributeGroupCode()
);
$attributeSearch->setAttributeCreate($attributeCreate->toHtml());
$fieldset->setHeaderBar($attributeSearch->toHtml());
}
$values = $product->getData();
// Set default attribute values for new product or on attribute set change
if (!$product->getId() || $product->dataHasChangedFor('attribute_set_id')) {
foreach ($attributes as $attribute) {
if (!isset($values[$attribute->getAttributeCode()])) {
$values[$attribute->getAttributeCode()] = $attribute->getDefaultValue();
}
}
}
if ($product->hasLockedAttributes()) {
foreach ($product->getLockedAttributes() as $attribute) {
$element = $form->getElement($attribute);
if ($element) {
$element->setReadonly(true, true);
$element->lock();
}
}
}
$form->addValues($values);
$form->setFieldNameSuffix('product');
$this->_eventManager->dispatch(
'adminhtml_catalog_product_edit_prepare_form',
['form' => $form, 'layout' => $this->getLayout()]
);
$this->setForm($form);
}
}
}
Vendor/CustomModule/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes.php
<?php
namespace Vendor\CustomModule\Block\Adminhtml\Catalog\Product\Edit\Tab;
class Attributes extends \Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes
{
protected function _prepareForm()
{
parent::_prepareForm();
$specialPrice = $this->getForm()->getElement('special_price');
if ($specialPrice) {
$specialPrice->setRenderer(
$this->getLayout()->createBlock(
\Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes\Special::class
)->setDisableChild(
false
)
);
$specialPrice->addClass(
implode(
' ',
[
'validate-greater-than-zero',
'validate-number-range',
'number-range-0.00-100.00'
]
)
);
}
$sku = $this->getForm()->getElement('sku');
if ($sku) {
$sku->setRenderer(
$this->getLayout()->createBlock(
\Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes\Extend::class
)->setDisableChild(
false
)
);
}
$price = $this->getForm()->getElement('price');
if ($price) {
$price->setRenderer(
$this->getLayout()->createBlock(
\Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes\Extend::class,
'adminhtml.catalog.product.bundle.edit.tab.attributes.price'
)->setDisableChild(
true
)
);
}
$tax = $this->getForm()->getElement('tax_class_id');
if ($tax) {
$tax->setAfterElementHtml(
'<script>' .
"
require(['prototype'], function(){
function changeTaxClassId() {
if ($('price_type').value == '" .
\Magento\Bundle\Model\Product\Price::PRICE_TYPE_DYNAMIC .
"') {
$('tax_class_id').disabled = true;
$('tax_class_id').value = '0';
$('tax_class_id').removeClassName('required-entry');
if ($('advice-required-entry-tax_class_id')) {
$('advice-required-entry-tax_class_id').remove();
}
} else {
$('tax_class_id').disabled = false;
" .
($tax->getRequired() ? "$('tax_class_id').addClassName('required-entry');" : '') .
"
}
}
if ($('price_type')) {
$('price_type').observe('change', changeTaxClassId);
changeTaxClassId();
}
});
" .
'</script>'
);
}
$weight = $this->getForm()->getElement('weight');
if ($weight) {
$weight->setRenderer(
$this->getLayout()->createBlock(
\Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes\Extend::class
)->setDisableChild(
true
)
);
}
$tier_price = $this->getForm()->getElement('tier_price');
if ($tier_price) {
$tier_price->setRenderer(
$this->getLayout()->createBlock(
\Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab\Price\Tier::class
)->setPriceColumnHeader(
__('Percent Discount')
)->setPriceValidation(
'validate-greater-than-zero validate-number-range number-range-0.00-100.00'
)
);
}
}
}
and I've added it to my di.xml
:
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes"
type="Vendor\CustomModule\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes" />
<preference for="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Attributes"
type="Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab\Attributes" />
<preference for="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Price"
type="Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab\Price" />
<preference for="Magento\Catalog\Block\Adminhtml\Product\Edit\Tab\Price\Tier"
type="Vendor\CustomModule\Block\Adminhtml\Product\Edit\Tab\Price\Tier" />
</config>
This however still does not seem to work. The complete module file structure now looks like this: