Chapters Close

This piece of information will throw some light on how one can configure URL Rewrites in Magento 2.

When the rewrite goes into effect, any links that points to the previous URL are redirected to the new address. URL rewrites make the existing URLs more “search engine friendly” and also easier for humans to read.

Enabling Web Server Apache/Nginx Rewrites is a part of the initial Magento 2 store development setup. Magento 2 uses URL rewrites to remove the file name “index.php” that normally appears in the URL just after the root folder. When Web Server Rewrites are enabled, the system rewrites each URL to omit “index.php.” The rewrite removes words that convey nothing of value to the search engines or the customers.

How to enable URL rewrites?

Step 1:

In the Admin login go to path Stores > Configuration > Web.

Step 2:

After that, expand the Search Engine Optimization section.

Step 3:

Set Use Web Server Rewrites to ‘Yes’.

And save the config.

Set up automatic redirects

To set up automatic redirects we need to follow the steps given below:

Step 1:

In the Admin login go to path Stores > Configuration > Catalog > Catalog.

Step 2:

Expand the Search Engine Optimization section.

Set Create Permanent Redirect for URLs if URL Key Changed to “Yes.”  and save the config value.

Now to check the automatic redirection. Go to the product edit page from the admin section.

 In the URL Key field, perform the following steps:

  • Make sure that the Create Permanent Redirect for old URL checkbox is selected. 
  • Update the URL Key as needed, using all lowercase characters and hyphens. 
  • Save the product and test the product on the store frontend.
  • To view the redirect records, go to: Marketing > SEO & Search > URL Rewrites from the admin section. The most recent permanent redirects appear at the top of the list.

Using a Magento Extension

Managing URL rewrites can become tedious, especially when dealing with a large number of redirects. This is where the Bulk URL Redirection extension by Aureate Labs comes in.

The Bulk URL Redirection extension simplifies and streamlines the process of managing URL rewrites in your Magento 2 store.

Here’s how it streamlines your workflow:

  • Bulk Upload and Update: Effortlessly upload or copy-paste a large list of URLs for redirection. Update existing rewrites in bulk to save significant time and effort.
  • Simplified Management: Gain a centralized view of all your URL rewrites within a user-friendly interface.
  • Error Handling: The extension efficiently identifies and highlights potential errors in your URL configurations, preventing issues down the line.
  • Import/Export: Easily import and export URL rewrites in CSV format for seamless data migration and backup purposes.
  • Automation: Schedule automated tasks to keep your URL rewrites up-to-date, ensuring a smooth user experience for your customers.

By incorporating the Bulk URL Redirection extension, you’ll significantly reduce the time and effort required to manage URL rewrites in your Magento 2 store. This results in improved efficiency, better accuracy, and a more streamlined store management experience.

This article will help you to understand the dependency inversion principle in Magento 2.

Dependency inversion principle means that the high-level classes are not working directly with the low-level classes, they are using interfaces as an abstract layer.

In this case, the instantiation of new low-level objects inside the high-level classes (if needed) cannot be done utilizing the operator new. Instead, some of the Creational design patterns can be used, such as the Factory Method, Abstract Factory, Prototype.

This principle should not be implemented blindly for every class or module. If we have a class functionality that is more likely to remain consistent in the future there is no need to apply this principle.

By injecting the (low-level) dependencies, and using interfaces or abstract classes as types, you open up each class to a broader range of possibilities, since each type can be replaced by different implementations.

  • The Manager class doesn’t require any changes when adding SuperWorkers.
  • The risk to affect old functionality present in the Manager class is reduced as we don’t modify it.
  • No need to revise the unit testing for the Manager class.

Example:

Below is the code which supports the Dependency Inversion Principle.

In this new design, a new abstraction layer is added through the IWorker Interface.

// Dependency Inversion Principle - Good example
interface IWorker {
public void work();
}

class Worker implements IWorker{
public void work() {
   // ....working
}
}

class SuperWorker  implements IWorker{
public void work() {
   //.... working much more
}
}

class Manager {
IWorker worker;

public void setWorker(IWorker w) {
worker = w;
}

public void manage() {
worker.work();
  }
}

Now we will see an example of the Model class in Magento2 module Aureatelabs/InventoryLog.

app/code/Aureatelabs/InventoryLog/Model/Movement.php

namespace Aureatelabs\InventoryLog\Model;

use Aureatelabs\InventoryLog\Api\Data\MovementInterface;

class Movement extends \Magento\Framework\Model\AbstractModel implements MovementInterface
{

   /**
    * @return void
    */
   protected function _construct()
   {
       $this->_init('Aureatelabs\InventoryLog\Model\ResourceModel\Movement');
   }

   /**
    * Get movement_id
    * @return string
    */
   public function getMovementId()
   {
       return $this->getData(self::MOVEMENT_ID);
   }

   /**
    * Set movement_id
    * @param string $movementId
    * @return \Aureatelabs\InventoryLog\Api\Data\MovementInterface
    */
   public function setMovementId($movementId)
   {
       return $this->setData(self::MOVEMENT_ID, $movementId);
   }
…..

}

Now for the interface,

app/code/Aureatelabs/InventoryLog/Api/Data/MovementInterface.php

namespace Aureatelabs\InventoryLog\Api\Data;

interface MovementInterface
{
   const MOVEMENT_ID = 'movement_id';
   
   /**
    * Get movement_id
    * @return string|null
    */
   public function getMovementId();

   /**
    * Set movement_id
    * @param string $movementId
    * @return \Aureatelabs\InventoryLog\Api\Data\MovementInterface
    */
   public function setMovementId($movementId);

}

