6

I need to create a module which lets the backend user add tooltips to the products custom options. So I created a field which the user fills with the unique identifier of a cms block which contains the text for the tooltip.

So my train of thought here was to create a plugin which appends the content of the given cms block to the html of my custom options.

Vendor/Module/Plugin/OptionsBlockPlugin.php

<?php

namespace Vendor\Module\Plugin;

class OptionsBlockPlugin {

protected $resultPageFactory;


public function __construct
(
       \Magento\Framework\View\LayoutFactory $layoutFactory
    ){
       $this->_layoutFactory = $layoutFactory;
    }

public function aroundGetOptionHtml(\Magento\Catalog\Block\Product\View\Options $subject, callable $proceed, \Magento\Catalog\Model\Product\Option $option)
{
     $returnValue = $proceed($option);
     $tooltip = $option->getData('tooltip'); //string of identifiert (for example: 'myBlock')

      if ($tooltip) {

          $block = $this->_layoutFactory->create()->createBlock('Vendor\Module\Block\Product\View\Options\Tooltip');
          $content = $block->getContent($tooltip);

          if($content){
              $returnValue = $returnValue.'<div class="option-tooltip">'.$content.'</div>';
         }

     }

        return $returnValue;
    }

 }

And my block class:

Vendor/Module/Block/Product/View/Options/Tooltip.php

<?php

namespace Vendor\Module\Block\Product\View\Options;

use Magento\Cms\Api\BlockRepositoryInterface;
use Magento\Cms\Api\Data\BlockInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\View\Element\Template;
use Magento\Framework\View\Element\Template\Context;


class Tooltip extends Template
{

    private $blockRepository;
    public function __construct(
        BlockRepositoryInterface $blockRepository,
        Context $context,
        array $data = []
    ) {
        $this->blockRepository = $blockRepository;
        parent::__construct($context, $data);
    }

    public function getContent($identifier)
    {
        try {
            $block = $this->blockRepository->getById($identifier);
            $content = $block->getContent();
        } catch (LocalizedException $e) {
            $content = false;
        }

        return $content;

    }

}

What am I doing wrong here? I just can't get the content of my cms block by its identifier. Can somebody help me out a bit?

6

I got it! The problem was the getById() method it DOES take a identifier as well as the id, my problem was that my test block had the identifier "123" and although it is a string either magento or php reads it as a numeric id in the method. So it is always was searching for the id (int) 123 instead of the identifier (string) '123'.

Maybe seperate methods for getByIdentifier()/getById() would solve this.

  • 2
    Be careful to make sure identifiers are not shared between multiple store views, otherwise, you will not be able to specify which one to load. github.com/magento/magento2/issues/10414 – Luke Rodgers Aug 29 '17 at 8:52
  • Right, I haven't thought about that, but thank your for the link, I'll update my module as soon as there is a method that takes the store id into account. – TrytoFly Aug 29 '17 at 8:59
1

Magento has the Magento\Cms\Model\GetBlockByIdentifier class for this purpose. Here is a usage example

<?php
namespace Company\Module\Block\Product;

use
    Magento\Catalog\Block\Product\View\AbstractView,
    Magento\Store\Model\StoreManagerInterface,
    Magento\Cms\Api\GetBlockByIdentifierInterface as BlockGetter,
    Magento\Catalog\Block\Product\Context as ProductContext,
    Magento\Framework\Stdlib\ArrayUtils;

class Masterpiece extends AbstractView
{
    private
        $_oStoreManager,
        $_oBlockGetter;

    public function __construct(
        StoreManagerInterface $oStoreManager,
        BlockGetter $oBlockGetter,
        ProductContext $oProductContext,
        ArrayUtils $oArrayUtils,
        array $data = []
    ) {
        $this->_oStoreManager = $oStoreManager;
        $this->_oBlockGetter  = $oBlockGetter;

        parent::__construct($oProductContext, $oArrayUtils, $data);
    }

    /**
     * Look on the product to see if there is a value in the
     * 'custom_static_block' attribute. If it is, use that value to search
     * for a static block with that as an identifier. If found, return the
     * markup from the static block. Otherwise return the empty string.
     */
    public function toHtml()
    {
        $staticBlockId = trim($this->getProduct()->getData('custom_static_block'));

        if($staticBlockId == '') {
            return '';
        }

        try {
            $storeId     = $this->_storeManager->getStore()->getId();
            $staticBlock = $this->_oBlockGetter->execute($staticBlockId, $storeId);
            return $staticBlock->getContent();
        } catch(\Exception $e) {
            return '';
        }
    }
}
0

Use below Helper class to get CMS block per store views. (Tested and Working)

<?php
namespace {{COMPANY_NAME}}\{{MODULE_NAME}}\Helper;

class Data extends \Magento\Framework\App\Helper\AbstractHelper
{
    protected $blockFactory;
    protected $blockResource;

    public function __construct(
        ...

        \Magento\Cms\Model\BlockFactory $blockFactory,
        \Magento\Cms\Model\ResourceModel\Block $blockResource,
        ...
    ) {
        ...

        $this->blockFactory = $blockFactory;
        $this->blockResource = $blockResource;
        ...
    }

    public function getStaticBlock($identifier){
        try {
            $block = $this->blockFactory->create();
            $block->setStoreId($this->storeManager->getStore()->getId());
            $this->blockResource->load($block, $identifier);
            if (!$block->getId()) {
                throw new NoSuchEntityException(__('CMS Block with identifier "%1" does not exist.', $identifier));
            }
            return $block;
        } catch(\Exception $e){
            //$this->logger->warning($e->getMessage());
        }
        return false;
    }

    public function getCmsBlockContent($identifier){

        $staticBlock = $this->getStaticBlock($identifier);

        if($staticBlock && $staticBlock->isActive()){
            return $staticBlock->getContent();
        }

        return __('Static block content not found');
    }
}

To use this class in .phtml:

<?php
$helper = $this->helper('{{COMPANY_NAME}}\{{MODULE_NAME}}\Helper\Data');
echo $helper->getCmsBlockContent("CMS_BLOCK_IDENTIFIER");
?>

NOTE: You can use this class for Blocks too

  • FYI, there is the Magento\Cms\Model\GetBlockByIdentifier class which implements your getStaticBlock method. Assume there was some copy & paste here? Also, why would you try and throw inside the same piece of code... – quickshiftin Mar 21 at 21:49

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.