Hooks allow MediaWiki core to call extensions, or allow one extension to call another. Starting in MediaWiki 1.35, every hook called by core has an associated PHP interface with a single method. To handle a hook in an extension, you create a handler class that implements that interface.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/wikimedia/mediawiki/llms.txt
Use this file to discover all available pages before exploring further.
How hooks work
HookContainer (in includes/HookContainer/HookContainer.php) is the service that maintains all registered handlers and calls them when HookContainer::run() is invoked. The container is not aware of hook interfaces or parameter types — it only deals with callables.
When a hook fires, HookContainer::run() iterates through registered handlers in order. For each handler:
- If the handler returns
false, iteration stops andrun()returnsfalse(the hook is aborted). - If the handler returns
trueornull(no explicit return), iteration continues. - Any other return value throws an
UnexpectedValueException.
Registering hooks in extension.json
Hook registration uses two coordinated fields:HookHandlers and Hooks.
HookHandlers
HookHandlers maps handler names to ObjectFactory specifications. The simplest form names a class:
Hooks
Hooks maps the hook name (without the trailing Hook suffix) to a handler name from HookHandlers:
Implementing a hook handler class
Each hook has a corresponding interface. The interface name is the hook name withHook appended. The method name is on followed by the hook name.
For the Mash hook, the extension defines:
src/HookHandler.php
BeforePageDisplay:
src/HookHandler.php
src/HookHandler.php
Service injection into hook handlers
Theservices key in HookHandlers lists MediaWiki service names to inject into the handler’s constructor via ObjectFactory. Services are prepended before any args.
extension.json
src/HookHandler.php
The noServices option
Calling a hook with thenoServices option disables service injection entirely. If a handler for such a hook declares services in its HookHandlers spec, HookContainer throws an UnexpectedValueException when the hook fires:
noServices, your HookHandlers entry must not include a services list.
Aborting hooks
Returnfalse from a handler to abort the hook and stop further handlers from being called:
HookContainer::run() returns the boolean result to the caller. Most hook callers do not check this return value — aborting only matters for hooks that are explicitly documented as abortable.
Some hooks are declared non-abortable by passing
[ 'abortable' => false ] to HookContainer::run(). Returning false from a handler for such a hook throws an UnexpectedValueException. Check hook documentation before relying on abort behaviour.Parameters passed by reference
Many hooks pass parameters by reference. Modifying a reference parameter is the standard way for a handler to return data to the caller:Calling hooks from your extension
Extensions that define their own hooks should create a hook runner class, mirroring the pattern used in core’sHookRunner.
To call the hook Mash as defined in the FoodProcessor extension:
src/HookRunner.php
HookContainer as a constructor dependency:
Defining custom hooks for your extension
If your extension exposes hooks for other extensions to handle, follow these steps:Create a hook interface
Place the interface in a
Hook subnamespace relative to your extension’s primary namespace. The method name is the hook name prefixed with on.src/Hook/MashHook.php
Create a hook runner class
The hook runner implements the interface and proxies calls to
HookContainer::run().src/HookRunner.php
Deprecating hooks you have defined
When you want to retire a hook your extension defines, use theDeprecatedHooks attribute in extension.json:
@deprecated to the hook interface doc comment — this deprecates implementing the interface (not just calling it):
Hooks registration. This activates call filtering: when MediaWiki knows the hook is deprecated, handlers that acknowledge deprecation are skipped entirely.
Call filtering example
The FoodProcessor example illustrates how call filtering provides both forwards and backwards compatibility:| MediaWiki | FoodProcessor | Result |
|---|---|---|
| 2.0 (Mash deprecated) | 1.0 (no acknowledgement) | onMash is called with a deprecation warning |
| 2.0 (Mash deprecated) | 2.0 (deprecated: true) | onMash is filtered; onSlice is called |
| 1.0 (Mash not deprecated) | 2.0 (deprecated: true) | onMash is called since it is not yet deprecated; onSlice is not called |
Silent deprecation
To deprecate a hook without immediately raising warnings — a “soft” deprecation — use thesilent flag. Call filtering is still activated, allowing extensions to migrate without a noisy warning period.