If you’re familiar with the Magento basic fundamentals then you certainly know Magento has been developed to show a variety of prices to your buyers. And below is the bunch of all prices that have their own explanation:

  1. Special Price.
  2. Tier Price.
  3. Grouped Price.
  4. The minimum price of composite products
  5. The price range of composite products
  6. Manufacturer price (MSRP)

Magento represents these prices as price types (e.g. final price, minimum price, maximum price, regular price) and is separate from the actual price in the code. For example, Special Price is represented by the final price type in the code and uses a separate template for each price(e.g. final_price.phtml, tier_price.phtml, default.phtml).

Hence being one of the top Magento web development companies, we wrote a custom module that will show you how to use custom price templates for related product lists. For that, you need to override module-catalog/view/base/templates/product/price/final_price.phtml

Step 1: Create a sample module

Create a new module named PriceTemplate under app/code/Aureatelabs/. Then include the needed registration.php and module.xml files.

File:  app/code/Aureatelabs/PriceTemplate/registration.php

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

File: app/code/Aureatelabs/PriceTemplate/etc/module.xml

 
 
 
Copy Code
<?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="Aureatelabs_PriceTemplate" setup_version="1.0.0"/>
</config>

Run below command to enable the created module.

 
 
 
Copy Code
php bin/magento module:enable Aureatelabs_PriceTemplate
php bin/magento setup:upgrade

Step 2: Create a block

Create a new Aureatelabs\PriceTemplate\Pricing\Render block in our modules layout file catalog_product_view.xml.

File: app/code/Aureatelabs/PriceTemplate/view/frontend/layout/catalog_product_view.xml

 
 
 
Copy Code
<?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>
       <block class="Aureatelabs\PriceTemplate\Pricing\Render" name="product.price.render.custom">
           <arguments>
               <argument name="price_render_handle" xsi:type="string">custom_catalog_product_prices</argument>
               <argument name="use_link_for_as_low_as" xsi:type="boolean">true</argument>
               <!-- set "override" configuration settings here -->
           </arguments>
       </block>
   </body>
</page>

Step 3: Add new price render handle

As we define custom price render handle custom_catalog_product_prices in step 2, now we need to create that handle as below.

File: app/code/Aureatelabs/PriceTemplate/view/frontend/layout/custom_catalog_product_prices.xml

 
 
 
Copy Code
<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
   <block class="Magento\Framework\Pricing\Render\RendererPool" name="render.product.prices.custom">
       <arguments>
           <argument name="default" xsi:type="array">
               <item name="default_render_class" xsi:type="string">Magento\Catalog\Pricing\Render\PriceBox</item>
               <item name="default_render_template" xsi:type="string">Magento_Catalog::product/price/default.phtml</item>
               <item name="default_amount_render_class" xsi:type="string">Magento\Framework\Pricing\Render\Amount</item>
               <item name="default_amount_render_template" xsi:type="string">Magento_Catalog::product/price/amount/default.phtml</item>
               <item name="prices" xsi:type="array">
                   <item name="final_price" xsi:type="array">
                       <item name="render_class" xsi:type="string">Magento\Catalog\Pricing\Render\FinalPriceBox</item>
                       <item name="render_template" xsi:type="string">Aureatelabs_PriceTemplate::product/price/final_price_related_product.phtml</item>
                   </item>
               </item>
           </argument>
       </arguments>
   </block>
</layout>

Step 4: Create Price Render class

As mentioned in step 2, Block type of product.price.render.custom is Aureatelabs\PriceTemplate\Pricing\Render

Hence create the same class and extend Magento\Framework\Pricing\Render

File: app/code/Aureatelabs/PriceTemplate/Pricing/Render.php

 
 
 
Copy Code
<?php

namespace Aureatelabs\PriceTemplate\Pricing;

use Magento\Framework\Pricing\SaleableInterface;

/**
* Base price render
*
* @api
* @method string getPriceRenderHandle()
*
* @api
*/
class Render extends \Magento\Framework\Pricing\Render
{
   /**
    * Render price
    *
    * @param string $priceCode
    * @param SaleableInterface $saleableItem
    * @param array $arguments
    * @return string
    * @throws \InvalidArgumentException
    * @throws \RuntimeException
    */
   public function render($priceCode, SaleableInterface $saleableItem, array $arguments = [])
   {
       $useArguments = array_replace($this->_data, $arguments);

       /** @var \Magento\Framework\Pricing\Render\RendererPool $rendererPool */
       $rendererPool = $this->priceLayout->getBlock('render.product.prices.custom');
       if (!$rendererPool) {
           throw new \RuntimeException('Wrong Price Rendering layout configuration. Factory block is missed');
       }

       // obtain concrete Price Render
       $priceRender = $rendererPool->createPriceRender($priceCode, $saleableItem, $useArguments);
       return $priceRender->toHtml();
   }
}

Here we’ve layout render.product.prices.custom block which was defined previously in catalog_product_view.xml file of our module.

As we want to change the price template for only related product only, now we need to override \Magento\Catalog\Block\Product\ProductList\Related, so first create a preference in di.xml file.

File: app/code/Aureatelabs/PriceTemplate/etc/frontend/di.xml

 
 
 
Copy Code
<?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\Product\ProductList\Related" type="Aureatelabs\PriceTemplate\Block\Product\ProductList\Related"/>
</config>

Here we’ve told Magento whenever someone requests that the object manager instantiate an Aureatelabs\PriceTemplate\Block\Product\ProductList\Related object instead of Magento\Catalog\Block\Product\ProductList\Related object.

So, create a block class in our module.

File: app/code/Aureatelabs/PriceTemplate/Block/Product/ProductList/Related.php

 
 
 
Copy Code
<?php
namespace Aureatelabs\PriceTemplate\Block\Product\ProductList;

