Joomla Plugins & events changes: Joomla 3 → 4, 5 and 6

6 issues in this guide

Plugins stop loading when they still extend JPlugin or register through JDispatcher. This guide groups 6 entries: onContentPrepare / onAfterDispatch / …, function onContentPrepare(...), JDispatcher::getInstance(), JPlugin, JPluginHelper, plugins/content/foo/foo.xml with a single php file. The replacement pattern is CMSPlugin (or a dedicated subscriber class) implementing SubscriberInterface::getSubscribedEvents(), with PluginHelper for loading — all under Joomla\CMS\Plugin. Event method names stay familiar; the registration model does not. Manifest filename and folder layout for plugins also moved after Joomla 1.5-style discover installs. Hop mix: 1 at Joomla 3 → 4; 5 at Joomla 5 → 6. Disable the BC plugin on Joomla 5 to surface Class "JPlugin" / "JDispatcher" fatals, then convert each listener to a subscribed event map using the before/after blocks below. Body rewrites that once called JResponse::getBody() belong with document and Web Asset Manager approaches documented in the media-assets guide. Catalog replacements in this guide include onContentPrepare / onAfterDispatch / … → SubscriberInterface::getSubscribedEvents(); function onContentPrepare(...) → CMSPlugin + SubscriberInterface::getSubscribedEvents(); JDispatcher::getInstance() → Event dispatcher + SubscriberInterface; JPlugin → Joomla\CMS\Plugin\CMSPlugin. Open each h2 anchor for the full before/after, fix list, and error strings shipped in the reference data.

EVENT-LIST-001

onContentPrepare / onAfterDispatch / …

Core plugin event names (J3 methods → subscribers)

The event names still fire. The implementation must become a subscriber on native Joomla 6. Search this entry for any onContent*/onUser*/onAfter* method.

onContentPrepare / onAfterDispatch / … → SubscriberInterface::getSubscribedEvents()

Dies at Joomla 5 → 6
Dies at Joomla 5 → 6J3: Works nativelyJ4: Changed behaviourJ6: Changed behaviourBC plugin: partialArchitecture change — no auto-fixEvents / plugins

Symptoms people search

onContentPrepare not firing · onAfterDispatch · onBeforeCompileHead · onUserLogin · onContentBeforeSave

Replace this code

Swap onContentPrepare / onAfterDispatch / … for SubscriberInterface::getSubscribedEvents().

Joomla 3

Remove or stop calling this

public function onAfterInitialise() {}
public function onAfterRoute() {}
public function onAfterDispatch() {}
public function onBeforeCompileHead() {}
public function onContentPrepare($ctx, &$article, &$params, $page=0) {}
public function onContentAfterTitle(...) {}
public function onContentBeforeDisplay(...) {}
public function onContentAfterDisplay(...) {}
public function onContentPrepareForm($form, $data) {}
public function onContentBeforeSave(...) {}
public function onContentAfterSave(...) {}
public function onContentBeforeDelete(...) {}
public function onContentChangeState(...) {}
public function onUserLogin(...) {}
public function onUserLogout(...) {}
public function onUserAfterSave(...) {}
public function onExtensionAfterInstall(...) {}
public function onDisplay(...) {}

Joomla 4 / 6

Use this instead

Map each name in getSubscribedEvents() to a method that receives a typed Event. Do not take &$article by reference.

How to fix it

  1. 1Implement SubscriberInterface.
  2. 2Register every event you handled as a J3 method.
  3. 3Read arguments from the Event object.

Also known as

onAfterInitialise · onAfterRoute · onAfterDispatch · onBeforeCompileHead · onAfterRender · onContentPrepare · onContentAfterTitle · onContentBeforeDisplay · onContentAfterDisplay · onContentPrepareForm · onContentBeforeSave · onContentAfterSave · onContentBeforeDelete · onContentChangeState · onUserLogin · onUserLogout · onUserAfterSave · onExtensionAfterInstall · onDisplay

There is no 1:1 swap for this one. The architecture changed. If you cannot rewrite it, Infyways can.

