Bepaalde pagina's in je Joomla website zijn supertraag. Hoe ga je dat oplossen?

Ingediend door Dirk Hornstra op 02-may-2023 21:30

Ik ben al een aantal jaar de webmaster van www.wergea.com. De site is in het verleden ingericht met Joomla. Dat was een versie 2.x, later door mij geüpgrade naar 3.x en binnenkort moeten we over naar 4.x. Maar als iets nu al traag is, dan gaat zo'n upgrade dat niet oplossen. Dus het is beter dat zelf van tevoren proberen op te lossen.

We hebben een pagina met "Alle verenigingen en stichtingen". En voor het gevoel duurt het tonen veel te lang. Want hoewel het wel een redelijk lange lijst is, het is het per regel "maar" een naam met een link naar een detailpagina.

Ik heb de bestanden en database op mijn laptop gezet, heb een Docker-container ingericht en laat de site daar draaien. Dat werkt goed. En op die locatie kun je ook rustig in je configuration.php bestand debug aanzetten: public $debug = '1';

Je krijgt dan onderin je pagina een aantal linkjes, onder andere ProfielInformatie en daar zie je een mooi lijstje met tijden per stap, wat er gedaan wordt en hoeveel geheugen dat kost. Dat geheugengebruik boeit me niet, wel dat ik zie dat bijna alles 0.17 milliseconden, 2.19 milliseconden duurt, maar één stap duurt 20832.32 ms! Dat zijn 20 seconden! Geen wonder dat die pagina "traag aanvoelt". Je ziet daarbij staan: "afterRenderComponent com_content".

In je code zoeken naar afterRenderComponent en dan kom je in het bestand /libraries/src/Component/ComponentHelper.php

Als je daar het stukje "$contents = static::executeComponent($path)" in commentaar zet (dus je zet er // voor), dan blijft je blok waar anders tekst zou staan leeg, maar het gaat wel supersnel. Dus hier moeten we dieper in duiken. Met een echo $path; druk je af welk bestand ingeladen wordt. Dat is /component/com_content/content.php

Dit bestand bevat niet zoveel code, er wordt een Controller aangemaakt en daar wordt een execute actie op uitgevoerd. In de code even een var_dump($controller); na de regel met getInstance toegevoegd en dan zie je wat informatie, maar dat zegt ook niet zoveel. Je ziet dat het een "ContentController" is (al verwacht) met wat eigenschappen en het pad van de views. Dat zal dan wel de class zijn die in het bestand /component/com_content/controller.php staat zijn. Die heeft maar 2 functies, de __construct voor het aanmaken en display voor het tonen. De class erft van JControllerLegacy, als je daarop zoekt, dan zie je dat in /libraries/classmap.php de class JControllerLegacy gekoppeld wordt aan /Joomla/CMS/MVC/Controller/BaseController. Dus eigenlijk erft je controller van de BaseController. Zoek je op class BaseController dan vind je die in /libraries/src/MVC/Controller/BaseController.php

Daar zie je dat een taak wordt uitgevoerd en dat zal standaard "display" zijn.  Als je naar de display-functie gaat en voor de $view->display(); een var_dump($view); uitvoert, dan zie je bovenin dat deze $view van het type ContentViewCategory is. En wat dieper bladeren, daar zie je het pad waar naar de templates gezocht wordt, /.../templates/jouw-thema/html/com_component/category en daarna /../components/com_content/views/category/tmpl/.

Maar goed, het object heeft het type ContentViewCategory, zoek je op die class dan kom je uit in /components/com_content/views/category/view.html.php
Er is ook nog een andere, maar je ziet dat die voor feeds is, dus die is hier niet van toepassing.

Er zit een foreach-loopje in om article slug op te halen en wat zaken voor te bereiden. Dat lijkt hier de "bottleneck" te zijn.

Als je namelijk dit in de code zet, dan krijg je netjes de naam en link en gaat het best snel:



// Compute the article slugs and prepare introtext (runs content plugins).
foreach ($this->items as $item)
{
    $item->slug = $item->alias ? ($item->id . ':' . $item->alias) : $item->id;

    $item->parent_slug = $item->parent_alias ? ($item->parent_id . ':' . $item->parent_alias) : $item->parent_id;

    // No link for ROOT category
    if ($item->parent_alias === 'root')
    {
        $item->parent_slug = null;
    }
continue; // quick patch
...

Maar goed, dat was even om te testen. We moeten de oorzaak vinden. Dus ik zet hieronder alle $dispatcher->... en $item->event... in commentaar en ga ze stuk voor stuk aan zetten. Dan moet wel duidelijk worden welke hier de vertragende factor is.

Oh, dat is wel heel snel gevonden, het is de eerste: $dispatcher->trigger('onContentPrepare', array ('com_content.category', &$item, &$item->params, 0));

Dit is een event waar je acties aan kunt koppelen. En dat heb ik ook in ruime mate gedaan... Dus in mijn code zoeken op function onContentPrepare( en dan vind ik flink wat matches, plugins die ik gemaakt heb.

En dan krijg ik al het flauwe vermoeden dat deze traagheid niet ontstaat doordat er iets in de database niet goed geconfigureerd is, maar omdat ik zelf een "fout in de code" gemaakt heb. En dat blijkt ook zo te zijn. We hebben namelijk ook een foto-album, dat wordt echter op een andere server/domein gehost. Dus via CURL vragen we die gegevens op. Maar dat moet natuurlijk alleen als een bepaalde "tag" in de content staat. Niet bij elk request... want dat gebeurt nu wel! Validatie aangepast en bam: de site vliegt er over!

Conclusie:

Als je een site met het Joomla CMS hebt en er is iets "traag", dan is de kans groot dat dit in een plugin of een foutje in je eigen sjablonen is. Met bovenstaande uitleg kun je als het goed is nu zelf dit probleem oplossen!