class Related extends \Magento\Catalog\Block\Product\ProductList\Related
{
   /**
    * Return HTML block
    *
    * @param \Magento\Catalog\Model\Product $product
    * @param string $priceType
    * @param string $renderZone
    * @param array $arguments
    * @return string
    * @throws \Magento\Framework\Exception\LocalizedException
    */
   public function getProductPriceHtml(
       \Magento\Catalog\Model\Product $product,
       $priceType,
       $renderZone = \Magento\Framework\Pricing\Render::ZONE_ITEM_LIST,
       array $arguments = []
   ) {
       if (!isset($arguments['zone'])) {
           $arguments['zone'] = $renderZone;
       }

       /** @var \Magento\Framework\Pricing\Render $priceRender */
       $priceRender = $this->getLayout()->getBlock('product.price.render.custom');
       $price = '';

       if ($priceRender) {
           $price = $priceRender->render($priceType, $product, $arguments);
       }
       return $price;
   }
}

Step 6: Create a custom template file

Now, the final step is to create a custom template for the final price and do changes as per your requirement.

File: app/code/Aureatelabs/PriceTemplate/view/frontend/templates/product/price/final_price_related_product.phtml

 
 
 
Copy Code
<?php
// @codingStandardsIgnoreFile
?>

<?php
/** @var \Magento\Catalog\Pricing\Render\FinalPriceBox $block */

$productId = $block->getSaleableItem()->getId();
//$currentProductId = $block->getRequest()->getParam('id');

/** ex: \Magento\Catalog\Pricing\Price\RegularPrice */
/** @var \Magento\Framework\Pricing\Price\PriceInterface $priceModel */
$priceModel = $block->getPriceType('regular_price');

/** ex: \Magento\Catalog\Pricing\Price\FinalPrice */
/** @var \Magento\Framework\Pricing\Price\PriceInterface $finalPriceModel */
$finalPriceModel = $block->getPriceType('final_price');
$idSuffix = $block->getIdSuffix() ? $block->getIdSuffix() : '';
$schema = ($block->getZone() == 'item_view') ? true : false;
?>
<?php if ($block->hasSpecialPrice()): ?>
   <span class="special-price">
       <?php /* @escapeNotVerified */ echo $block->renderAmount($finalPriceModel->getAmount(), [
           'display_label'     => __('Special Price'),
           'price_id'          => $block->getPriceId('product-price-' . $idSuffix),
           'price_type'        => 'finalPrice',
           'include_container' => true,
           'schema' => $schema
       ]); ?>
   </span>
<?php else: ?>
   <?php /* @escapeNotVerified */ echo $block->renderAmount($finalPriceModel->getAmount(), [
       'price_id'          => $block->getPriceId('product-price-' . $idSuffix),
       'price_type'        => 'finalPrice',
       'include_container' => true,
       'schema' => $schema
   ]); ?>
<?php endif; ?>

<?php if ($block->showMinimalPrice()): ?>
   <?php if ($block->getUseLinkForAsLowAs()):?>
       <a href="<?= /* @escapeNotVerified */ $block->getSaleableItem()->getProductUrl() ?>" class="minimal-price-link">
           <?= /* @escapeNotVerified */ $block->renderAmountMinimal() ?>
       </a>
   <?php else:?>
       <span class="minimal-price-link">
           <?= /* @escapeNotVerified */ $block->renderAmountMinimal() ?>
       </span>
   <?php endif?>
<?php endif; ?>

Conclusion

In this way, you’re done with the successful module building to change price templates for related products only. In case you’re stuck in between and need any help in this regard, we’re all glad to help you. Feel free to contact us.

In this article, I’ve shown you how to change price templates for related products step by step. If you still need any help regarding the price template or Magento, we are happy to help you. Feel free to get in touch!

Also read: Set custom price programmatically in Magento 2

FAQs

How do I change price in Magento?


To change price in Magento, follow the below steps:
1. Login to the admin dashboard.
2. Click on the “Catalog” menu and open the “Manage products” page.
3. Click on the product whose price you want to edit.
4. In the blank labeled “Price,” write the updated price. 
5. Click the save button at the button to save the new price.
You can also change the price of multiple products at once by clicking on the “Actions” button at the top.

What is final price in magento2?


The final price in Magento 2 is the base price of the product plus any additional costs or discounts. It can be higher or lower than the base price and is the cost customers pay while making the final purchase of the product. Usually, final price = base price + tax +shipping +other costs – discounts.

How to override Final_price Phtml in Magento 2?


To override final_price.phtml in Magento 2, follow these steps:

1. Create Vendor Module as app/code/Vendor/Extension/etc/di.xml
 <type name="Magento\Catalog\Pricing\Render\FinalPriceBox">
        <plugin name="override_price_block" type="Vendor\Extension\Plugin\FinalPricePlugin" />
</type>

2. Next, create the Plugin file in Vendor Module as app/code/Vendor/Extension/Plugin/FinalPricePlugin.php -
<?php
namespace Vendor\Extension\Plugin;
class FinalPricePlugin
{
    public function beforeSetTemplate(\Magento\Catalog\Pricing\Render\FinalPriceBox $subject, $template)
    {
        if ($template == 'Magento_Catalog::product/price/final_price.phtml') {
           return ['Vendor_Extension::product/price/final_price.phtml'];
        } 
        else
        {
            return [$template];
        }
    }
}

3. Further, create a new template file in Vendor Module as app/code/Vendor/Extension/view/frontend/templates/product/price/final_price.phtml.
4. Now, copy the content of the default template file you want to override and make the required changes.

How do I add custom text under the price in frontend?


To add custom text under the price on the front end, you can use a plugin by following the below-mentioned steps –

