NO, the full page cache is not the culprit.
DON'T DISABLE FULL PAGE CACHE.
The logic flow is clearly described in \Magento\Catalog\Helper\Data::getBreadcrumbPath()
when it runs $category = $this->getCategory()
.
Just see the getCategory()
code
/**
* Return current category object
*
* @return \Magento\Catalog\Model\Category|null
*/
public function getCategory()
{
return $this->_coreRegistry->registry('current_category');
}
It returns an object saved in the registry called current_category
. If the object is not present, the breadcrumbs will be empty.
For example, if you make a first time access (clean browser and magento cache) to a product directly from search box, you will have that breadcrumbs will be empty because registry('current_category')
was not setted.
Otherwise, if you make a first time access (clean browser and magento cache) to a product after visited its category, breadcrumbs will be present, because registry('current_category')
was setted.
Then, every time you make a second visit to same product page you just see the same result, because FPC (FULL PAGE CACHE) JUST CACHE EVERY GET REQUEST AND RESPONSE WITH THE CONTENT OF THE FIRST TIME VISIT.
With help of some posts on stackexchange, I found out this solution, This approach does not require you to override with di.xml
YOUR_THEME\Magento_Catalog\layout\catalog_product_view.xml
<referenceContainer name="content.top">
<block class="Vendor\Module\Block\Breadcrumbs" name="breadcrumbs" as="breadcrumbs" />
</referenceContainer>
Create a module with the following block:
Vendor/Module/Block/Breadcrumbs.php
<?php
namespace Vendor\Module\Block;
use Magento\Catalog\Helper\Data;
use Magento\Framework\View\Element\Template\Context;
use Magento\Store\Model\Store;
use Magento\Framework\Registry;
class Breadcrumbs extends \Magento\Theme\Block\Html\Breadcrumbs
{
/**
* Catalog data
*
* @var Data
*/
protected $_catalogData = null;
/**
* @param Context $context
* @param Data $catalogData
* @param array $data
*/
public function __construct(Context $context, Data $catalogData, Registry $registry, array $data = [])
{
$this->_catalogData = $catalogData;
$this->registry = $registry;
parent::__construct($context, $data);
}
/**
* Retrieve HTML title value separator (with space)
*
* @param null|string|bool|int|Store $store
* @return string
*/
public function getTitleSeparator($store = null)
{
$separator = (string)$this->_scopeConfig->getValue('catalog/seo/title_separator', \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $store);
return ' ' . $separator . ' ';
}
public function getCrumbs() {
return $this->_crumbs;
}
/**
* Preparing layout
*
* @return \Magento\Catalog\Block\Breadcrumbs
*/
protected function _prepareLayout() {
$title = [];
if ($breadcrumbsBlock = $this->getLayout()->getBlock('breadcrumbs')) {
$breadcrumbsBlock->addCrumb(
'home', [
'label' => __('Home'),
'title' => __('Go to Home Page'),
'link' => $this->_storeManager->getStore()->getBaseUrl()
]
);
$path = $this->_catalogData->getBreadcrumbPath();
$product = $this->registry->registry('current_product');
if ($product && count($path) == 1) {
$categoryCollection = clone $product->getCategoryCollection();
$categoryCollection->clear();
$categoryCollection->addAttributeToSort('level', $categoryCollection::SORT_ORDER_DESC)->addAttributeToFilter('path', array('like' => "1/" . $this->_storeManager->getStore()->getRootCategoryId() . "/%"));
$categoryCollection->setPageSize(1);
$breadcrumbCategories = $categoryCollection->getFirstItem()->getParentCategories();
foreach ($breadcrumbCategories as $category) {
$catbreadcrumb = array("label" => $category->getName(), "link" => $category->getUrl());
$breadcrumbsBlock->addCrumb("category" . $category->getId(), $catbreadcrumb);
$title[] = $category->getName();
}
//add current product to breadcrumb
$prodbreadcrumb = array("label" => $product->getName(), "link" => "");
$breadcrumbsBlock->addCrumb("product" . $product->getId(), $prodbreadcrumb);
$title[] = $product->getName();
} else {
foreach ($path as $name => $breadcrumb) {
$breadcrumbsBlock->addCrumb($name, $breadcrumb);
$title[] = $breadcrumb['label'];
}
}
$this->pageConfig->getTitle()->set(join($this->getTitleSeparator(), array_reverse($title)));
return parent::_prepareLayout();
}
$path = $this->_catalogData->getBreadcrumbPath();
foreach ($path as $name => $breadcrumb) {
$title[] = $breadcrumb['label'];
}
$this->pageConfig->getTitle()->set(join($this->getTitleSeparator(), array_reverse($title)));
return parent::_prepareLayout();
}
}
YOUR_THEME\Magento_Catalog\templates\product\breadcrumbs.phtml
<?php if ($crumbs && is_array($crumbs)) : ?>
<div class="breadcrumbs">
<ul class="items">
<?php foreach ($crumbs as $crumbName => $crumbInfo) : ?>
<?php
$label = $block->escapeHtml($crumbInfo['label']);
$link = $block->escapeUrl($crumbInfo['link']);
?>
<li class="item <?php /* @escapeNotVerified */ echo $block->escapeHtml($crumbName) ?>">
<?php if ($link) : ?>
<a href="<?php /* @escapeNotVerified */ echo $link ?>"
title="<?= $block->escapeHtml($crumbInfo['title']) ?>">
<?= $label ?>
</a>
<?php elseif ($crumbInfo['last']) : ?>
<strong><?= $label ?></strong>
<?php else: ?>
<?= $label ?>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
Best Answer
Breadcrumbs within 2.2.4 have changed dramatically is seems. Default navigation is needed now so modules for a Megamenu messed my Breadcrumbs up and switching back to default navigation fixed them for me. If however you want my alternative to breadcrumbs which change how the breadcrumbs work on product pages see below answer:
This does create a breadcrumb trail when searching for products or if you have a warm up script so breadcrumbs are always present rather than normally where they can get cached without a trail.
This is based on my module here I haven't thoroughly tested it however have just updated it for 2.2.4 based on my answer so please let me know of any issues: