I am trying to display on the new order transactional email the custom options for every product(in this case a configurable product), along with the price.
Custom Options are displayed by default, but the prices are not.
This is the method responsible for the custom options:
File:
/app/code/vendor/Email/Block/Order/Email/Items/DefaultItems.php
**
* @return array
*/
public function getItemOptions()
{
$result = [];
if ($options = $this->getItem()->getOrderItem()->getProductOptions()) {
if (isset($options['options'])) {
$result = array_merge($result, $options['options']);
}
if (isset($options['additional_options'])) {
$result = array_merge($result, $options['additional_options']);
}
if (isset($options['attributes_info'])) {
$result = array_merge($result, $options['attributes_info']);
}
}
return $result;
}
And this is an example of the result:
'options' =>
array (size=4)
0 =>
array (size=7)
'label' => string 'Metal' (length=5)
'value' => string '14ct Yellow Gold' (length=16)
'print_value' => string '14ct Yellow Gold' (length=16)
'option_id' => string '3027' (length=4)
'option_type' => string 'radio' (length=5)
'option_value' => string '18447' (length=5)
'custom_view' => boolean false
As you can see there is no key for the price of the actual option;
I've tried to load the product model via productFactory injecting Magento\Catalog\Model\ProductFactory
into DefaultItems.php
with the following method:
public function getProductModel($id)
{
$product = $this->productFactory->create()->load($id);
return $product;
}
and then calling the method on the template file
app/code/vendor/Email/view/frontend/templates/email/items/order/default.phtml
like this:
$_productCustomOption = $block->getProductModel($_item->getProductId())->getProductOptionsCollection()->getItemById('3027');
Where 3027
is the id of the custom options as seen before but, because this custom option has several values with different prices, the price always return null
like this:
protected '_data' =>
array (size=19)
'option_id' => string '3027' (length=4)
'product_id' => string '268' (length=3)
'type' => string 'radio' (length=5)
'is_require' => string '1' (length=1)
'sku' => null
'max_characters' => string '0' (length=1)
'file_extension' => null
'image_size_x' => string '0' (length=1)
'image_size_y' => string '0' (length=1)
'sort_order' => string '1' (length=1)
'default_title' => string 'Metal' (length=5)
'store_title' => null
'title' => string 'Metal' (length=5)
'default_price' => null
'default_price_type' => null
'store_price' => null
'store_price_type' => null
'price' => null
'price_type' => null
While if I call a custom option with only one value the price it defined.
So how do I get the price for a custom option with several values?
Best Answer
After days I came up with a solution, but it's worth noting that this solution won't work if, for whatever reason, you change the price of the custom option and resend the new order email; this is because the I am generating the product model through the productFactory that is NOT the same model as the one in:
I am pretty sure there is a better way to do it , but at the moment I am not able to find it, so this is what I came up with:
In
Injected
PriceCurrencyInterface
to format the price once we retrieve it:and then added this function:
This function checks if the price is either not
null
or0.0000
and, in this case, we decide not to display it; if either those options are false then the price is returned and is wrapped in aconvertAndFormat
function which will return a nicely formatted price with your currency of choice.In the template is then passed in this way:
There are lots of ifs and checking because sometimes the option value it's not a number or it doesn't exists at all. The product object model it's quite complex and deep as structure and that required lots of iteration and getters.
There are hundreds of way to do this better so if you feel like to improve this answer please do.