1. Create a Custom Price Module as app/code/CustomPriceText/etc/di.xml
<type name="Magento\Catalog\Pricing\Render\PriceBox">
<plugin name="add_custom_text_under_price" type="CustomPriceText\Pricing\Plugin\AddCustomTextUnderPrice"/>
</type>

2. Next, create a Plugin folder under the Custom Price Module as app/code/CustomPriceText/Pricing/Plugin.
3. Now, create AddCustomTextUnderPrice.php in the above folder and use the code – 
<?php
namespace CustomPriceText\Pricing\Plugin;
use Magento\Framework\View\Element\Template;
class AddCustomTextUnderPrice
{
    public function afterToHtml(Template $subject, $result)
    {
        $customText = "Custom Text";
        $result .= "<div>{$customText}</div>";
        return $result;
    }
}

4. Refresh the cache and run the setup:upgrade command.

What to read next?? Know How to Add Custom Validation Rule in Magento 2?

Table of Contents

To Display description in wishlist you have to follow the steps given below:

Step 1

Create a new file wishlist_index_index.xml at location: <root>\app\design\frontend\Companyname\Packagename\Magento_Wishlist\layout\wishlist_index_index.xml

<body>
<referenceBlock name="customer.wishlist.items">
<block class="Companyname\Packagename\Block\Description" name="customer.wishlist.item.description" template="Magento_Wishlist::item/column/description.phtml" cacheable="false" after="customer.wishlist.item.name"/>
</referenceBlock>
</body>

Step 2

Create a new file description.phtml at location: <root>\app\design\frontend\Companyname\Packagename\Magento_Wishlist\templates\item\column\description.phtml

<?php 
$item = $block->getItem(); 
$product = $item->getProduct(); 
?> 
<strong class="product-item-description"> 
<?php echo $block->escapeHtml($product->getDescription()) ?> 
</strong>

Step 3

Create a new file Description.php at location: <root>\app\code\Companyname\Packagename\Block\Description.php

<?php
namespace Companyname\Packagename\Block;
class Description extends \Magento\Wishlist\Block\Customer\Wishlist\Item\Column\Info
{
 /**
    * @var \Magento\Catalog\Api\ProductRepositoryInterface 
  */
protected $productRepository;

public function __construct(
\Magento\Catalog\Block\Product\Context $context,
\Magento\Framework\App\Http\Context $httpContext,
array $data = [],
\Magento\Catalog\Api\ProductRepositoryInterface $productRepository
) {
$this->productRepository = $productRepository;
parent::__construct($context, $httpContext, $data);
}

public function getDescription()
{
$id = $this->getItem()->getProduct()->getId();
$product = $this->productRepository->getById($id);
return $product->getDescription();
}
}

Note:- Do not make changes in the core files, add it in your theme directory

Step 4

In layout file replace block class from Magento\Wishlist\Block\Customer\Wishlist\Item\Column\Info to Companyname\Packagename\Block\Description

After that in your template file, you can get product description using the code given below:

Finally, run the commands given below to make changes effective:

php bin/magento setup:di:compile
php bin/magento setup:static-content:deploy en_US -f
php bin/magento cache:clean
php bin/magento cache:flush

Feel free to leave the comments below and contact us if you need any help to customize your Magento store.

Happy coding!

Variables are pieces of information that can be created once and can be used in multiple places, such as email templates, blocks, and content pages. There are two kinds of variables: Predefined Variables & Custom Variables.

So, when we develop an e-commerce store on Magento, it includes a large number of predefined variables that can be used to personalize communications. Below are the default variables that can be added:

The list of default variables is limited. In addition, we can create our own custom variables.

Now, We will learn how to add predefined variables.

Step 1 : 

Choose the template where you want to add variables. It can be email template or page template.

Example: To add variables to email templates.
Firstly, navigate to Marketing > Communications > Email Templates. Then choose the template where you want to add the variables to (or create new templates).

Step 2 :

Firstly, navigate to Marketing > Communications > Email Templates. Then choose the template where you want to add the variables to.

Step 3 :

To create a custom variable, we need to do the following: 
Go to System > Other Settings > Custom Variables.

After the page loads, you need to click on the add variable button.

Then Enter the custom variable information.

  • In the Variable Code field, Enter an identifier and use all lowercase characters, without spaces.
  • Enter a Variable Name, which is used for internal reference.
  • In the Variable HTML Value text field, enter any content you want to include, using basic HTML tags. This option allows you to format the value.
  • In the Variable Plain Value field, enter the variable value as plain text.

This way you can add custom as well as default variable in the page, block and email templates.

Related resources:

Widgets are elements for adding static or dynamic content in any cms block and cms page in magento 2. Widgets have configurable parameters that can be set when you are adding the widget in the admin panel. Widgets are reusable component and with configurable parameter you can use the same widget in different number of pages with different parameter value.

Some of the custom widget implementation is as follows:

  • Dynamic listing of recently viewed products
  • Dynamic product listing
  • Dynamic flash elements that are inserted in content pages
  • Interactive navigation elements and action blocks
  • Promotional banners

For creating custom widget you have to create one module. Here I will be using the Aureatelabs_CustomWidget as my module.

Create the registration.php file in the app/code/Aureatelabs/CustomWidget folder.

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
   \Magento\Framework\Component\ComponentRegistrar::MODULE,
   'Aureatelabs_CustomWidget',
   __DIR__
);

Create the module.xml file in the app/code/Aureatelabs/CustomWidget/etc folder.

<?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="Aureatelabs_CustomWidget" setup_version="1.0.0" />
</config>

Now for initialisation of the widget we need a widget.xml file. So next you need to do is create the widget.xml file in the app/code/Aureatelabs/CustomWidget/etc folder.

