026 —Joomla
Joomla 3 naar Joomla 5: overrides die de sprong overleven
Zestig procent van je Joomla 3 overrides is te redden. De andere veertig procent sloopt je site geruisloos. Dit is de volgorde die wij draaien.
Een Nederlands bureau waar we mee werken stuurde op een vrijdagavond een FTP-login op: 38 templates, één maatwerk Joomla 3.10-site voor een regionale evenementenorganisatie, en de PHP 8.2-deadline lag binnen de maand. Hun lead developer had de Joomla Update Component al een keer geprobeerd. Die had geruisloos de helft van hun artikel-overrides platgeslagen en de homepage-hero veranderd in een verticale stapel grijze knoppen. De sprong van Joomla 3 naar Joomla 5 is niet zo'n upgrade waar je op update klikt en daarna gewoon wegloopt.
Dit is het draaiboek dat we inmiddels op elke port van Joomla 3 naar Joomla 5 toepassen. Een deel is saai (letterlijk grep'en door je override-boom). Een deel is minder voor de hand liggend (de Web Asset Manager waarschuwt niet als een oude script-tag stilletjes geen effect heeft). Aan elk onderdeel hebben we ons in het afgelopen jaar gebrand.
De auditronde voordat je iets aanraakt
Voordat je één bestand bijwerkt, breng je elke override op de huidige site in kaart. In Joomla 3 staan ze op twee plekken onder je template:
find templates/YOUR_TEMPLATE/html -type f -name "*.php" | sort
find templates/YOUR_TEMPLATE/html/layouts -type f -name "*.php" | sort
Voor een site van vijf jaar oud krijg je meestal 20 tot 60 bestanden. Groepeer ze per component: com_content, com_users, com_contact, plus module-overrides onder mod_* en eventuele gedeelde layouts onder html/layouts/joomla/.
Maak nu een diff van elke override tegen het Joomla 3-corebestand waar hij vandaan komt. De uitvoer van die diff is het enige wat er tijdens de migratie toe doet. Is een override voor vijfennegentig procent identiek aan core, dan hoef je hem vrijwel zeker niet over te zetten. Joomla 5 levert betere defaults voor artikelweergave, paginering en formulier-rendering dan Joomla 3 deed. Die override bestaat omdat iemand vijf jaar geleden één CSS-klasse moest toevoegen.
Label elke Joomla 3-override in een van drie bakjes:
- Behouden. Inhoudelijke layout- of markup-wijzigingen waar de klant nog steeds van afhankelijk is.
- Inkorten. Grotendeels core-code met één of twee maatwerk-aanpassingen. Deze worden in Joomla 5 kleine layout-overrides, geen volledige kopieën.
- Schrappen. Overrides die alleen bestonden om een Bootstrap 2-utility-klasse toe te voegen. Joomla 5 is daar allang voorbij.
Op de verouderde site van 38 templates hierboven belandden 24 overrides in schrappen zodra we ze naast de huidige core legden. Minder code om te migreren is minder code om kapot te maken.
Bootstrap 2 naar Bootstrap 5: de klassenwissel
Dit is de grootste bron van visuele regressies bij het overzetten van Joomla 3-overrides. Joomla 3 kwam met Bootstrap 2.3, Joomla 4 sprong naar Bootstrap 5 en Joomla 5 bleef daar. Bevatten je overrides Bootstrap-utility-klassen, dan hebben de meeste nieuwe namen of bestaan ze helemaal niet meer.
De hernoemingen die je in vrijwel elke Joomla 3-override tegenkomt:
pull-left float-start
pull-right float-end
btn-default btn-secondary
btn-xs btn-sm (xs verwijderd)
panel card
panel-heading card-header
panel-body card-body
hidden-phone d-none d-md-block
visible-phone d-block d-md-none
img-responsive img-fluid
input-large form-control-lg
control-group mb-3
help-block form-text
row-fluid row
span6 col-md-6
span12 col-12
Draai eerst een bulk-replace op een kopie van de override-boom en loop dan elk bestand visueel na. De officiële migration guide van Bootstrap bevat de volledige diff tussen versies; sla hem op, want je komt terug. Let vooral op alles in row-fluid, dat is verdwenen, en op span6-kolomklassen die uitgingen van een twaalfkoloms fluid grid.
Wat je niet zo snel ziet: btn-group bestaat nog steeds, maar de manier waarop hij samenwerkt met dropdowns is veranderd. Heeft je override een dropdown-toggle in een artikel-actiebalk, reken er dan op dat je de markup herschrijft, niet alleen de klassen hernoemt. Het data-attribuut is nu data-bs-toggle in plaats van data-toggle, en de JavaScript-lijm is geen jQuery meer.
JHtml is dood, lang leve HTMLHelper
Elke Joomla 3-override die het framework aanroept, gebruikt de oude classnames zonder namespace: JHtml, JFactory, JText, JLayoutHelper, JRoute. Geen van deze bestaat standaard nog in Joomla 5. Ze werden in 4.0 zacht gedeprecateerd en in 5.0 verwijderd.
De vervangers zitten onder namespaced classes, en je overrides hebben bovenaan elk bestand use-statements nodig:
<?php
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;
$app = Factory::getApplication();
$user = $app->getIdentity();
echo HTMLHelper::_('image', 'system/icon.png', Text::_('JTOOLBAR_BACK'));
echo LayoutHelper::render('joomla.content.icons', ['item' => $this->item]);
Een search-and-replace brengt je voor zeventig procent waar je moet zijn. De resterende dertig procent zit in calls die niet alleen van naam, maar ook van signature zijn veranderd. Waar je op elke Joomla 3-naar-5-port op moet letten:
JFactory::getUser()wordtFactory::getApplication()->getIdentity(). De oude methode is in sommige contexten nog aanroepbaar, maar logt een deprecation die je error log bij elke pageload volramt.JFactory::getDbo()werkt nog via de legacy facade, maar nieuwe code zouFactory::getContainer()->get('DatabaseDriver')moeten gebruiken.JText::_()wordtText::_(). Goedkoop om te migreren, makkelijk te missen in includes en partials.JRoute::_()wordtRoute::_()met dezelfde signature.
Werk je vanuit een artikel-override en roep je $this->escape() aan, dan werkt dat nog steeds. View-methodes op de overgeërfde HtmlView-class zijn niet veranderd, wat betekent dat de meeste loops over $this->items ongewijzigd overzetten.
Scripts laden via de Web Asset Manager
Hier breken de meeste ports van Joomla 3 naar Joomla 5 stilletjes. In Joomla 3 laadde je een script in een override zo:
$doc = JFactory::getDocument();
$doc->addScript('templates/your_template/js/article-gallery.js');
$doc->addStyleSheet('templates/your_template/css/article-gallery.css');
In Joomla 5 draait die code nog steeds. Hij gooit geen error. Hij logt geen deprecation. Hij weigert simpelweg om je asset ergens nuttigs neer te zetten, omdat de Web Asset Manager het heeft overgenomen en verwacht dat assets geregistreerd worden, niet aangehangen.
Het juiste patroon is je asset declareren in templates/your_template/joomla.asset.json en hem dan vanuit de override aanroepen:
{
"$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
"name": "your_template",
"version": "1.0.0",
"assets": [
{
"name": "template.article-gallery",
"type": "script",
"uri": "js/article-gallery.js",
"dependencies": ["core"],
"attributes": { "defer": true }
},
{
"name": "template.article-gallery",
"type": "style",
"uri": "css/article-gallery.css"
}
]
}
<?php
use Joomla\CMS\Factory;
$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
$wa->useScript('template.article-gallery')
->useStyle('template.article-gallery');
Voordeel buiten het overleven van de upgrade: gedeclareerde assets krijgen versioning, dependency-resolutie en deferred loading erbij. Hangt je script af van core of van bootstrap.dropdown, dan declareer je dat één keer en stop je met vechten tegen de laadvolgorde.
Formuliervelden en de layouts-directory
Override-bestanden voor formuliervelden en gedeelde layouts zijn tussen major versies verhuisd. In Joomla 3 stonden layout-overrides onder templates/your_template/html/layouts/joomla/. Dat pad werkt in Joomla 5 nog steeds, maar de onderliggende layout-bestanden zijn flink herschreven, vooral alles onder joomla.form. en joomla.content..
Een veelvoorkomende faalcase: een bureau-override voor het artikel-infoblok onder html/layouts/joomla/content/info_block.php. In Joomla 3 was het bestand zo'n zestig regels. In Joomla 5 zit de core dichter bij de tweehonderd, gebruikt het Bootstrap 5-markup, semantische iconen via HTMLHelper::_('icon', ...) en een andere datavorm. De oude override over de nieuwe core kopiëren lijkt te werken en verbergt vervolgens stilletjes de publicatiedatum en auteurslink op elk artikel.
Het patroon dat de sprong overleeft: begin bij de huidige Joomla 5-core-layout, pas je aanpassingen op dat bestand toe, sla het op als de override. Neem het oude override-bestand nooit ongewijzigd mee. Behandel elke layout-override als een kleine patch bovenop de huidige core, niet als een fork die in 2019 bevroren is.
Een testronde die de stille breuk vangt
Joomla-migraties falen op plekken waar niets een error gooit. Het testplan dat we op elke Joomla 3-naar-5-site draaien:
- Zet
error_reporting = E_ALLinconfiguration.phpen tail de PHP error log terwijl je doorklikt. Deprecation-warnings vertellen je welke override nogJFactoryaanroept. - Open elk menu item-type dat de site gebruikt: enkel artikel, categorieblog, contactformulier, login, registratie, zoeken. Elk heeft minstens één gedeelde layout die stilletjes overgeërfd kan zijn.
- Verstuur aan de voorkant één van elk formulier. Bij formuliervelden bijt het layout-override-pad het hardst.
- Diff de homepage-HTML tegen een Joomla 3-snapshot.
curl -s https://old-site.com/ | tidy -q -i > old.htmlen hetzelfde op de staging-kopie. Massale klassenhernoemingen springen uit de diff. - Draai Lighthouse op drie representatieve pagina's. De standaardmarkup van Joomla 5 is slanker; is je score gezakt, dan zit er nog een oude override Bootstrap 2-kolommen in Bootstrap 5-containers te plempen.
Een volledige audit kost op een middelgrote site een dag. De prijs van overslaan is een dinsdagochtend-telefoontje van een klant wiens registratieformulier sinds de vrijdagdeploy stilletjes kapot is.
Toen we Pier bouwden, liepen we precies hier tegenaan op die site met 38 templates: de override-audit was de enige eerlijke manier om te weten wat er zou breken, maar met de hand was het slopend. Wat we uiteindelijk deden was elk verouderd bestand vóór elke bewerking diff'en tegen zijn upstream Joomla-tegenhanger, met volledige versiegeschiedenis bij elke stap, zodat de audit en de daadwerkelijke port op dezelfde plek leven.
Het kleinste wat je vandaag kunt doen: draai dat find-commando tegen de html/-directory van je eigen template en sorteer de uitvoer op bestandsgrootte. De grootste bestanden zijn vrijwel altijd de duurste overrides, en de duurste overrides zijn vrijwel altijd degene die je niet meer nodig hebt.
— Vragen —
Kun je Joomla 3-template-overrides direct op Joomla 5 draaien?
Sommige laden zonder fouten, maar de meeste verkleuteren stilletjes je Bootstrap-markup of raken verwijderde namespaces. Plan om elke override die je wilt behouden netjes over te zetten.
Vervangt de Web Asset Manager addScript volledig?
addScript bestaat nog in Joomla 5 en gooit geen error, maar assets die je zo toevoegt omzeilen dependency-resolutie en versioning. Gebruik voor alles wat nieuw is joomla.asset.json.
Hoe lang duurt een override-migratie van Joomla 3 naar Joomla 5?
Voor een middelgrote site met dertig overrides ben je met een volledige audit, port en testronde meestal twee tot drie werkdagen kwijt. Sites met maatwerkformulieren of shop-overrides lopen uit.