1

I've created a module to add a custom category attribute (custom canonical URL) to a category page. The attribute displays in the admin and I can save the value. I've extended _prepareLayout() function of \Magento\Catalog\Block\Category\View but it doesn't seem to be working. I'm I missing something or is there a better way to do this?

Example/CategoryCanonicalUrl/etc/module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Example_CategoryCanonicalUrl" setup_version="0.0.1">
    </module>
</config>

Example/CategoryCanonicalUrl/Setup/InstallData.php

<?php

namespace Example\CategoryCanonicalUrl\Setup;

use Magento\Catalog\Setup\CategorySetup;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;

class InstallData implements InstallDataInterface
{
    /**
     * @var CategorySetup
     */
    private $categorySetup;

    public function __construct(
        CategorySetup $categorySetup
    ) {
        $this->categorySetup = $categorySetup;
    }

    /**
     * @inheritDoc
     */
    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $setup->startSetup();

        $this->categorySetup->addAttribute(
            \Magento\Catalog\Model\Category::ENTITY,
            'custom_canonical_url',
            [
                'type' => 'varchar',
                'label' => 'Custom Canonical URL',
                'required' => false,
                'visible' => 1,
                'visible_on_front' => 1,
                'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE,
                'group' => 'Search Engine Optimization',
            ]
        );

        $setup->endSetup();
    }
}

Example/CategoryCanonicalUrl/view/adminhtml/ui_component/category_form.xml

<?xml version="1.0"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <fieldset name="search_engine_optimization">
        <field name="custom_canonical_url" sortOrder="160" formElement="input">
            <settings>
                <dataType>string</dataType>
                <label translate="true">Custom Canonical URL</label>
                <scopeLabel>[STORE VIEW]</scopeLabel>
                <notice translate="true">URL without forward slash (/) e.g. example-category</notice>
            </settings>
        </field>
    </fieldset>
</form>

Example/CategoryCanonicalUrl/Block/Category/CanonicalUrl.php

<?php

namespace Example\CategoryCanonicalUrl\Block\Category;

class CanonicalUrl extends \Magento\Catalog\Block\Category\View
{
    /**
     * Core registry
     *
     * @var \Magento\Framework\Registry
     */
    protected $_coreRegistry = null;

    /**
     * Catalog layer
     *
     * @var \Magento\Catalog\Model\Layer
     */
    protected $_catalogLayer;

    /**
     * @var \Magento\Catalog\Helper\Category
     */
    protected $_categoryHelper;

    /**
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver
     * @param \Magento\Framework\Registry $registry
     * @param \Magento\Catalog\Helper\Category $categoryHelper
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Magento\Catalog\Model\Layer\Resolver $layerResolver,
        \Magento\Framework\Registry $registry,
        \Magento\Catalog\Helper\Category $categoryHelper,
        array $data = []
    ) {
        $this->_categoryHelper = $categoryHelper;
        $this->_catalogLayer = $layerResolver->get();
        $this->_coreRegistry = $registry;
        parent::__construct($context, $data);
    }

    /**
     * @return $this
     */
    protected function _prepareLayout()
    {
        parent::_prepareLayout();

        $this->getLayout()->createBlock(\Magento\Catalog\Block\Breadcrumbs::class);

        $category = $this->getCurrentCategory();
        if ($category) {
            $title = $category->getMetaTitle();
            if ($title) {
                $this->pageConfig->getTitle()->set($title);
            }
            $description = $category->getMetaDescription();
            if ($description) {
                $this->pageConfig->setDescription($description);
            }
            $keywords = $category->getMetaKeywords();
            if ($keywords) {
                $this->pageConfig->setKeywords($keywords);
            }
            if ($this->_categoryHelper->canUseCanonicalTag()) {
                $customCanonicalUrl = trim($category->getCustomCanonicalUrl());

                if ($customCanonicalUrl) {
                    $canonicalUrl = $customCanonicalUrl;
                } else {
                    $canonicalUrl = $category->getUrl();
                }

                $this->pageConfig->addRemotePageAsset(
                    $canonicalUrl,
                    'canonical',
                    ['attributes' => ['rel' => 'canonical']]
                );
            }

            $pageMainTitle = $this->getLayout()->getBlock('page.main.title');
            if ($pageMainTitle) {
                $pageMainTitle->setPageTitle($this->getCurrentCategory()->getName());
            }
        }

        return $this;
    }
}