<?xml version="1.0" encoding="UTF-8"?>
<widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Widget:etc/widget.xsd">
   <widget class="Aureatelabs\CustomWidget\Block\Widget\CustomWidget" id="aureatelabs_customwidget">
       <label>Aureatelabs Custom Widget</label>
       <description>Aureatelabs Custom Widget Example</description>
       <parameters>
           <parameter name="title" sort_order="10" visible="true" xsi:type="text">
               <label>Title</label>
           </parameter>
       </parameters>
   </widget>
</widgets>

Here in the widget node there are two attributes

  • class : Defines the widget class
  • id : Gives custom widget an unique id

In widget node there are child nodes such as:

  • label : Sets the widget label that will appear in the widget list
  • description : Sets widget description
  • parameters :  The parameters node allows you to add different parameters like the text, select, multiselect, block and templates. We will discuss further about this later in this tutorial.

Now we have to create a block file for the widget as defined in widget.xml. So create the CustomWidget.php file in the app/code/Aureatelabs/CustomWidget/Block/Widget folder.

<?php
namespace Aureatelabs\CustomWidget\Block\Widget;

use Magento\Framework\View\Element\Template;
use Magento\Widget\Block\BlockInterface;

class CustomWidget extends Template implements BlockInterface
{
   protected $_template = "widget/custom_widget.phtml";

}

In the above snippet, $_template is used to set the template for the widget. 

We have set the $_template value to “widget/custom_widget.phtml”. So it will search for the custom_widget.phtml file in the  app/code/Aureatelabs/CustomWidget/view/frontend/templates/widget folder.

Thus create the custom_widget.phtml file in the app/code/Aureatelabs/CustomWidget/view/frontend/templates/widget folder.

<h1><?php echo $this->getData('title'); ?></h1>

In order to get the parameter value from the phtml file we have to use $this->getData(‘parameter_name’)

It is important to note that we can also use this in block file for getting the parameter value.

We have performed all the steps that are needed to create a custom widget in magento 2 . Now we have to just Flush the cache and add our custom widget in any cms page or any cms block.

You will see the “Aureatelabs Custom Widget” in the widget list.

We have created a simple custom widget in magento 2. For advanced information about custom widgets refer the section given below.

How to add the select and multiselect parameters in the custom widget

In order to add the select and multiselect options in the  widget, you have to add the parameters given below in the widget.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Widget:etc/widget.xsd">
   <widget class="Aureatelabs\CustomWidget\Block\Widget\CustomWidget" id="aureatelabs_customwidget">
       <label>Aureatelabs Custom Widget</label>
       <description>Aureatelabs Custom Widget Example</description>
       <parameters>
           <parameter name="options" xsi:type="select" visible="true" source_model="Aureatelabs\CustomWidget\Model\Config\Source\DataOptions" sort_order="20" >
               <label>Select options</label>
               <description>Select options</description>
           </parameter>
           <parameter name="data_options" xsi:type="multiselect" visible="true" source_model="Aureatelabs\CustomWidget\Model\Config\Source\DataOptions" sort_order="40" >
               <label>Data Options</label>
               <description>Select data options </description>
           </parameter>
       </parameters>
   </widget>
</widgets>

Here, in parameter node in xsi:type attribute, set the value to select or multiselect.

There is one more attribute named the source_model. It is used in the  select and multiselect widget parameter.

Now you have to create a source file for the select and multiselect parameter.So create a DataOptions.php file in the app/code/Aureatelabs/CustomWidget/Model/Config/Source folder

<?php
namespace Aureatelabs\CustomWidget\Model\Config\Source;

use Magento\Framework\Option\ArrayInterface;

class DataOptions implements ArrayInterface
{
   public function toOptionArray()
   {
       $options = [
           [
               'value' => 'option1',
               'label' => __('Option-1')
           ],
           [
               'value' => 'option2',
               'label' => __('Option-2')
           ],
           [
               'value' => 'option3',
               'label' => __('Option-3')
           ],
       ];

       return $options;
   }
}

Dependency in Widget Parameter

Depends attribute is used when one parameter is dependent on the other parameter.

<?xml version="1.0" encoding="UTF-8"?>
<widgets xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Widget:etc/widget.xsd">
   <widget class="Aureatelabs\CustomWidget\Block\Widget\CustomWidget" id="aureatelabs_customwidget">
       <label>Aureatelabs Custom Widget</label>
       <description>Aureatelabs Custom Widget Example</description>
       <parameters>
           <parameter name="enable_url" xsi:type="select" visible="true" source_model="Magento\Config\Model\Config\Source\Yesno" sort_order="20" >
               <label>Add URL</label>
               <description>Enable or disable URL link </description>
           </parameter>
           <parameter name="url" xsi:type="text" visible="true" sort_order="30" >
               <label>URL</label>
               <depends>
                   <parameter name="enable_url" value="1" />
               </depends>
           </parameter>
       </parameters>
   </widget>
</widgets>

In above example url parameter is dependent on the enable_url parameter. When enable_url value is set to 1, then the url parameter will be displayed or else the url parameter will not be shown.

In this post we will guide you how to add a new custom tab in the product detail page in magento2.

To start with create a file ‘catalog_product_view.xml’ in the app/code/<VendorName>/<ModuleName>/view/frontend/layout folder.

<?xml version="1.0"?>
<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
   <body>
       <referenceBlock name="product.info.details">
           <block class="Magento\Catalog\Block\Product\View" name="custom.tab" template="Aureatelabs_Training::custom_tab.phtml" group="detailed_info" >
               <arguments>
                   <argument translate="true" name="title" xsi:type="string">Custom Tab</argument>
               </arguments>
           </block>
       </referenceBlock>
   </body>
</page>

