Each product in Magento 2 usually has several prices: regular, special, final, etc. Each type of price has its own class, which is responsible for calculating the total value of this price. Some types of prices are available for all products, while others are specific to a particular type of product.
Here are the issues that we will consider in this article:
How to identify what composes the final price of the product
How to customize the price calculation process
How price is rendered in Magento
How to render price in a given place on the page and how to modify how the price is rendered
Let’s take a look at the basic types of prices available for all types of products:
- base_price — product price at the default currency exchange rate;
- regular_price — product price at the rate of the selected currency;
- final_price — the total price of the product;
- special_price — product price with a discount;
- tier_price — product price that depends on its quantity in the cart;
- custom_option_price — the price of options if the selected product has any;
- configured_price — product price including the options;
- catalog_rule_price — product price after applying the catalog rules.
The special_price, tier_price, custom_option_price types may have a fixed value or a percentage. If necessary, they can be set for specific user groups.
The base classes that are responsible for implementing different types of prices are located in the Magento\Catalog\Pricing\Price namespace and extend the Magento\Framework\Pricing\Price\AbstractPrice class. Different product types usually override the logic of calculating a particular type of price. In this case, the corresponding classes are located in the namespace of the corresponding product type. Also, some product types add their own types of price:
- downloadable products:
- link_price — product price when downloaded via a specific link;
- bundle products:
- bundle_option — product price of the bundle option.
Each type of price has its getValue() and getAmount() methods. The getValue() method returns the price value, and the getAmount() method returns the total price value with all taxes included.
The final_price of a product depends on its type.
For ordinary products (simple, virtual) it corresponds to the lowest value from regular_price, catalog_rule_price, special_price, tier_price.
For configurable products, the price of each option is selected as the minimum value from base_price, tier_price, index_price, catalog_rule_price. At the same time, when choosing the minimum price, the status of the configurable option of the product and its availability for a specific site are checked. After determining the final_price of all the options, the final price of the configurable product is determined, which will be equal to the lowest price of its options.
The final_price of the grouped product is equal to the lowest final_price of all the products in the group.
For bundle products, the price is calculated in the same way as for simple products + bundle_option, which is the price of all the required options multiplied by their number.
There are several ways to change the price calculation process:
- Create a new price type and add it to the set of basic types. To do this, you need to create your own module with a class that will implement the Magento\Framework\Pricing\Price\BasePriceProviderInterface interface and extend the Magento\Framework\Pricing\Price\AbstractPrice class, as well as add the necessary instructions to the module di-file:
XHTML12345678<virtualType name="MyVendor\MyModule\Pricing\Price\Pool" type="Magento\Framework\Pricing\Price\Pool"><arguments><argument name="prices" xsi:type="array"><item name="my_price" xsi:type="string">MyVendor\MyModule\Pricing\Price\MyPrice</item></argument><argument name="target" xsi:type="object">Magento\Catalog\Pricing\Price\Pool</argument></arguments></virtualType>
- Create a plugin for the class methods of the price type, the process of calculating which we want to change, for example, around the getValue() method.
- Override the class that corresponds to the type of price that we need for a specific type of product, using the di-file in the module:
XHTML1234567<virtualType name="MyVendor\MyModule\Pricing\Price\Pool" type="Magento\Framework\Pricing\Price\Pool"><arguments><argument name="prices" xsi:type="array"><item name="regular_price" xsi:type="string">MyVendor\MyModule\Pricing\Price\MyRegularPrice</item></argument></arguments></virtualType>
- Completely override the price class using the preference instruction in the di-file module.
Let us consider how the price display is formed using the example of forming and displaying the final_price of a simple product. The Magento\Catalog\Pricing\Render\FinalPriceBox class is responsible for displaying the price. The template that is used when displaying the contents of the block is Magento_Catalog::product/price/final_price.phtml. In case the product has a special price, the user will be shown the old and the new prices by calling the block’s renderAmount() method. Otherwise, only the final price will be displayed. When displaying the final price, the lowest price of all possible prices will be selected. Further, if the product has options (e.g.: size), a block with the price of the cheapest option is displayed.
To display the price in the right place on the page, you need to add the Magento\Catalog\Pricing\Render class block to your layout by passing the price_type_code parameter as an argument to it.
<block class="Magento\Catalog\Pricing\Render" name="product.price.myprice">
<argument name="price_render" xsi:type="string">product.price.render.default</argument>
<argument name="price_type_code" xsi:type="string">final_price</argument>
<argument name="zone" xsi:type="string">item_view</argument>
Using data-arguments, you can change the price box, amount renders and adjustment renders by changing their css-classes, id_suffix, id_prefix, etc.
To change the price display template you can create your own catalog_product_prices.xml. Inside it, you can change the render.product.prices block by passing as parameters the name of the class of the block and the name of your template for the required type of price.
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/layout_generic.xsd">
<argument name="myprice" xsi:type="array">
<item name="prices" xsi:type="array">
<item name="final_price" xsi:type="array">
<item name="render_class" xsi:type="string">MyVendor\MyModule\Pricing\Render\FinalPriceBox</item>
<item name="render_template" xsi:type="string">MyVendor_MyModule::product/price/final_price.phtml</item>
This is what the price generation for different types of products looks like in Magento 2. Thank you for reading, hope everything was clear and helpful. Please leave your comments and questions in the section below and we will take a look at them together.