I've created a module to add a custom category attribute (custom canonical URL) to a category page, based on Display custom canonical URL on category page in Magento 2 question.

Here is the contents of Vendor/Module/Block/Category/CanonicalUrl.php:


namespace Vendor\Module\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;
      $this->_logger = $logger;
        parent::__construct($context, $layerResolver, $registry, $categoryHelper, $data);

     * @return $this
    protected function _prepareLayout()

        $category = $this->getCurrentCategory();
        if ($category) {
            $title = $category->getMetaTitle();
            if ($title) {
            $description = $category->getMetaDescription();
            if ($description) {
            $keywords = $category->getMetaKeywords();
            if ($keywords) {
            if ($this->_categoryHelper->canUseCanonicalTag()) {
                $customCanonicalUrl = trim($category->getCustomCanonicalUrl());
                if ($customCanonicalUrl) {
                    $canonicalUrl = $this->_storeManager->getStore()->getBaseUrl() . $customCanonicalUrl;
                } else {
                    $canonicalUrl = $category->getUrl();

                    ['attributes' => ['rel' => 'canonical']]

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

        return $this;

I implemented his answer but it isn't working for me. Inside the protected function _prepareLayout() within CanonicalUrl.php it seems $category->getCurrentCategory() seems to work because if I insert $category->getId() immediately after it, the correct Id of the category is retrieved. Also later in the code, $category->getUrl() also correctly retrieves the url of the category.

However, $category->getMetaTitle(), $category->getMetaKeywords(), and $category->getCustomCanonicalUrl() return null, so I'm unable to insert the custom_canonical_url attribute value in the category page.

Also, I notice that I'm getting the following errors in my system.log:

main.CRITICAL: Invalid template file: 'category/banner.phtml' in module: 'Example_CategoryCanonicalUrl' block's name: 'category_banner' [] []
main.CRITICAL: Invalid template file: 'category/desc_main_column.phtml' in module: 'Example_CategoryCanonicalUrl' block's name: 'category_desc_main_column' [] []

What am I doing wrong?


You do not state exactly what you want to use as a custom canonical value - the standard canonical url can be set by enabling "Use Canonical Link Meta Tag For Categories" in admin.

For any other custom value in the head section of a category page you can add this via catalog_category_view.xml layout.

Module MyModule_Seo:




<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
        <referenceBlock name="head.additional">
            <block class="Magento\Catalog\Block\Category\View" name="custom.category" template="MyModule_Seo::catalog/view/custom/category.phtml"></block>


<meta property="mymodule:custom" content="custom-content-for-<?= $block->escapeUrl($block->getCurrentCategory()->getName()) ?>" />

If you want to perform some extra logic based on $block->getCurrentCategory() data pass the object into a ViewModel help class and perform the logic and return the data to your template.


Turns out the "invalid template file" errors were the clue to the problem (imagine that). To resolve, I merely copied those templates:

From app/design/ThemeVendor/Theme/Magento_Catalog/templates/category

To app/code/Vendor/Module/view/frontend/templates/category

Works like a charm now. :)

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.