Example/CategoryCanonicalUrl/registration.php

<?php \Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE, 'Example_CategoryCanonicalUrl',
    __DIR__
);

1 Answer 1

0

I now have this working by making the follow changes.

Created Example/CategoryCanonicalUrl/etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Catalog\Block\Category\View" type="Example\CategoryCanonicalUrl\Block\Category\CanonicalUrl"/>
</config>

Added the below to Example/CategoryCanonicalUrl/etc/module.xml

        <sequence>
            <module name="Magento_Catalog"/>
        </sequence>

Adjusted parent::__construct($context, $data); to parent::__construct($context, $layerResolver, $registry, $categoryHelper, $data); in Example/CategoryCanonicalUrl/Block/Category/CanonicalUrl.php as I was getting Type Error occurred when creating object error.

Removed parent::_prepareLayout(); from protected function _prepareLayout() in Example/CategoryCanonicalUrl/Block/Category/CanonicalUrl.php as I was getting duplicated canonical link tags.

Added store manager to Example/CategoryCanonicalUrl/Block/Category/CanonicalUrl.php for the full canonical URL when e.g. example-category is added via the Custom Canonical URL input in the admin area.

<?php

namespace Example\CategoryCanonicalUrl\Block\Category;

use Magento\Store\Model\Store;

class CanonicalUrl extends \Magento\Catalog\Block\Category\View
{
    /**
     * Core registry
     *
     * @var \Magento\Framework\Registry
     */
    protected $_coreRegistry = null;

    /**
     * Catalog layer
     *
     * @var \Magento\Catalog\Model\Layer
     */
    protected $_catalogLayer;

    /**
     * @var \Magento\Catalog\Helper\Category
     */
    protected $_categoryHelper;

    /**
     * Store manager
     *
     * @var \Magento\Store\Model\StoreManagerInterface
     */
    protected $_storeManager;

    /**
     * @param \Magento\Framework\View\Element\Template\Context $context
     * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver
     * @param \Magento\Framework\Registry $registry
     * @param \Magento\Catalog\Helper\Category $categoryHelper
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Magento\Catalog\Model\Layer\Resolver $layerResolver,
        \Magento\Framework\Registry $registry,
        \Magento\Catalog\Helper\Category $categoryHelper,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        array $data = []
    ) {
        $this->_categoryHelper = $categoryHelper;
        $this->_catalogLayer = $layerResolver->get();
        $this->_coreRegistry = $registry;
        $this->_storeManager = $storeManager;
        parent::__construct($context, $layerResolver, $registry, $categoryHelper, $data);
    }

    /**
     * @return $this
     */
    protected function _prepareLayout()
    {
        $this->getLayout()->createBlock(\Magento\Catalog\Block\Breadcrumbs::class);

        $category = $this->getCurrentCategory();
        if ($category) {
            $title = $category->getMetaTitle();
            if ($title) {
                $this->pageConfig->getTitle()->set($title);
            }
            $description = $category->getMetaDescription();
            if ($description) {
                $this->pageConfig->setDescription($description);
            }
            $keywords = $category->getMetaKeywords();
            if ($keywords) {
                $this->pageConfig->setKeywords($keywords);
            }
            if ($this->_categoryHelper->canUseCanonicalTag()) {
                $customCanonicalUrl = trim($category->getCustomCanonicalUrl());

                if ($customCanonicalUrl) {
                    $canonicalUrl = $this->_storeManager->getStore()->getBaseUrl() . $customCanonicalUrl;
                } else {
                    $canonicalUrl = $category->getUrl();
                }

                $this->pageConfig->addRemotePageAsset(
                    $canonicalUrl,
                    'canonical',
                    ['attributes' => ['rel' => 'canonical']]
                );
            }

            $pageMainTitle = $this->getLayout()->getBlock('page.main.title');
            if ($pageMainTitle) {
                $pageMainTitle->setPageTitle($this->getCurrentCategory()->getName());
            }
        }

        return $this;
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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