Hello! I have a site with enough pages that load times are starting to be noticeably affected by how long it takes the autonav to generate.
On version 8 I have successfully followed this awesome article to cache the autonav: https://www.kalmoya.com/articles/concrete5-speed-boost-autonav-block
However, I’ve got a site on 9.1.1 that just isn’t taking to this method. I’ve double-checked against the official documentation to see if anything in the article seemed outdated, but nothing does (https://documentation.concretecms.org/9-x/developers/security/cache ).
The IsMiss(); check just keeps being true no matter what I do - so instead of loading from cache, it keeps rebuilding to autonav from scratch, despite that fact that I’ve proven through logging that the $datacache variable is indeed saving and returning what looks like valid autonav data. See below for a snapshot of the saved cache data:
I’ve got all my cache setting enabled in the Dashboard. I am not hardcoding the block, it’s in a GlobalArea, and i simply have a view.php in the application/blocks/autonav folder to override it with the custom cache template from the above article.
My theory is that something about the autonav data causes the function to loop through the “miss” condition, as if in version 9.1.1 is not liking something about the data that version 8 was OK with. However I’ve spent hours changing everything I can think of and find on the internet, and no matter what, it still refuses to find the cache and counts it as a “miss”.
Any insight would be appreciated!!
my autonav_caching_engine.php:
<?php namespace Application\Controller;
use Concrete\Core\Controller\Controller;
class AutonavCachingEngine extends Controller
{
public function getOrSetCachedAutonav($handle, $autonavController, $expire = 3600)
{
\Log::addInfo('Cache handle: ' . $handle);
\Log::addInfo('Expiration: ' . $expire);
$expensiveCache = $this->app->make('cache/expensive');
$cacheKey = $handle;
// $dataCache = $expensiveCache->getItem($cacheKey);
$dataCache = $expensiveCache->getItem('WebsiteAutonav/' . $cacheKey);
// \Log::addInfo('Datacache handle: ' . print_r($dataCache, true));
// Log the cache key for debugging
\Log::info('Checking cache for key: ' . $cacheKey);
\Log::info('dataCache is null: ' . ($dataCache == null ? "null" : "NOT NULL"));
//\Log::info('dataCache variable value: ' . print_r(get_class_vars($dataCache), true));
if ($dataCache->isMiss()) {
\Log::info('Cache miss for key: ' . $cacheKey);
// Rebuild and cache the navigation
$navItems = $autonavController->getNavItems();
\Log::info('IsArray: ' . (is_array($navItems) ? 'yep' : 'nope'));
foreach ($navItems as $index => $item) {
$item->cObj->siteTree = null;
$navItems[$index] = $item;
}
// Log the actual data cached
// \Log::addInfo('Storing navItems in cache: ' . print_r($navItems, true));
$dataCache->lock();
$expensiveCache->save($dataCache->set($navItems)->expiresAfter($expire));
\Log::info('Saved nav items to cache for ' . $cacheKey);
//$checkCache = $expensiveCache->getItem($cacheKey);
//\Log::info('Immediate cache check: ' . ($checkCache->isMiss() ? 'Miss' : 'Hit'));
}
else {
\Log::info('Cache hit for key: ' . $cacheKey);
$navItems = $dataCache->get();
}
return $navItems;
}
public function testCache()
{
$expensiveCache = \Core::make('cache/expensive');
$testKey = 'test_cache_key';
// Try to get cache
$dataCacheTest = $expensiveCache->getItem($testKey);
if (!$dataCacheTest->isMiss()) {
\Log::info('Cache hit for test key: ' . $testKey);
return $dataCacheTest->get();
} else {
\Log::info('Cache miss for test key: ' . $testKey);
}
// Set a cache value
$expensiveCache->save($dataCacheTest->set('test_data')->expiresAfter(3600 * 24));
\Log::info('Saved test data to cache for ' . $testKey);
}
public function adjustCachedAutonavForPage($item, $currentPage)
{
// if the current page ID is the same as this nav item cID it's the current page
if ($currentPage->getCollectionID() == $item->cID) {
$item->isCurrent = true;
$item->inPath = true;
} else {
// We know this is not the currnt page so we set our values to false
$item->isCurrent = false;
$item->inPath = false;
// We get the path for a current page
$cPath = $currentPage->getCollectionPath();
$itemPagePath = $item->cObj->getCollectionPath();
if (strncmp($cPath, $itemPagePath, strlen($itemPagePath)) === 0) {
$item->inPath = true;
}
}
return $item;
}
}
My view.php:
<?php defined('C5_EXECUTE') or die("Access Denied.");
$dataCache = \Concrete\Core\Support\Facade\Application::getFacadeApplication()->make(\Application\Controller\AutonavCachingEngine::class);
$dataCache->testCache();
$navItems = $dataCache->getOrSetCachedAutonav("side_nav", $controller);
$c = Page::getCurrentPage();
foreach ($navItems as $ni) {
$ni = $dataCache->adjustCachedAutonavForPage($ni, $c);
$classes = array();
if ($ni->isCurrent) {
//class for the page currently being viewed
$classes[] = 'nav-selected';
}
if ($ni->inPath) {
//class for parent items of the page currently being viewed
$classes[] = 'nav-path-selected';
}
$ni->classes = implode(" ", $classes);
}
//*** Step 2 of 2: Output menu HTML ***/
if (count($navItems) > 0) {
echo '<ul class="nav royce">'; //opens the top-level menu
foreach ($navItems as $ni) {
echo '<li class="' . $ni->classes . '">'; //opens a nav item
echo '<a href="' . $ni->url . '" target="' . $ni->target . '" class="' . $ni->classes . '">' . h($ni->name) . '</a>';
if ($ni->hasSubmenu) {
echo '<ul>'; //opens a dropdown sub-menu
} else {
echo '</li>'; //closes a nav item
echo str_repeat('</ul></li>', $ni->subDepth); //closes dropdown sub-menu(s) and their top-level nav item(s)
}
}
echo '</ul>'; //closes the top-level menu
} elseif (is_object($c) && $c->isEditMode()) {
?>
<div class="ccm-edit-mode-disabled-item"><?=t('Empty Auto-Nav Block.')?></div>
<?php
}