basically, you have to process the description through the Block Filter class.
Lately, I had to do this for Categories to allow widgets, the same should work for block directives (although the directive looks slightly different in Magento2)
{{block id="123"}}
To execute the filter on the description when a category is loaded I added a plugin on the repository get Method and to execute it also when categories are loaded through a colelction I added an observer on the catalog_category_collection_load_after function.
I'll try to translate it to product ;)
First the loading for a single Object:
In your di.xml, define a new Plugin on the ProductRepository:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Catalog\Api\ProductRepositoryInterface">
<plugin name="filterProductDescription" type="Vendor\Module\Plugin\ProductRepository\FilterProductDescription"/>
</type>
</config>
Then you need to create the Plugin Class in your module:
<?php
declare(strict_types = 1);
namespace Vendor\Module\Plugin\ProductRepository;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\Product;
use Magento\Cms\Model\Template\FilterProvider;
class FilterProductDescription
{
const ATTR_DESCRIPTION = 'description';
/**
* @var FilterProvider
*/
private $filterProvider;
public function __construct(
FilterProvider $filterProvider
) {
$this->filterProvider = $filterProvider;
}
/**
* @param ProductRepositoryInterface $subject
* @param ProductInterface|Product $product
* @return ProductInterface
*/
public function afterGet($subject, ProductInterface $product): ProductInterface
{
if (false === $product->hasData(static::ATTR_DESCRIPTION)) {
return $product;
}
$filteredDescription = $this->filterProvider->getBlockFilter()
->filter($product->getData(static::ATTR_DESCRIPTION));
$product->setData(static::ATTR_DESCRIPTION, $filteredDescription);
return $product;
}
}
Now to also apply the filter, when a product collection is loaded, you need to add the same logic to the collection.
You can do this by adding an observer in the events.xml:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="catalog_product_collection_load_after">
<observer name="filterProductDescription" instance="Vendor\Module\Observer\ProductCollection\FilterProductDescription" />
</event>
</config>
and finally implement the observer class:
<?php
declare(strict_types = 1);
namespace Vendor\Module\Observer\ProductCollection;
use Magento\Cms\Model\Template\FilterProvider;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;
class FilterProductDescription implements ObserverInterface
{
const ATTR_DESCRIPTION = 'description';
/**
* @var FilterProvider
*/
private $filterProvider;
public function __construct(
FilterProvider $filterProvider
) {
$this->filterProvider = $filterProvider;
}
/**
* @param Observer $observer
* @return void
*/
public function execute(Observer $observer)
{
/** @var ProductCollection $productCollection */
$productCollection = $observer->getData('product_collection');
foreach ($productCollection->getItems() as $product) {
$filteredDescription = $this->filterProvider->getBlockFilter()
->filter($product->getData(static::ATTR_DESCRIPTION));
$product->setData(static::ATTR_DESCRIPTION, $filteredDescription);
}
}
}