EVENT-SUBSCRIBER-001

function onContentPrepare(...)

JPlugin onX methods vs SubscriberInterface

Method-name events still fire, but Joomla 4+ wants subscribers with typed Event objects. Native Joomla 6 quality means SubscriberInterface, not a JPlugin with onContentPrepare by convention.

function onContentPrepare(...) → CMSPlugin + SubscriberInterface::getSubscribedEvents()

Dies at Joomla 5 → 6
Dies at Joomla 5 → 6J3: Works nativelyJ4: Changed behaviourJ6: Changed behaviourBC plugin: partialArchitecture change — no auto-fixEvents / plugins

Symptoms people search

plugin does not run on Joomla 6 · onContentPrepare never called

Replace this code

Swap function onContentPrepare(...) for CMSPlugin + SubscriberInterface::getSubscribedEvents().

Joomla 3

Remove or stop calling this

class PlgContentLms extends JPlugin {
    public function onContentPrepare($context, &$article, &$params, $page = 0) {}
}

Joomla 4 / 6

Use this instead

class Lms extends CMSPlugin implements SubscriberInterface {
    public static function getSubscribedEvents(): array {
        return ['onContentPrepare' => 'prepare'];
    }
    public function prepare(Event $event): void {}
}

How to fix it

  1. 1Extend CMSPlugin and implement SubscriberInterface.
  2. 2Map event names in getSubscribedEvents().
  3. 3Read arguments from the Event object, not &$article by reference.

Also known as

SubscriberInterface · onContentPrepare · onAfterRender · JPlugin

There is no 1:1 swap for this one. The architecture changed. If you cannot rewrite it, Infyways can.

JDISPATCHER-CLASS-001

JDispatcher::getInstance()

JDispatcher / JEventDispatcher

The old dispatcher was removed in Joomla 4. Plugins should subscribe to events, not trigger JDispatcher.

JDispatcher::getInstance() → Event dispatcher + SubscriberInterface

Dies at Joomla 3 → 4
Dies at Joomla 3 → 4J3: Works nativelyJ4: Removed — fatalJ6: Removed — fatalBC plugin: no — already dead on J4Architecture change — no auto-fixEvents / plugins

What you will see

  • Class "JDispatcher" not found
  • Class "JEventDispatcher" not found

Symptoms people search

plugin events never fire · trigger() fatal

Replace this code

Swap JDispatcher::getInstance() for Event dispatcher + SubscriberInterface.

Joomla 3

Remove or stop calling this

$dispatcher = JDispatcher::getInstance();
$dispatcher->trigger('onFoo', $args);

Joomla 4 / 6

Use this instead

$dispatcher = Factory::getApplication()->getDispatcher();
// Plugins should implement SubscriberInterface

How to fix it

  1. 1Stop calling JDispatcher::getInstance().
  2. 2For plugins, implement SubscriberInterface::getSubscribedEvents().
  3. 3To dispatch, use the application dispatcher and Event classes.

Also known as