Change “Aureatelabs_Training” with <VendorName>_<ModuleName> in the catalog_product_view.xml

Now create the custom_tab.phtml file in app/code/<VendorName>/<ModuleName>/view/frontend/layout folder and add the below snippet in the phtml file.

<?php

echo "This is Custom tab in product detail page";

?>

Now you can check your product detail page on frontend.

Custom Tab

Show product details in custom tab

You can show product data on custom tab in product detail page. In order to do this you have to make the below changes in the custom_tab.phtml file.

<?php
// get current product data
$product = $block->getProduct();

// get Product name
echo $product->getName();

// get product description
echo $product->getDescription();

// Get custom product attribute value, change ‘custom_product_attribute’ with your ‘product attribute code’
echo $product->getData('custom_product_attribute');

?>

$block->getProduct() will get current product data.

In custom_product_attribute you can add custom attribute code to get custom attribute data for current product.

Show static block in custom tab

You can show static block data on custom tab in product detail page. To do this you have to make the below change in the custom_tab.phtml file.

<?php

echo $this->getLayout()
   ->createBlock('Magento\Cms\Block\Block')
   ->setBlockId('your_block_identifier')
   ->toHtml();

?>

Hope this article helped you to create a custom tab on product detail page in Magento 2.

By default, Magento 2 provides 6 product types including simple, grouped, configurable, virtual, bundled and downloadable having unique behaviours and attributes. These default product types cover the majority of the E-commerce needs by supporting the wide range of requirements.

There may arise circumstances when you may be not satisfied with the available types and your products might not be suitable for those default product types.

In general, when a product class has distinct behaviour or attributes, it should be represented by its own custom product type. This allows the product type to have complex and custom logic and presentation, with no impact on other product types, ensuring that default product types can continue to function as intended.

In this post, I will be guiding you on how to create a new Magento 2 product type.

Module Registration File

Create the app/code/Aureatelabs/NewProductType/registration.php file

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
   \Magento\Framework\Component\ComponentRegistrar::MODULE,
   'Aureatelabs_NewProductType',
   __DIR__
);

Config XML

Create the app/code/Aureatelabs/NewProductType/etc/module.xml file

<?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="Aureatelabs_NewProductType" setup_version="1.0.0" />
</config>

Defining a custom product type involves an XML declaration of product_types.xml.

Create the app/code/Aureatelabs/NewProductType/etc/product_types.xml file

<?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="new_product_type" label="New Product Type" modelInstance="Aureatelabs\NewProductType\Model\Product\Type\NewProductType" indexPriority="60" sortOrder="80" isQty="true">
   </type>
</config>

In type, the node has three required attributes.

  • name: new product type code
  • label: new product type name
  • modelInstance: new product type model

You can also specify the below attributes

  • indexPriority: priority index
  • isQty: whether it has a quantity
  • sortOrder: position number in the sort list

Although there are many other nodes and attributes that can influence the product type definition, this is an illustration of the simplest case.

Also, we are capable to override such internal models:

  • priceModel: the model of a price
  • indexerModel: the model of indexing logic
  • stockIndexerModel: the model of stock indexing

Product Type Model

Each product type instance is associated with an instance of the corresponding product type model. This model has the opportunity to modify product type behaviour and attributes and is called during several product manipulation processes. In short, you can apply your custom logic in the product type model.

Create the app/code/Aureatelabs/NewProductType/Model/Product/Type/NewProductType.php file

<?php

namespace Aureatelabs\NewProductType\Model\Product\Type;

class NewProductType extends \Magento\Catalog\Model\Product\Type\AbstractType {

   /**
    * Delete data specifically for new product type
    *
    * @param \Magento\Catalog\Model\Product $product
    * @return void
    */
   public function deleteTypeSpecificData(\Magento\Catalog\Model\Product $product)
   {
        // method intentionally empty
   }

}

A product model must inherit from the \Magento\Catalog\Model\Product\Type\AbstractType class. This class has only one abstract method and it is deleteTypeSpecificData. This specific method is called while saving a product instance if its type has changed, and gives the original product type the opportunity to clean up any type-specific data before the type change is finalized.

Unless the new custom product type has such type-specific data, the method can be overridden with an empty method.

Core Product Types

It’s often the case that a custom product type behaves like and has similar requirements for a core product type. In that case, it will be useful to extend one of the core product types instead of the abstract type directly.

The following product type classes are available in the core Magento.

  • Simple: \Magento\Catalog\Model\Product\Type\Simple
  • Virtual: \Magento\Catalog\Model\Product\Type\Virtual
  • Configurable: \Magento\ConfigurableProduct\Model\Product\Type\Configurable
  • Grouped: \Magento\GroupedProduct\Model\Product\Type\Grouped
  • Downloadable: \Magento\Downloadable\Model\Product\Type
  • Bundle: \Magento\Bundle\Model\Product\Type
  • Giftcard (Enterprise Edition Only): \Magento\GiftCard\Model\Catalog\Product\Type\Giftcard

Result

Once the product type is declared in XML and its associated product type model is created, products of the new type can be shown in the admin.

Additional Steps

Having successfully created a new product type, now there are some general steps (optional) to utilize it.

Associate With Common Attributes

Since product attributes can be scoped to relevant product types, any core attributes which are already scoped will not apply to the new product type. Thus attributes that are indeed relevant will need to be associated with the new product type. Hence you have to create one Install data script in order to make these changes.

Create the app/code/Aureatelabs/NewProductType/Setup/InstallData.php file

<?php
namespace Aureatelabs\NewProductType\Setup;

use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;


class InstallData implements InstallDataInterface
{
   private $eavSetupFactory;

   public function __construct(EavSetupFactory $eavSetupFactory)
   {
       $this->eavSetupFactory = $eavSetupFactory;
   }

