Руководство:Регистрация расширений
Версия MediaWiki: | ≥ 1.25 Gerrit change 166705 |
Регистрация расширения - механизм, который MediaWiki использует для загрузки расширений и стилей оформления(skin).
Вы помещаете конфигурационные данные в файл extension.json
или skin.json
в корневой директории вашего расширения или темы оформления, и MediaWiki использует его, что бы зарегистрировать расширение или тему оформления.
Миграция для администраторов
До MediaWiki 1.25, конфигурация для расширений и тем оформления находилась в PHP файле с именем расширения или темы оформления, например MyExtension.php
или MySkin.php
.
require_once "$IP/extensions/Hello/Hello.php";
require_once "$IP/extensions/FooBar/FooBar.php";
$wgFooBarEnable = true;
require_once "$IP/skins/Baz/Baz.php";
require_once "/tmp/extension/some/where/else/BarFoo/BarFoo.php";
Сейчас можно преобразовать в:
wfLoadExtensions( [ 'Hello', 'FooBar' ] );
$wgFooBarEnable = true;
wfLoadSkin( 'Baz' );
wfLoadExtension( 'BarFoo', '/tmp/extension/some/where/else/BarFoo/extension.json' );
Custom locations
Это должно быть сделано до того, как вы загрузите расширение или стиль оформления.
- Если вы храните расширение не в
$IP/extensions
, вам нужно переопределить$wgExtensionDirectory
.- If one or more of your extensions are stored in additional locations, use the second parameter of
wfLoadExtension()
to specify the location of the.json
file for each of those extensions. wfLoadExtensions()
(plural) always uses$wgExtensionDirectory
and cannot be overridden.
- If one or more of your extensions are stored in additional locations, use the second parameter of
$wgExtensionDirectory = '/some/path'; wfLoadExtension( 'FooBar' ); // Looks in $wgExtensionDirectory for /some/path/FooBar/extension.json wfLoadExtension( 'Hello', '/some/other/path/HelloV2/Hello.json' ); // Looks for /some/other/path/HelloV2/Hello.json
- Если вы храните стиль оформления не в
$IP/skins
, вам нужно переопределить плохо названную$wgStyleDirectory
.- If one or more of your skins are stored in additional locations, use the second parameter of
wfLoadSkin()
to specify the location of the.json
file for each of those skins. wfLoadSkins()
(plural) always uses$wgStyleDirectory
and cannot be overridden.
- If one or more of your skins are stored in additional locations, use the second parameter of
$wgStyleDirectory = '/my/skins'; wfLoadSkins( [ 'BarBaz', 'BazBar' ] ); // Looks in $wgStyleDirectory for both /my/skins/BarBaz/skin.json and /my/skins/BazBar/skin.json wfLoadSkin( 'BamBam', '/yet/another/path/BamBam/skin.json' ); // Looks for /yet/another/path/BamBam/skin.json
Миграция для разработчиков расширений
Since MW 1.30, namespace IDs defined in extension.json
can be overwritten locally, by defining the respective constant in LocalSettings.php
before loading the extension.
Consider for instance the following namespace declaration in a extension.json
file:
"namespaces": [
{
"id": 1212,
"constant": "NS_FOO",
"name": "Foo"
},
{
"id": 1213,
"constant": "NS_FOO_TALK",
"name": "Foo_Talk"
}
]
This would per default cause the constant NS_FOO to be defined to have the value 1212. However, this can be overwritten by defining the respective constant in LocalSettings.php:
define( 'NS_FOO', 6688 );
define( 'NS_FOO_TALK', 6689 );
wfLoadExtension( "Foo" );
This would cause the "Foo" namespace to be registered with the ID 6688 instead of 1212. When overriding namespace IDs, don't forget that all talk namespaces must have odd IDs, and the ID of the talk namespace must always be the subject namespace's ID plus one.
- See also the extension registration wall of sadness (now superpowers).
Скрипт maintenance/convertExtensionToRegistration.php
поможет вам мигрировать с PHP точек входа(?) на файл метеданных JSON.
Если ваше расширение поддерживает старые версии MediaWiki, вы должны оставить вашу точку входа FooBar/FooBar.php
пока не перестанете поддерживать старые версии.
Пример запуска команды:
$ cd core
$ php maintenance/convertExtensionToRegistration.php extensions/MassMessage/MassMessage.php
$ php maintenance/convertExtensionToRegistration.php skins/MonoBook/MonoBook.php --skin
Возможно вам надо деинсталлировать ваше расширение из LocalSettings.php
, если вы получаете ошибки о том, что константы или функции не могут быть переопределены.
Вы должны заменить вашу PHP точку входа (файл FooBar.php) на что-то наподобие следующего, что бы не сломать wiki в процессе обновления.
<?php
if ( function_exists( 'wfLoadExtension' ) ) {
wfLoadExtension( 'FooBar' );
// Keep i18n globals so mergeMessageFileList.php doesn't break
$wgMessagesDirs['FooBar'] = __DIR__ . '/i18n';
$wgExtensionMessagesFiles['FooBarAlias'] = __DIR__ . '/FooBar.alias.php';
wfWarn(
'Deprecated PHP entry point used for the FooBar extension. ' .
'Please use wfLoadExtension() instead, ' .
'see https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extension_registration for more details.'
);
return;
} else {
die( 'This version of the FooBar extension requires MediaWiki 1.29+' );
}
Или темы оформления
<?php
if ( function_exists( 'wfLoadSkin' ) ) {
wfLoadSkin( 'FooBar' );
// Keep i18n globals so mergeMessageFileList.php doesn't break
$wgMessagesDirs['FooBar'] = __DIR__ . '/i18n';
$wgExtensionMessagesFiles['FooBarAlias'] = __DIR__ . '/FooBar.alias.php';
wfWarn(
'Deprecated PHP entry point used for the FooBar skin. Please use wfLoadSkin instead, ' .
'see https://www.mediawiki.org/wiki/Extension_registration for more details.'
);
return;
} else {
die( 'This version of the FooBar skin requires MediaWiki 1.25+' );
}
Вспомогательная документация
PHP точки входа обычно имеют документацию настроек конфигурации, которая полезна и не должна потеряться.
К сожалению JSON не поддерживает комментариев. Рекомендуется переместить документацию конфигурации в файл README
репозитория расширения.
Вы также должны задокументировать конфигурацию в вики на странице вашего расширения Extension:MyExtension.
Возможно также добавить некоторую документацию напрямую в extension.json
.
Регистрация расширения игнорирует любые ключи в extension.json
, начинающиеся с '@
' в корне структуры, так что вы можете поместить комментарии в этих местах JSON-файла. Например:
{
"@note": "This file must be kept in sync with LocalisationUpdate.php",
"@name": ...
Формат версии 1 extension.json
допускает @note
в разделе config
, но это не рекомендуется и не поддерживается с версии 2. Вместо этого следует использовать поле description
переменной config.
Это должно использоваться только для кратких пометок и комментариев.
Возможности
Если вы загружаете большое количество расширений, регистрация расширений может быть ускорена, если у вас установлен APC (или APCu). Расширения, которые загружаются вместе с wfLoadExtensions
(с множественными -s) будут кэшироваться вместе.
Атрибуты
Повторяющаяся проблема - как "зарегистрировать" что-то с другим расширением.
Обычно это означает, что вы хотите загрузить одно расширение перед другим.
Например VisualEditor имеет $wgVisualEditorPluginModules
, который позволяет расширениям загружать их модули.
Тем не менее в точке входа VisualEditor'а имеется:
$wgVisualEditorPluginModules = [];
Это означает, что если расширение добавляется в массив до VisualEditor'а, VE сотрет эту запись в массиве.
Некоторые расширения зависели от определенного порядка загрузки, другие взламывали это при помощи $wgExtensionFunctions
.
Регистрация расширений решает эту проблему при помощи "атрибутов".
В расширении Math его extension.json
имеет что-то следующее
{
"VisualEditorPluginModules": [
"ext.math.visualEditor"
]
}
Starting with manifest version 2, the attributes need to be defined in the separate section attributes
.
The attributes
node needs to be an object with the extension name as key and an object of attribute/value pairs as the value. Be aware that the key in the subobject must not contain the extension name!
{
"attributes": {
"VisualEditor": {
"PluginModules": [
"ext.math.visualEditor"
]
}
},
"manifest_version": 2
}
Когда VisualEditor хочет получить доступ к атрибуту, он использует:
ExtensionRegistry::getInstance()->getAttribute( 'VisualEditorPluginModules' );
Требования (зависимости)
Extension registration has a requires
section, which acts similar to Composer's require
section.
It allows an extension developer to specify several requirements for the extension, such as a specific MediaWiki version (or greater/less than) or another extension/skin.
For example, to add a dependency on a MediaWiki version that is greater than 1.26.0, you can add the following code to extension.json
: [1]
{
"requires": {
"MediaWiki": ">= 1.26.0"
}
}
The key of the requires
object is the name of the dependency (prior to MediaWiki 1.29.0 only MediaWiki
was supported), the value is a valid version constraint (the format has to match the one used by composer).
In MediaWiki 1.29.0 and above you can also add dependencies on skins and other extensions like so:
{
"requires": {
"MediaWiki": ">= 1.29.0",
"extensions": {
"ExampleExtension": "*"
},
"skins": {
"ExampleSkin": "*"
}
}
}
- The extensions and skins specified here must also use the extension registrations system described on this page for this to work.
- The string added to specify the extension or skin must be identical to the string specified in the "name" field of the respective "extension.json" or "skin.json" file.
- For extensions using Wikimedia continuous integration, dependencies also need to be added to zuul/parameter_functions.py
In MediaWiki 1.33.0(?!??) and above you can also add dependencies on PHP like so:
{
"requires": {
"MediaWiki": ">= 1.33.0",
"platform": {
"php": ">= 7.0.3"
}
}
}
Check if an extension is loaded without actually requiring it
Many extensions may provide features that work only if another extension is loaded too, without really needing this feature for the core extension function to work. As an example: If extension B is loaded, extension A can provide a real WYSIWYG editor, otherwise it will use a simple textarea. Extension A can profit from extension B (if it is loaded), but doesn't require it to be loaded to work properly. For this, you generally check, if the extension is loaded, rather than adding it as a hard dependency.
To implement a standardized way of checking, if an extension is loaded or not (without the need of extra work in an extension that is a soft-dependency in another one), extension registration can be used. It implements an isLoaded
method, which returns a simple boolean, if the extension is loaded or not (the extension needs to be loaded with extension registration for this to work). Example:
if ( ExtensionRegistry::getInstance()->isLoaded( 'ExtensionB' ) ) {
// do things only, if extension B is loaded
}
Версия MediaWiki: | ≥ 1.32 Gerrit change 455752 |
Since MediaWiki 1.32 it's also possible to check if an extension is loaded and satisfies a given composer version constraint:
if ( ExtensionRegistry::getInstance()->isLoaded( 'ExtensionB', '>=1.2' ) ) {
// do things only, if extension B is loaded and has a version of 1.2 or greater.
}
If you would like to check if a specific version of an extension is loaded in earlier versions of MediaWiki, information like that can be extracted with the getAllThings
method, which returns credit information for all loaded extensions. Example:
$bVersion = ExtensionRegistry::getInstance()->getAllThings()['ExtensionB']['version'] ?? null;
if ( $bVersion !== null && version_compare( $bVersion, '2.1.0', '>=' ) ) {
// do things only, if extension B is loaded and has a version number greater than or equal to 2.1.0
}
Alternatively, if the extension B defines a special constant meant for this purpose during loading, it is possible to check, if it is defined:
if ( defined( 'ExtensionBVersion' ) ) { // You could also check for a version, if the constant holds the version
// do things only, if extension B is loaded
}
A more brittle way, that should be avoided is to check if a specific class of extension B exists or not, e.g. using this code:
if ( class_exists( 'ExtensionBHooks' ) ) {
// do things only, if extension B its classes exist
}
This might break if the extension exists in the file system but is not loaded, e.g. if composer was used for autoloading. If the class was renamed or ceases to exist (e.g. because it is not package public) this will also break.
In general it is preferred to share code via composer components instead of extensions. If the classes of an extension only need to exist, but the extension does not need to be configured nor loaded, for what you want to do, that is a strong indicator that that code should be split off into a composer component you should depend on instead.
Конфиги (настройки вашего расширения/стиля)
By default, extension.json
assumes that your config settings start with a "wg" prefix.
If that's not the case, you can override the prefix by using a special key:
{
"config": {
"_prefix": "eg",
"MyExtSetting": true
}
}
That would use a prefix of "eg", and set the global variable $egMyExtSetting
to true.
Starting with manifest version 2, the configuration section of extension registration provides a lot more features and allows you to describe your configuration options with much more detail. Instead of having a single key -> value store for your configuration options, you can also add the following information.
The general structure of the config
changes slightly to the following, more object-oriented version:
{
"config_prefix": "eg",
"config": {
"MyExtSetting": {
"value": true,
"path": false,
"description": "The description for the configuration",
"descriptionmsg": "myextension-config-myextsetting",
"public": true
}
},
"manifest_version": 2
}
value
The value of the configuration moved to this place. This is the only required key for a configuration object.
path
The boolean value of the path
key identifies, if the value of the configuration option should be interpreted as a filesystem path, relative to the extension directory root.
E.g., if the value of the configuration is myFile.png
and the path
is true, the actual value will be /path/to/the/wiki/extensions/MyExtension/myFile.png
.
description
The description
key for a configuration option can hold a non-localized string, which can be used to explain the configuration option to other developers or the users (system administrators) of your extension.
It may also be used as tooltip text on the parameters section of the extension infobox on the MediaWiki.org extension description page.
The value of the description key is usually not exposed to the frontend of the wiki, however, take a look to the outlook for more information how this feature could be used in the future!
descriptionmsg
There's also the possibility to add a message key of MediaWiki's internal localisation system as a description (descriptionmsg
), which, in the future, will be used to expose the description in the frontend of the MediaWiki installation.
public / private
This option is a boolean, which defaults to false
, which means, that the configuration option and the value is marked as "private".
This value is not used anywhere at the moment, take a look to the outlook to find out more about this option.
Outlook
The mentioned changes above are also preparation steps for an improved configuration management in MediaWiki. The above changes allow us to, e.g., expose the configuration options of extensions in the MediaWiki UI. For this, the localised description message (descriptionmsg
and description
) and the indication, if the configuration option should be exposed or not (public
) is needed.
Unit tests auto-discovery
MediaWiki allows any extension to register phpunit tests. Without extension registration, you would need to register a hook handler for the UnitTestsList hook, which would look something like:
public static function onUnitTestsList( array &$paths ) {
$paths[] = __DIR__ . '/tests/phpunit/';
}
(as described on the manual page). However, this code looks the same for a lot of extensions, so you could call it unnecessary code duplication.
If your extension uses extension registration and your phpunit tests are located in the tests/phpunit/
subdirectory of your extension, the phpunit wrapper of MediaWiki will autodiscover the unit tests with the help of extension registration.
Therefore, you don't need to register the hook anymore and you don't need to specify, that your unit tests are saved in the default directory.
Кастомизация регистрации
Также composer.json
If an extension or skin has library dependencies, it may have a composer.json
file as well, see Manual:Composer.json best practices . Use the load_composer_autoloader
field to make MediaWiki use Composer's autoloading when appropriate.
Some metadata fields overlap between extension.json
and composer.json
(discussed in задача T89456), including :
url
andhomepage
license-name
andlicense
Code stewardship
- Maintained by Core Platform Team .
- Live chat (IRC): #mediawiki-core подключиться
- Issue tracker: Phabricator MediaWiki-Configuration (Report an issue)
Смотри также
- Report bugs against the MediaWiki-Configuration project.
- Old versions of Manual:Developing extensions#Setup (prior to May 2015) and
$wgExtensionCredits
describe the old approach of declaring extension information in PHP code and variables
- Известные ограничения
- Overview of architecture
docs/extension.schema.v2.json
is the schema forextension.json
(and skin.json).- RfC about implementing extension registration
- Extension registration wall of superpowers! — summary of which extensions are still to be converted.
- задача T98668 — Tracking ticket for converting all extensions and skins on Git to use extension registration.