JDispatcher · JEventDispatcher · trigger(

There is no 1:1 swap for this one. The architecture changed. If you cannot rewrite it, Infyways can.

JPLUGIN-CLASS-001

JPlugin

JPlugin class name

JPlugin is a Joomla 3 global class. Joomla 4 still has an alias. Joomla 5 needs the Behaviour – Backward Compatibility plugin. Native Joomla 6 does not load that alias — you get Class "JPlugin" not found.

JPlugin → Joomla\CMS\Plugin\CMSPlugin

Dies at Joomla 5 → 6
Dies at Joomla 5 → 6J3: Works nativelyJ4: Alias (old name still resolves)J6: Removed — fatalBC plugin: covers the class nameMechanical renameEvents / plugins

What you will see

  • Class "JPlugin" not found
  • Class 'JPlugin' not found
  • Failed to open stream: JPlugin

Symptoms people search

white screen after disabling compatibility plugin · class not found on Joomla 6 · works on Joomla 5 until I turn off backward compatibility · plugin not loading

Replace this code

Swap JPlugin for Joomla\CMS\Plugin\CMSPlugin.

Joomla 3

Remove or stop calling this

JPlugin::getInstance();
// or new JPlugin()

Joomla 4 / 6

Use this instead

use Joomla\CMS\Plugin\CMSPlugin;

// Call the namespaced class. Do not keep the J prefix.

How to fix it

  1. 1Add a use statement for Joomla\CMS\Plugin\CMSPlugin.
  2. 2Replace every JPlugin with the short class name from that use line.
  3. 3Disable Behaviour – Backward Compatibility on a Joomla 5 staging site. If it fatals, this class is still in the code.

Also known as

JPlugin · Joomla\CMS\Plugin\CMSPlugin · class alias · J prefix

JPLUGINHELPER-CLASS-001

JPluginHelper

JPluginHelper class name

JPluginHelper is a Joomla 3 global class. Joomla 4 still has an alias. Joomla 5 needs the Behaviour – Backward Compatibility plugin. Native Joomla 6 does not load that alias — you get Class "JPluginHelper" not found.

JPluginHelper → Joomla\CMS\Plugin\PluginHelper

Dies at Joomla 5 → 6
Dies at Joomla 5 → 6J3: Works nativelyJ4: Alias (old name still resolves)J6: Removed — fatalBC plugin: covers the class nameMechanical renameEvents / plugins

What you will see

  • Class "JPluginHelper" not found
  • Class 'JPluginHelper' not found
  • Failed to open stream: JPluginHelper

Symptoms people search

white screen after disabling compatibility plugin · class not found on Joomla 6 · works on Joomla 5 until I turn off backward compatibility

Replace this code

Swap JPluginHelper for Joomla\CMS\Plugin\PluginHelper.

Joomla 3

Remove or stop calling this

JPluginHelper::getInstance();
// or new JPluginHelper()

Joomla 4 / 6

Use this instead

use Joomla\CMS\Plugin\PluginHelper;

// Call the namespaced class. Do not keep the J prefix.

How to fix it

  1. 1Add a use statement for Joomla\CMS\Plugin\PluginHelper.
  2. 2Replace every JPluginHelper with the short class name from that use line.
  3. 3Disable Behaviour – Backward Compatibility on a Joomla 5 staging site. If it fatals, this class is still in the code.

Also known as

JPluginHelper · Joomla\CMS\Plugin\PluginHelper · class alias · J prefix

PLUGIN-XML-FILENAME-001

plugins/content/foo/foo.xml with a single php file

Plugin XML: only <filename plugin="x">x.php</filename>

A single php file still installs. Native Joomla 4+ plugins use a service provider and a subscriber class. The J3 file will run as CMSPlugin until you rewrite events.

plugins/content/foo/foo.xml with a single php file → Namespaced plugin class + services/provider.php

Dies at Joomla 5 → 6
Dies at Joomla 5 → 6J3: Works nativelyJ4: Changed behaviourJ6: Changed behaviourBC plugin: partialYou rewrite thisEvents / plugins

Symptoms people search

plugin installs but events never fire on J6 · no provider.php

Replace this code

Swap plugins/content/foo/foo.xml with a single php file for Namespaced plugin class + services/provider.php.

Joomla 3

Remove or stop calling this

<files>
  <filename plugin="lms">lms.php</filename>
</files>

Joomla 4 / 6

Use this instead

<namespace path="src">Acme\Plugin\Content\Lms</namespace>
<files>
  <folder plugin="lms">services</folder>
  <folder>src</folder>
</files>

How to fix it

  1. 1Add services/provider.php.
  2. 2Move the plugin class into src/ and implement SubscriberInterface.

Also known as

filename plugin · plugin xml · services/provider.php

There is no 1:1 swap for this one. The architecture changed. If you cannot rewrite it, Infyways can.

Start a project

Have something
to build?

Tell us what you are building. You will hear back from an engineer within one business day.

hello@infyways.com · Remote, working across time zones

Tell us about your project

Fill out the quick form and we'll reach out.