Manual:Registo de Extensão

This page is a translated version of the page Manual:Extension registration and the translation is 24% complete.
Outdated translations are marked like this.
Versão MediaWiki:
1.25
Gerrit change 166705

Registo de Extensão é o mecanismo que o MediaWiki utiliza para carregar as extensões e os temas. Você coloca os dados de configuração num ficheiro chamado extension.json ou skin.json na diretoria raiz da sua extensão ou tema, e o MediaWiki utiliza isto para registar as extensões e os temas.

Before MediaWiki 1.25, configuration for extensions and skins was done in a PHP file using the extension's or skin's name, for example MyExtension.php or 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";

Isto pode ser convertido para:

wfLoadExtensions( [ 'Hello', 'FooBar' ] );
$wgFooBarEnable = true;
wfLoadSkin( 'Baz' );
wfLoadExtension( 'BarFoo', '/tmp/extension/some/where/else/BarFoo/extension.json' );

Locais personalizados

This must be done before you load any extensions or skins from non-standard directory locations:

If you keep your extensions in a location different from $IP/extensions, you need to override $wgExtensionDirectory , or use the second parameter of wfLoadExtension(), to specify the directory in which to find the extension.
Se uma ou mais das suas extensões estiver armazenada em lugares adicionais, use o segundo parâmetro de wfLoadExtension() para especificar a localização do ficheiro .json para cada uma dessas extensões.
wfLoadExtensions() (plural) usa sempre $wgExtensionDirectory e não pode ser sobreposto.
$wgExtensionDirectory = '/some/path';
wfLoadExtension( 'FooBar' ); // Looks in $wgExtensionDirectory for /some/path/FooBar/extension.json
wfLoadExtension( 'Hello', '/some/other/path/HelloV2/Hello.json' ); // Procurar por /some/other/path/HelloV2/Hello.json
If your skins are not in $IP/skins, you need to override the poorly named $wgStyleDirectory , or use the second parameter of wfLoadSkin(), to specify the directory in which to find the skin.
Se uma ou mais das suas skins estiver armazenada em lugares adicionais, use o segundo parâmetro de wfLoadSkin() para especificar a localização do ficheiro .json para cada uma dessas skins.
wfLoadSkins() (plural) usa sempre $wgStyleDirectory e não pode ser sobreposto.
$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' ); // Procurar por /yet/another/path/BamBam/skin.json

Migração para os programadores de extensão

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).

The script maintenance/convertExtensionToRegistration.php helps you migrating from PHP entry points to a JSON metadata file. If your extension supports older versions of MediaWiki, you should keep your PHP entry point FooBar/FooBar.php until you drop support for those older versions.

Linhas de comando amostra:

$ cd core
$ php maintenance/convertExtensionToRegistration.php extensions/MassMessage/MassMessage.php
$ php maintenance/convertExtensionToRegistration.php skins/MonoBook/MonoBook.php --skin

You may need to uninstall your extension from LocalSettings.php if you receive errors that constants or functions cannot be redefined. You should replace your PHP entry point file (FooBar.php) with something like the following happens to not break wikis during the upgrade process.

<?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+' );
}

Ou temas

<?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+' );
}

Retaining documentation

PHP entry points usually have some documentation of configuration settings that is useful and shouldn't be lost. Unfortunately JSON doesn't support comments. It is recommended that you transfer configuration documentation to a README file in the extension's repository. You should also document configuration on-wiki in your Extension:MyExtension page. It is possible to include some documentation directly in the extension.json file as well. Extension registration ignores any key in extension.json starting with '@' in the top-level structure, so you can put comments in those parts of the JSON file. For example:

{
	"@note": "This file must be kept in sync with LocalisationUpdate.php",
	"@name": ...

Version 1 of the extension.json format also allowed @note in config section, but this is no longer recommended or supported in version 2. description field of the config variable should be used instead.

This should only be used for brief notes and comments.

Funcionalidades

If you are loading a large number of extensions, extension registration will provide a performance boost as long as you have APC (or APCu) installed. Extensions that are loaded together with wfLoadExtensions (with plural -s) will be cached together.

Atributos

A recurring problem is how to "register" something with another extension. Usually this meant that you had to load one extension before another. For example, VisualEditor has a $wgVisualEditorPluginModules which allows extensions to add their modules. However, in VisualEditor's entry point it has:

$wgVisualEditorPluginModules = [];

This means that if any extension appends to the array before VisualEditor is loaded, VE will wipe out its entry in this array. Some extensions depended upon a specific load order, others hacked around this with $wgExtensionFunctions . Extension registration solves this problem with "attributes". In the Math extension, its extension.json would have something like:

{
	"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
}

When VisualEditor wants to access this attribute it uses:

ExtensionRegistry::getInstance()->getAttribute( 'VisualEditorPluginModules' );

Requisitos (dependências)

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.

No MediaWiki 1.33.0(?!??) e acima, pode adicionar dependências no PHP como:

{
	"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' ) ) {
	// faça apenas isto se a extensão B estiver carregada
}
Versão MediaWiki:
1.32
Gerrit change 455752

Uma vez que MediaWiki 1.32 também é possível verificar se a extensão foi carregada e se satisfaz uma determinada restrição de versão do compositor:

if ( ExtensionRegistry::getInstance()->isLoaded( 'ExtensionB', '>=1.2' ) ) {
	// faça isto apenas se a extensão B estiver carregada e tiver uma versão de 1.2 ou maior.
}

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', '>=' ) ) {
	// faça isto apenas se a extensão B estiver carregada e tiver um número versão maior que ou igual a 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
	// faça apenas isto se a extensão B estiver carregada
}

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' ) ) {
	// faça apenas isto se a extensão B e a suas classes existirem
}

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.

Configurações (As suas definições de extensão/temas)


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": "A descrição para a configuração",
			"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.

Customizing registration

See Manual:Extension.json/Schema#callback.

Also 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 task T89456), including :

  • url and homepage
  • license-name and license

Code stewardship

Consulte também

Referências