   public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
   {
       /** @var EavSetup $eavSetup */
       $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);

       //associate these attributes with new product type
       $fieldList = [
           'price',
           'special_price',
           'special_from_date',
           'special_to_date',
           'minimal_price',
           'cost',
           'tier_price',
           'weight',
       ];
       // make these attributes applicable to new product type
       foreach ($fieldList as $field) {
           $applyTo = explode(
               ',',
               $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field, 'apply_to')
           );
           if (!in_array('new_product_type', $applyTo)) {
               $applyTo[] = 'new_product_type';
               $eavSetup->updateAttribute(
                   \Magento\Catalog\Model\Product::ENTITY,
                   $field,
                   'apply_to',
                   implode(',', $applyTo)
               );
           }
       }
   }
}

Composite Products

When you are adding child products to a composite product type like configurable, grouped or bundle, it will only show products where the associated product type has explicitly declared its eligibility to be the child of a composite product.

So new product types can allow themselves to be children of composite product types by adding a composableTypes node in product_types.xml

Create app/code/Aureatelabs/NewProductType/etc/product_types.xml file.

<?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="new_product_type" label="New Product Type" modelInstance="Aureatelabs\NewProductType\Model\Product\Type\NewProductType" indexPriority="60" sortOrder="80" isQty="true">
   </type>
   <composableTypes>
       <type name="new_product_type" />
   </composableTypes>
</config>

Custom Attributes Node

The customAttributes nodes can be used when Magento wants to get a list of product types that comply with the condition.

<?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="new_product_type" label="New Product Type" modelInstance="Aureatelabs\NewProductType\Model\Product\Type\NewProductType" indexPriority="60" sortOrder="80" isQty="true">
       <customAttributes>
           <attribute name="refundable" value="true"/>
       </customAttributes>
   </type>
</config>

Inside this node, we can declare some attributes nodes:

  • refundable: It will check the product type, it can be refunded or not. By default Magento CE, the downloadable and virtual product cannot be refunded (In Magento EE added Gift product). The product type in sales order item table will be used for checking the refundable product.
  • taxable: It will check the product type, it is taxable or not.
  • Is_real_product: It is used for checking “it is a real product or not”. Group product, Downloadable Product, Virtual Product are not real products.
  • is_product_set: checks whether product type is a set of products. In group product is_product_set value is set to true.

Customize Product type models

Creating a new product type is only the beginning. Now that it’s defined, the new product type provides an enormous capacity for scoped customization.

Product Type Model Methods

The behaviour of products can be significantly influenced by overriding methods in the product type model. This allows custom logic to be applied within the product type. So you don’t have to create any observer or plugin to do that.

Some examples of such methods:

  • beforeSave() : This method runs during the beforeSave() products of the given type.
  • save(): This method runs during the afterSave() products of the given type.
  • isSalable(): This method allows a custom product type to customize product saleability.
  • _prepareProduct(): This method provides a hook to interact with the information by request when a product is initially added to the cart.
  • isVirtual(): By default it is false. If your product type is like virtual type then you can use this function and return true.

Price Model

In addition to the product type model, a module can specify a price model in the product type definition 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="new_product_type" label="New Product Type" modelInstance="Aureatelabs\NewProductType\Model\Product\Type\NewProductType" indexPriority="60" sortOrder="80" isQty="true">
       <priceModel instance="Aureatelabs\NewProductType\Model\Product\Price" />
   </type>
</config>

The price model should extend \Magento\Catalog\Model\Product\Type\Price. This class has no abstract methods which must be implemented but allows extending classes to interact with nearly every aspect of price calculation.

<?php

namespace Aureatelabs\NewProductType\Model\Product;

class Price extends \Magento\Catalog\Model\Product\Type\Price {
    //your custom code here
}

You can also add indexerModel and stockIndexerModel like priceModel in the product type definition XML.

In this article, you will be learning how one can use curl in Magento 2 development.

At first, you need to create an instance of “\Magento\Framework\HTTP\Client\Curl” in the Constructor as shown below:

/**
* @var \Magento\Framework\HTTP\Client\Curl
*/
protected $_curl;

/**
* Data constructor.
*
* @param \Magento\Framework\App\Helper\Context $context
* @param \Magento\Framework\HTTP\Client\Curl $curl
*/
public function __construct(
   \Magento\Framework\App\Helper\Context $context,
   \Magento\Framework\HTTP\Client\Curl $curl
) {
   $this->_curl = $curl;
   parent::__construct($context);
}

Make GET request using curl

//get method
$this->_curl->get($url);

//response will contain the output of curl request
$response = $this->_curl->getBody();

In the snippet given above,

  • $url : Contain the endpoint url.
  • $response : It will contain the response of the curl request.

Make POST request using curl

//post method
$this->_curl->post($url, $params);

//response will contain the output of curl request
$response = $this->_curl->getBody();

In the code given above,

  • $url : Contain the endpoint url.
  • $params : it’s an array, if you want to attach extra parameters in url.
  • $response :  It will contain the response of the curl request.

You can also add headers, basic authorization, additional curl options and cookies in the curl request. All you need to do is just add these methods before using get or post method. 

The detailed description on how to add headers, basic authorization, additional curl options, and cookies in curl request is given below.

Set curl headers

The two methods used to set the curl headers are:

  • addHeader
  • setHeaders

Set curl header using addHeader method

The addheader method accepts two parameters. First is the curl header name and second is the curl header value.

$this->_curl->addHeader("Content-Type", "application/json");
$this->_curl->addHeader("Content-Length", 200);

Set curl header using setHeaders method

The setHeaders method accepts one parameter as an array.

$headers = ["Content-Type" => "application/json", "Content-Length" => "200"];
$this->_curl->setHeaders($headers);

