Removed and backward incompatibility
All the deprecated features than have now been removed and any backward incompatibilities. There should be an explanation of how to mitigate the removals / changes.
Replacing .tar.bz2 with .tar.zstd
Starting with the final release of Joomla! 5.0.0 we no longer create .tar.bz2 packages. Instead we use .tar.zstd packages. This allows us to create download packages which are about 3 MiB smaller then bzip2 compressed files and about 11 MiB smaller files then zip compressed files.
PSR-3 upgraded to version 3
The PSR-3 (Logging) is upgraded to version 3 of the specification.
Most critically, the signature of the \Psr\Log\LoggerInterface
methods has changed. The $message
argument is now strongly typed as string|\Stringable
. Any logger implementation you use must be compatible with this new signature. This is relevant to you if you implement your own logger, or if you are using a third party logger such as Monolog, in your extension.
If you are using your own logger, you want to preserve compatibility with Joomla 4 and 5 in the same extension package, and you do not mind losing PSR-3 compatibility you can include a copy of PSR-3 in your extension as long as it's under your extension's namespace. For example, instead of using \Psr\Log\LoggerInterface
you could use \Acme\Component\Example\Administrator\Log\LoggerInterface
. Note that you can use PHP Scoper to easily migrate your dependencies under your own namespace.
If you only need to maintain compatibility with PSR-3 to use an logger external to your component, such as Joomla's logger, you can still typehint against \Psr\Log\LoggerInterface
. Please note that the external logger you are using must be compatible with PSR-3 version 1 on Joomla 4 and PSR-3 version 3 on Joomla 5. If you are providing a third party, external logger yourself you may need to include two versions of the logger with your extension and only load the correct one for each Joomla version.
Framework Update
Joomla! 5.0 uses the Joomla! Framework 3.0, this might have it own breaking changes:
- Dependency Container:
PR: https://github.com/joomla-framework/di/pull/48 Description: It is possible to override services in child containers. This allows to override protected services, like the form factory one, in the containers of an extension when they are booted.
Database must be injected in constructor model
- PR: https://github.com/joomla/joomla-cms/pull/38511
- Description: The database instance in the model should be injected through the
$this->setDatabase()
or the deprecated function$this->setDbo()
configuration in the constructor to make it available in the base class. Like that it is ensured that calls to$this->getDatabase()
and the deprecated function$this->getDbo()
will point to the same instance.
class MyModel extends ListModel {
public function __construct(..) {
parent::__construct(...);
$this->setDatabase(MyHelper::getGridDB());
}
}
Drop -es5.js files
- PR: https://github.com/joomla/joomla-cms/pull/39618
- Descriptions: The build tools won't produce es5 files (IIFE, transpiled to ES5) anymore. Further more the dependencies in all the assets.json files that were pointing to these (es5) files were removed (the actual entries for the -es5.js were kept for B/C but the URLs are empty, the files won't be loaded). The .es6.js files are transpiled to ES2018 and specifically the minimum browser versions are the ones from caniuse: es6-module. 3rd PD code that used the
type=module
/nomodule
to load modern/legacy code will still work as it did before but the core is not distributiong anymoreIE11
compatible scripts! .
CSS removals
The CSS class ".ie11" was removed via PR #39018
Javascript removals
The following Javascript assets were removed via PR #40302:
-
/media/com_templates/js/admin-template-compare.js
- Not used anymore by the core since version 4.3.0, see PR #38823. -
/media/com_users/js/admin-users-mail.js
- Not used anymore by the core since version 4.3.0, see PR #39374.
This includes also the -es5.js
files and the minified and gzipped files and the corresponding entries in joomla.asset.json
files.
The files have been kept in Joomla 4 for b/c with layout overrides.
To fix these layout overrides for Joomla 5, change your layout override in the same way as the corresponding core layout has been changed by the PR mentioned in the list above for each Javascript asset.
Eg for the template manager's side-by-side comparison view, see PR #38823.
Return Types
All return types have been updated to match the PHP 8.1 return type signatures. This addresses any class utilising the ArrayAccess, Datetime or the JsonSerializable interfaces. If you extend from any of the affected classes and require compatibility with both Joomla 4.x and 5.x you should add the #[\ReturnTypeWillChange]
annotation to your code.
administrator/components/com_users/src/DataShape/DataShapeObject.php
public function __isset(...) --> public function __isset(...): bool
public function offsetExists(...) --> public function offsetExists(...): bool
public function offsetGet(...) --> public function offsetGet(...): mixed
public function offsetSet(...) --> public function offsetSet(...): void
public function offsetUnset(...) --> public function offsetUnset(...): void
libraries/src/Date/Date.php
public function format(...) --> public function format(...): string
public function setTimezone(...) --> public function setTimezone(...): \Datetime
libraries/src/Document/JsonapiDocument.php
public function jsonSerialize(...) --> public function jsonSerialize(...): mixed
libraries/src/Feed/Feed.php
public function count(...) --> public function count(...): int
public function offsetExists(...) --> public function offsetExists(...): bool
public function offsetGet(...) --> public function offsetGet(...): mixed
public function offsetSet(...) --> public function offsetSet(...): void
public function offsetUnset(...) --> public function offsetUnset(...): void
libraries/src/Language/Language.php
\Joomla\CMS\Language\Language extends now from \Joomla\Language\Language
Duplicated code which is extended from the framework has been removed
public function debugFile(...) --> public function debugFile(string $filename): int
Menus controller resync function got removed
- PR: https://github.com/joomla/joomla-cms/pull/40336
- Description: The resync function in the administrator MenusController class is only used for the 1.5 to 1.6 upgrade routine.
User changes
- PR: https://github.com/joomla/joomla-cms/pull/41048
- Description: Removed message "Cannot load user X", for removed users.
Some core classes are not anymore of type CMSObject
PR: https://github.com/joomla/joomla-cms/pull/40999 Files:
- libraries/src/Categories/CategoryNode.php
- libraries/src/Changelog/Changelog.php
- libraries/src/Filesystem/Stream.php
- libraries/src/Installer/InstallerExtension.php
- libraries/src/MVC/Model/BaseModel.php
- libraries/src/MVC/View/AbstractView.php
- libraries/src/Table/Table.php
- libraries/src/Updater/Update.php
- libraries/src/User/User.php
Description: These classes do not extend anymore from CMSObject
, but are including the LegacyErrorHandlingTrait
and LegacyPropertyManagementTrait
legacy traits as the CMSObject
does too. Like that does the functionality not change. Keep in mind that the functions of these traits are deprecated and exceptions should be thrown or proper getter and setters should be created.
DIC Service Provider Changes
PR: https://github.com/joomla/joomla-cms/pull/36499
The input object is now available in the DIC. You should NOT use it directly in your extensions and should continue to get the input via the application object.
\Joomla\CMS\Factory::$application is no longer sometimes set inside the Application's DIC provider but instead is now reliably set inside the includes/app.php file of each Application. It is not expected for this change to affect extension developers as there are no extension hooks this early in the Joomla Application lifecycle.
Session Object Changes
In the unusual case of creating a full custom session object of \Joomla\CMS\Session\Storage\JoomlaStorage
the
cookie domain and cookie path should now be set in the options object when creating the class. They will not be fetched
from the application object to fix various circular dependency issues. As we expect all extensions to use the principal
session created by the CMS in the application this is not expected to have a practical effect on end users.
Error reporting options in global configuration
The option to set error reporting to development in global configuration has been removed, as obsolete. Since php 5.4 error_reporting(-1) and error_reporting(E_ALL) have the same behavior. See https://www.php.net/manual/en/function.error-reporting
Wincache has been removed
WinCache is abandoned and not supported from PHP 8 onwards. Removed without replacement.
Toolbar popupButton now use JoomlaDialog
Toolbar popupButton now use JoomlaDialog, for popup rendering. Legacy Bootstrap modals still works. PR: https://github.com/joomla/joomla-cms/pull/40359
To use new dialog, following properties was added:
popupType
- popup type:inline
,iframe
,ajax
;url
- url, or css selector for content for inline popup;textHeader
- text for popup header;modalWidth
,modalHeight
- optional, width and height, any valid css value;
Use Bootstrap modal for Toolbar popupButton and property onclose
is deprecated.
Example inline button definition:
// Old:
$toolbar->popupButton('batch', 'JTOOLBAR_BATCH')
->selector('collapseModal')
->listCheck(true);
// New
$toolbar->popupButton('batch', 'JTOOLBAR_BATCH')
->popupType('inline')
->textHeader(Text::_('COM_CONTENT_BATCH_OPTIONS'))
->url('#joomla-dialog-batch')
->modalWidth('800px')
->modalHeight('fit-content')
->listCheck(true);
Example inline rendering for Batch:
Old:
<?php
echo HTMLHelper::_('bootstrap.renderModal', 'collapseModal', [
'title' => Text::_('COM_CATEGORIES_BATCH_OPTIONS'),
'footer' => $this->loadTemplate('batch_footer'),
],
$this->loadTemplate('batch_body')
);
?>
New:
<template id="joomla-dialog-batch"><?php echo $this->loadTemplate('batch_body'); ?></template>
Note: The batch buttons now is part of batch_body
.
Example iframe button definition:
// Old:
$toolbar->popupButton('example', 'Example iframe')
->url('index.php?option=com_example&view=foobar&tmpl=component');
// New
$toolbar->popupButton('example', 'Example iframe')
->popupType('iframe')
->url('index.php?option=com_example&view=foobar&tmpl=component')
->textHeader('Optional iframe title');
Plugins
Demo task plugin got removed
- PR: https://github.com/joomla/joomla-cms/pull/40147
- Description: The demo task plugin got removed as it was intended for demonstration purposes only.
Recaptcha plugin is removed, Invisible Captcha is unlocked
- PR: https://github.com/joomla/joomla-cms/pull/41530
- Description: Outdated Recaptcha plugin is removed. Invisible Captcha is unlocked and can be removed manually. It is recommended to install a new captcha from https://extensions.joomla.org/.
Codemirror plugin
PR: https://github.com/joomla/joomla-cms/pull/41070
Codemirror script has been update to 6-th version. New version are based on ES modules. Any customisation and javascript code written for Codemirror 5 is incompatible with Codemirror 6.
To initialise codemirror instance you can use helper provided by Joomla in codemirror
module, example:
$wa->getRegistry()->addExtensionRegistryFile('plg_editors_codemirror');
$wa->useScript('codemirror');
import { createFromTextarea } from 'codemirror';
const editor = await createFromTextarea(textAreaElement, options);
Captcha plugin now have to use onCaptchaSetup
event
PR: https://github.com/joomla/joomla-cms/pull/39657
Captcha plugin now have to use onCaptchaSetup
event to register own Captcha provider which should implement CaptchaProviderInterface
.
See Captcha Plugin for more information.
For external class, kind of:
public function onCaptchaSetup(CaptchaSetupEvent $event)
{
$event->getCaptchaRegistry()->add(new MyCaptchaProvider());
}
When plugin implements CaptchaProviderInterface
on its own:
public function onCaptchaSetup(CaptchaSetupEvent $event)
{
$event->getCaptchaRegistry()->add($this);
}
Captcha provider is a class that provide an abstract access to your captcha. It have all old methods, but slightly changed:
onDisplay($name = null, $id = '', $class = '')
now isdisplay(string $name = '', array $attributes = []): string
;onInit($id = '')
is removed, you should load your assets indisplay()
method;onCheckAnswer($code = null)
now ischeckAnswer(string $code = null): bool
;onSetupField($field, $element)
now issetupField(FormField $field, \SimpleXMLElement $element): void
Legacy plugins will continue to function until next major release.
Editor plugin now have to use onEditorSetup
event
PR: https://github.com/joomla/joomla-cms/pull/40082
Editor plugin now have to use onEditorSetup
event to register own Editor provider which should implement EditorProviderInterface
.
See Editors Plugin for more information.
For external class, kind of:
public function onEditorSetup(EditorSetupEvent $event)
{
$event->getEditorsRegistry()->add(new MyEditorProvider());
}
When plugin implements EditorProviderInterface
on its own:
public function onEditorSetup(EditorSetupEvent $event)
{
$event->getEditorsRegistry()->add($this);
}
Editor provider is a class that provide an abstract access to your editor. It have all old methods, but slightly changed:
onDisplay($name, $content, $width, $height, $col, $row, $buttons, $id, $asset, $author, $params)
now isdisplay(string $name, string $content = '', array $attributes = [], array $params = []): string
;onInit($id = '')
is removed, you should load your assets indisplay()
method;
Legacy plugins will continue to function until next major release.
Editor XTD buttons plugin now have to use onEditorButtonsSetup
event
PR: https://github.com/joomla/joomla-cms/pull/40082
Editor XTD buttons plugin now have to use onEditorButtonsSetup
event to register the button(s) instance.
See Editors Buttons (XTD) Plugin for more information.
Additional the button now can register a custom action, that will be run when it is clicked.
Example transforming old button to Joomla\CMS\Editor\Button
:
// Legacy
$button = new CMSObject;
$button->modal = true;
$button->link = $link;
$button->text = Text::_('PLG_ARTICLE_BUTTON_ARTICLE');
$button->name = $this->_type . '_' . $this->_name;
$button->icon = 'file-add';
return $button
// New
$button = new Button($this->_name, [
'action' => 'modal',
'link' => $link,
'text' => Text::_('PLG_ARTICLE_BUTTON_ARTICLE'),
'name' => $this->_type . '_' . $this->_name,
'icon' => 'file-add'
]);
$event->getButtonsRegistry()->add($button);
Legacy plugins will continue to function until next major release.
Plugin constructor doesn't contain the assignment operator
- PR: https://github.com/joomla/joomla-cms/pull/40746
- Description: The constructor of the
CMSPlugin
class doesn't contain now the extra assign operator for the dispatcher as objects are always passed by reference. So constructors in plugins should now be written in the following way:
public function __construct(DispatcherInterface $dispatcher, array $config, more arguments)
{
parent::__construct($dispatcher, $config);
// Assign the extra arguments to internal variables
}
Module event onRenderModule
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41780 https://github.com/joomla/joomla-cms/pull/41413
- Description:
onRenderModule
should now use$event->getAttributes()
and$event->updateAttributes($attributes)
, instead of modification by reference. The referencing still works but will be removed in the future.
// Old
function onRenderModule($module, &$attributes){
$attributes['foo'] = 'bar';
}
// New
function onRenderModule(Joomla\CMS\Event\Module\BeforeRenderModuleEvent $event){
$attributes = $event->getAttributes();
$attributes['foo'] = 'bar';
$event->updateAttributes($attributes);
}
Module event onAfterRenderModules
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41413
- Description:
onAfterRenderModules
should now use$event->getContent()
and$event->updateContent($content)
, instead of modification by reference. The referencing still works but will be removed in the future.
// Old
function onAfterRenderModules(&$content, &$params){
$content .= '<strong>foobar</strong>';
}
// New
function onAfterRenderModules(Joomla\CMS\Event\Module\AfterRenderModulesEvent $event){
$content = $event->getContent();
$content .= '<strong>foobar</strong>';
$event->updateContent($content);
}
Module events onPrepareModuleList
, onAfterModuleList
, onAfterCleanModuleList
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41780
- Description:
onPrepareModuleList
,onAfterModuleList
,onAfterCleanModuleList
should now use$event->getModules()
and$event->updateModules($module)
, instead of modification by reference. The referencing still works but will be removed in the future. The modules argument is now always initialised with an empty array. This is needed for consistency (typehint) and to allow references for legacy plugins.
// Old
function onAfterModuleList(&$modules){
unset($modules[3]);
}
// New
function onAfterModuleList(Joomla\CMS\Event\Module\AfterModuleListEvent $event){
$modules = $event->getModules();
unset($modules[3]);
$event->updateModules($modules);
}
Custom Fields event onCustomFieldsAfterPrepareField
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41495
- Description:
onCustomFieldsAfterPrepareField
should now use$event->getValue()
and$event->updateValue($value)
, instead of modification by reference. The referencing still works but will be removed in the future.
// Old
function onCustomFieldsAfterPrepareField($context, $item, $field, &$value){
$value .= '<strong>foobar</strong>';
}
// New
function onCustomFieldsAfterPrepareField(Joomla\CMS\Event\CustomFields\AfterPrepareFieldEvent $event){
$value = $event->getValue();
$value .= '<strong>foobar</strong>';
$event->updateValue($value);
}
Installer event onInstallerBeforeInstallation
, onInstallerBeforeInstaller
, onInstallerAfterInstaller
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41518
- Description:
onInstallerBeforeInstallation
,onInstallerBeforeInstaller
should now use$event->getPackage()
and$event->updatePackage($package)
, instead of modification by reference. The referencing still works but will be removed in the future.
// Old
function onInstallerBeforeInstaller($model, &$package){
$package['foo'] = 'bar';
}
// New
function onInstallerBeforeInstaller(Joomla\CMS\Event\Installer\BeforeInstallerEvent $event){
$package = $event->getPackage() ?: [];
$package['foo'] = 'bar';
$event->updatePackage($package);
}
Additionally onInstallerAfterInstaller
, should use $event->getInstallerResult()
, $event->updateInstallerResult($result)
, and $event->getMessage()
, $event->updateMessage($message)
.
Installer event onInstallerBeforePackageDownload
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41518
- Description:
onInstallerBeforePackageDownload
should now use$event->getUrl()
and$event->updateUrl($url)
,$event->getHeaders()
and$event->updateHeaders($headers)
, instead of modification by reference. The referencing still works but will be removed in the future.
// Old
function onInstallerBeforePackageDownload(&$url, &$headers){
$url .= '&foo=bar';
}
// New
function onInstallerBeforePackageDownload(Joomla\CMS\Event\Installer\BeforePackageDownloadEvent $event){
$url = $event->getUrl();
$url .= '&foo=bar';
$headers = $event->getHeaders();
$headers['foo'] = 'bar';
$event->updateUrl($url);
$event->updateHeaders($headers);
}
Content event onContentBeforeValidateData
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41780
- Description:
onContentBeforeValidateData
should now use$event->getData()
and$event->updateData($data)
, instead of modification by reference. The referencing still works but will be removed in the future.
// Old
function onContentBeforeValidateData($context, &$data){
$data['foo'] = 'bar';
}
// New
function onContentBeforeValidateData(Joomla\CMS\Event\Model\BeforeValidateDataEvent $event){
$data = $event->getData();
$data['foo'] = 'bar';
$event->updateData($data);
}
Content event onContentPrepareData
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41780
- Description:
onContentPrepareData
should now use$event->getData()
and$event->updateData($data)
, instead of modification by reference. The referencing still works but will be removed in the future.
// Old
function onContentPrepareData($context, &$data){
$data['foo'] = 'bar';
}
// New
function onContentPrepareData(Joomla\CMS\Event\Model\PrepareDataEvent $event){
// Note: The data may be or Object or Array, following changes need only when data is an Array
$data = $event->getData();
$data['foo'] = 'bar';
$event->updateData($data);
}
Contact event onValidateContact
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41780
- Data modification in
onValidateContact
event is not allowed, useonSubmitContact
event instead.
Contact event onSubmitContact
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41780
- Description:
onSubmitContact
should now use$event->getData()
and$event->updateData($data)
, instead of modification by reference. The referencing still works but will be removed in the future.
// Old
function onSubmitContact($contact, &$data){
$data['foo'] = 'bar';
}
// New
function onSubmitContact(Joomla\CMS\Event\Contact\SubmitContactEvent $event){
$data = $event->getData();
$data['foo'] = 'bar';
$event->updateData($data);
}
Menu event onPreprocessMenuItems
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41780
- Description:
onPreprocessMenuItems
should now use$event->getItems()
and$event->updateItems($items)
, instead of modification by reference. The referencing still works but will be removed in the future.
// Old
function onPreprocessMenuItems($context, &$items, $params, $enabled){
unset($items[3]);
}
// New
function onPreprocessMenuItems(Joomla\CMS\Event\Menu\PreprocessMenuItemsEvent $event){
$items = $event->getItems();
unset($items[3]);
$event->updateItems($items);
}
Menu event onAfterGetMenuTypeOptions
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41780
- Description:
onAfterGetMenuTypeOptions
should now use$event->getItems()
and$event->updateItems($items)
, instead of modification by reference. The referencing still works but will be removed in the future.
// Old
function onAfterGetMenuTypeOptions(&$items, $model){
unset($items[3]);
}
// New
function onAfterGetMenuTypeOptions(Joomla\CMS\Event\Menu\AfterGetMenuTypeOptionsEvent $event){
$items = $event->getItems();
unset($items[3]);
$event->updateItems($items);
}
User group event onUserBeforeDeleteGroup
and onUserAfterDeleteGroup
backward compatibility
- PR: https://github.com/joomla/joomla-cms/pull/41916
- Description:
onUserBeforeDeleteGroup
andonUserAfterDeleteGroup
is now compatible withonContentBeforeDelete
andonContentAfterDelete
events. Old attributes still work but will be removed in the future.
// Old
function onUserBeforeDeleteGroup($data){
}
// New
function onUserBeforeDeleteGroup(Joomla\CMS\Event\User\UserGroupBeforeDeleteEvent $event){
$context = $event->getContext();
$data = $event->getItem()->getProperties();
}
CategoryFeedView Inheritance
\Joomla\CMS\MVC\View\CategoryFeedView
extends directly \Joomla\CMS\MVC\View\AbstractView
(previously it extended \Joomla\CMS\MVC\View\HtmlView
which in turn inherited from AbstractView
) as it isn't rendering any HTML. We do not expect this to have a major influence on extensions.
Removed 3rd party libraries
Joomla\Ldap
Our own LDAP library is no longer compatible with Joomla 5, it has been removed. As part of this we removed the following class aliases from the b/c plugin:
- JClientLdap -> \Joomla\Ldap\LdapClient
- JLDAP -> \Joomla\Ldap\LdapClient
Joomla 4 and 5 includes the symfony Ldap package.
Change ordered lists in com_content links to unordered lists
The links in com_content > category > blog-links.php and com_content > featured > default-links.php use <ul></ul>
instead of <ol></ol>
.
Changes made via PR #40629
TinyMCE
CSS classes defined in the editor.css file of a template are no longer displayed in the formats dropdown menu or button. They can be displayed if you wish by enabling the new TinyMCE plugin option CSS Classes Menu.