5

I want to use CMS blocks inside product attributes, eg in description and short description.

  • inside product description I've added {{block id="test1"}}.
  • i have two observer
    • catalog_product_collection_load_after for collections
    • catalog_controller_product_view for products

Observer:

public function execute(Observer $observer): void
{
    $product = $observer->getProduct();
    $this->helper->parse($product);
}

Helper:

use Magento\Cms\Model\Template\FilterProvider
...
public function __construct(Context $context, FilterProvider $filterProvider)
{
    $this->filterProvider = $filterProvider;
    parent::__construct($context);
}

public function parse(Product $product): void
{
    # some code to get attribute code and value
    ...
    $attributeValue = $this->insertCmsBlocks($product, $attributeCode, $attributeValue);
    $product->setData($attributeCode, $attributeValue);
}

public function insertCmsBlocks(Product $product, string $attributeCode, string $attributeValue): string
{
    ...
    $attributeValue = $this->filterProvider->getBlockFilter()->filter($attributeValue);
    ...

    return $attributeValue;
}

Category page

This works w/o any problems ...

enter image description here


Product page

Instead of default LUMA theme product page "compare" and "wishlist" block is loaded ...

enter image description here


  • block_html and full_page is disabled ...
  • $this->filterProvider->getBlockFilter()->filter($attributeValue) looks ok when debugging

enter image description here

If I comment $this->filterProvider->getBlockFilter()->filter($attributeValue) everthing works ... so, there is no problem with the event, cache or $product->setData() ...

Any ideas whats wrong with this code?

  • I have tried with the same observer you wrote and it worked for me. Where on your image should be the description displayed? Because I can not see it anywhere. Have you tried debugging on \Magento\Catalog\Block\Product\View\Description::getProduct and what does the description holds? Maybe it's changed to default somewhere. And last thing, you cleared the cache right? :) – Sebastian Oct 22 '18 at 20:49
2
+50

Let me suggest a slightly different way of processing the attributes on the product pages that I think might be better. The core uses the \Magento\Catalog\Helper\Output class to process them and it has an addHandler() method. It takes a class as a callback and executes a method on it, allowing your code to be very clean. So instead of using an event, add a plugin:

<type name="Magento\Catalog\Helper\Output"> 
    <plugin name="Example::attribute_handler" type="Example\Module\Plugin\Product\AttributeHandler"/>
</type>

Add the product attribute handler (this can be used for category attributes too) and inject your helper into the constructor. The product attribute handlers need an arbitrary name, as you can see in the method definition.

namespace Example\Module\Plugin\Product;

class AttributeHandler
{
    private $attributeHandler;

    public function __construct(\Example\Module\Model\Processor\Attribute\Handler $attributeHandler)
    {
        $this->attributeHandler = $attributeHandler;
    }

    public function beforeProductAttribute(\Magento\Catalog\Helper\Output $context, $subject)
    {
        if (count($context->getHandlers('productattribute')) < 1) {
            $context->addHandler('productAttribute', $this->attributeHandler);
        }
    }
}

Last, update your helper to include a productAttribute() method. I like to check for the existence of a substring {{ before running the processor to make it more efficient if there is not blocks / widgets.

The productAttribute() method would look like this in your case (I would abstract insertCmsBlocks() further to include a method that does not require Product):

public function productAttribute(\Magento\Catalog\Helper\Output $context, $value, $params)
{
    if ($value && strpos((string) $value, '{{') !== false) {
        $value = $this->filter($value);
    }

    return $value;
}

One benefit of this approach is that it works anywhere the Magento_Catalog product attribute handler is used.

  • It works. Thank you. I'll leave the question open until bounty ends ... maybe someone has an idea whats breaks the layout. – sv3n Oct 25 '18 at 9:07
0

Are you using FPC?
The catalog_controller_product_view event cannot be used in conjunction with FPC cache since Magento will not raise it after the first visit.

See here for a possible solution

  • No. FPC is disabled. – sv3n Oct 23 '18 at 18:18
  • @sv3n can you confirm that your observer is getting hit on every product page view? – Haim Oct 23 '18 at 18:19
  • Yes. I've updated the question ... w/o $this->filterProvider.... everything is OK. – sv3n Oct 23 '18 at 18:23
  • what happens if you log $product->getData($attributeCode, $attributeValue); after $product->setData($attributeCode, $attributeValue); does the value for the attribute include your CMS block? – Haim Oct 23 '18 at 19:09
  • 1
    @sv3n bassplayer7's answer is a good other method, I'm trying to figure out what is it about your code that breaks the layout of the product page – Haim Oct 25 '18 at 14:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.