Set basic authorization in Curl

We can set the basic authorization using the setCredentials method.

$userName = "UserName";
$password = "Password";
$this->_curl->setCredentials($userName, $password);

It will be equivalent to setting CURLOPT_HTTPHEADER value

“Authorization : “. “Basic “.base64_encode($userName.”:”.$password)

Set additional curl options

The two methods used to set the curl options are:

  • setOption
  • setOptions

Set curl option using setOption method

The setOption method accepts two parameters. First is the curl option name and second is the curl option value.

$this->_curl->setOption(CURLOPT_RETURNTRANSFER, true);
$this->_curl->setOption(CURLOPT_PORT, 8080);

Set curl option using setOptions method

The setOptions method accepts one parameter as an array.

$options = [CURLOPT_RETURNTRANSFER => true, CURLOPT_PORT => 8080];
$this->_curl->setOptions($options);

Set cookies in curl

The two methods used to set the curl cookies in curl are:

  • addCookie
  • setCookies

Set curl cookies using addCookie method

The addCookie method accepts two parameters. First is the cookie name and second is the cookie value.

$this->_curl->addCookie("cookie-name-1", "123");
$this->_curl->addCookie("cookie-name-2", "test-cookie-value");

Set curl cookies using setCookies method

The setCookies method accepts one parameters as an array.

$cookies = ["cookie-name-1" => "100", "cookie-name-2" => "name"];
$this->_curl->setCookies($cookies);

FAQs

What is cURL in Magento2?


cURL in Magento2 or client for URL is a command-line tool. It is used to interact with web pages through HTTP requests to external servers and getting responses. For example, cURL can send secure requests to third-party payment gateways. The cURL can be run by creating a command through the cURL command syntax.

What is curl vs HTTP?


cURL vs HTTP cannot be compared as cURL is a command line used to make different types of HTTP requests and receive responses. HTTP is a protocol for client and server communication. When cURL requires data, it sends an HTTP request through the command line, directing the servers to initiate HTTP data transfers.

Which is better curl or Postman?


cURL or Postman both can be better depending on the requirements. cURL is a simple tool that accelerates HTTP requests without any complicated configuration choices, making it quick and efficient. On the other hand, Postman is more flexible and versatile which allows developers to create custom APIs according to their requirements.

Is curl a REST API?


No, cURL is not a REST API. cURL is a command-line that is used to send requests and receive network responses. REST API, on the other hand, is an application program designed for the REST software architecture. You can use cURL to send REST requests, but it isn’t the API itself.

We discussed how to set custom prices programmatically in the last post. Now, in this article, we will be guiding you on one of the most frequently asked queries related to Magento web development. That is, how to convert the price from one currency to another in the magento 2.

The first thing you need to do is to create an instance of “\Magento\Directory\Model\CurrencyFactory” and “\Magento\Store\Model\StoreManagerInterface” as given below:

 
 
 
Copy Code
/**
* @var \Magento\Directory\Model\CurrencyFactory
*/
public $currencyFactory;

/**
* @var \Magento\Store\Model\StoreManagerInterface
*/
public $storeManager;

/**
* Data constructor.
*
* @param \Magento\Framework\App\Helper\Context $context
* @param \Magento\Directory\Model\CurrencyFactory $currencyFactory
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
*/
public function __construct(
   \Magento\Framework\App\Helper\Context $context,
   \Magento\Directory\Model\CurrencyFactory $currencyFactory,
   \Magento\Store\Model\StoreManagerInterface $storeManager
) {
   $this->currencyFactory = $currencyFactory;
   $this->storeManager = $storeManager;
   parent::__construct($context);
}

Then you need to use the function given below to get the price converted from one currency to another currency.

 
 
 
Copy Code
public function convertPrice($price, $currencyCodeFrom, $currencyCodeTo)
{
   $rate = $this->currencyFactory->create()
                ->load($currencyCodeFrom)
                ->getAnyRate($currencyCodeTo);
   
   $convertedPrice = $price * $rate;

   return $convertedPrice;
}

In the snippet above,
$price : amount that you want to convert
$currencyCodeFrom : currency code from which the price has to be converted
$currencyCodeTo : currency code in which you want the price to be converted

Convert price from current currency to base currency

You need to use the following function to get the converted price from current currency to base currency.

 
 
 
Copy Code
public function convertPriceFromCurrentCurrencyToBaseCurrency($price)
{
   $curentCurrencyCode =  $this->storeManager->getStore()
                               ->getCurrentCurrency()
                               ->getCode();
   $baseCurrencyCode =  $this->storeManager->getStore()
                             ->getBaseCurrency()
                             ->getCode();

   $rate = $this->currencyFactory->create()
                 ->load($curentCurrencyCode)
                 ->getAnyRate($baseCurrencyCode);

   $convertedPrice = $price * $rate;

   return $convertedPrice;
}

Convert price from current currency to another currency

You need to use the following function to get the converted price from current currency to another currency.

 
 
 
Copy Code
public function convertPriceFromCurrentToAnotherCurrency($price, $currencyCodeTo)
{
   $curentCurrencyCode =  $this->storeManager->getStore()->getCurrentCurrency()->getCode();
   $rate = $this->currencyFactory->create()
                ->load($curentCurrencyCode)
                ->getAnyRate($currencyCodeTo);

   $convertedPrice = $price * $rate;

   return $convertedPrice;
}

In this example, I have implemented this code in the helper, but you can also implement this in a Block or a Controller as per your requirement.

Also read: How to add a column to tier pricing in Magento 2

Grow your online business like 2,399 subscribers

    * This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
    envelope

    Thank You!

    We are reviewing your submission, and will be in touch shortly.