Creating your own product type

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.

Getting ready

Every product type has its own unique code specified, and it's important to use a short code to identify your product type.

How to do it…

The following steps in this recipe show you how to create a (minimal) new product type:

  1. First, we need to declare the 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>
  2. Now, we create 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)
      {
      }
    }
  3. To calculate the price based on the cost attribute, 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;
      }
    }
  4. By default, the cost attribute is only available for all product types; therefore, we need to add our product type to the 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)
              );
            }
          }
        }
      }
    }
  5. Specify the available product types that can be used to create an order:

    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>
  6. Optionally, it is possible to specify a custom renderer to create the 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>
  7. As we added a data upgrade script, it is necessary to increment 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>
  8. After this, run the upgrade command to update the attributes specified in the upgrade command. The cache is flushed at the same time to read the updated configuration.

How it works…

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:

How it works…

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:

How it works…

In the configuration of the new product type (in product_types.xml), it is also possible to specify the following items:

  • indexerModel: This is to specify a custom indexer for your product type
  • stockIndexerModel: This is to specify a custom indexer to manage the stock of your product type
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.72.15