In Magento 2, it is easy to add your own product type, which can be useful when you want to add some special features that are not available through the default product types. In this recipe, we will see a minimal new product type that calculates the price based on the cost of the product; you can easily extend it further to fit your own needs.
Every product type has its own unique code specified, and it's important to use a short code to identify your product type.
The following steps in this recipe show you how to create a (minimal) new product type:
etc/product_types.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Catalog:etc/product_types.xsd">
<type name="demo" label="Demo Product" modelInstance="GenmatoSampleModelProductTypeDemo" indexPriority="80" sortOrder="80">
<priceModel instance="GenmatoSampleModelProductTypeDemoPrice
" />
<customAttributes>
<attribute name="refundable" value="true"/>
<attribute name="taxable" value="true"/>
</customAttributes>
</type>
</config>
modelInstance
as configured in the product type definition; this is the minimal product type code definition. You can add your own functions that would be necessary to your product here:Model/Product/Type/Demo.php
<?php namespace GenmatoSampleModelProductType; use MagentoCatalogModelProductTypeAbstractType; class Demo extends AbstractType { /** * Product-type code */ const TYPE_CODE = 'demo'; /** * Delete data specific for Simple product-type * * @param MagentoCatalogModelProduct $product * @return void */ public function deleteTypeSpecificData(MagentoCatalogModelProduct $product) { } }
priceModel
is specified. This class holds the code to get the price of a product. Here, we use a fixed value of 1.25*cost attribute. It is also possible to get this value from another attribute or system configuration field:Model/Product/Type/Demo/Price.php
<?php namespace GenmatoSampleModelProductTypeDemo; use MagentoCatalogModelProductTypePrice as ProductPrice; class Price extends ProductPrice { /** * Default action to get price of product * * @param Product $product * @return float */ public function getPrice($product) { return $product->getData('cost')*1.25; } }
apply_to
field of the cost attribute. This will be done through an UpgradeData
script:Setup/UpgradeData.php
<?php namespace GenmatoSampleSetup; use MagentoEavSetupEavSetup; use MagentoEavSetupEavSetupFactory; use MagentoFrameworkSetupUpgradeDataInterface; use MagentoFrameworkSetupModuleContextInterface; use MagentoFrameworkSetupModuleDataSetupInterface; use MagentoCatalogModelProduct; /** * @codeCoverageIgnore */ class UpgradeData implements UpgradeDataInterface { /** * EAV setup factory * * @var EavSetupFactory */ private $eavSetupFactory; /** * Init * * @param EavSetupFactory $eavSetupFactory */ public function __construct(EavSetupFactory $eavSetupFactory) { $this->eavSetupFactory = $eavSetupFactory; } /** * {@inheritdoc} * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) { if (version_compare($context->getVersion(), '0.8.4', '<')) { /** @var EavSetup $eavSetup */ $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); $fieldList = [ 'price', 'special_price', 'special_from_date', 'special_to_date', 'minimal_price', 'cost', 'tier_price', 'weight', ]; // make these attributes applicable to demo product foreach ($fieldList as $field) { $applyTo = explode( ',', $eavSetup->getAttribute(Product::ENTITY, $field, 'apply_to') ); if (!in_array('demo', $applyTo)) { $applyTo[] = 'demo'; $eavSetup->updateAttribute( Product::ENTITY, $field, 'apply_to', implode(',', $applyTo) ); } } } } }
etc/sales.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Sales:etc/sales.xsd"> <order> <available_product_type name="demo"/> </order> </config>
Invoice
and Creditmemo
PDF documents:etc/pdf.xml
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Sales:etc/pdf_file.xsd"> <renderers> <page type="invoice"> <renderer product_type="demo">MagentoSalesModelOrderPdfItemsInvoiceDefaultInvoice</renderer> </page> <page type="creditmemo"> <renderer product_type="demo">MagentoSalesModelOrderPdfItemsCreditmemoDefaultCreditmemo</renderer> </page> </renderers> </config>
setup_version
in the module configuration. In this case, the version has been updated from 0.8.3
to 0.8.4
. This is used in the upgrade script to execute only if the installed version is lower than the new version.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="Genmato_Sample" setup_version="0.8.4"> <sequence> <module name="Magento_Store"/> </sequence> </module> </config>
upgrade
command to update the attributes specified in the upgrade
command. The cache is flushed at the same time to read the updated configuration.The new defined product type is now available in the backend to create a new product. The attributes used are similar to a simple product, and you can add your own fields if necessary. The priceModel
instance specified will calculate the product price on rendering on the frontend; in this case, the cost attribute is used and multiplied by 1.25.
While creating the product, it is possible to set the Cost attribute in the Advanced Pricing tab. In this example, we used a product cost of €25.00:
When the product is saved and requested on the frontend, the price will be calculated based on the preceding values and result in a final price of €31.25:
In the configuration of the new product type (in product_types.xml
), it is also possible to specify the following items:
18.227.72.15