« Extensions MediaWiki » : différence entre les versions
De Banane Atomic
Aller à la navigationAller à la recherche
(25 versions intermédiaires par le même utilisateur non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
= Extensions utiles = | = Extensions utiles = | ||
* [https://www.mediawiki.org/wiki/Extension: | == Native == | ||
* [[ReplaceText]] | * [https://www.mediawiki.org/wiki/Extension:CodeEditor CodeEditor] | ||
* [[WikiEditor]] | * [https://www.mediawiki.org/wiki/Extension:MultimediaViewer MultimediaViewer] | ||
* [https://www.mediawiki.org/wiki/Extension:NativeSvgHandler NativeSvgHandler] | * [[ReplaceText]] | ||
* [https://www.mediawiki.org/wiki/Extension:SimpleMathJax SimpleMathJax] | * [[WikiEditor]] | ||
* [[MobileFrontend]] | == Additional == | ||
* [https://www.mediawiki.org/wiki/Extension:Highlightjs_Integration Highlightjs Integration] | |||
* [https://www.mediawiki.org/wiki/Extension:NativeSvgHandler NativeSvgHandler] | |||
* [https://www.mediawiki.org/wiki/Extension:SimpleMathJax SimpleMathJax] | |||
== To test == | |||
* [[MobileFrontend]] | |||
* [[Footer MediaWiki#FooterManager|FooterManager]] | * [[Footer MediaWiki#FooterManager|FooterManager]] | ||
* [[SyntaxHighlight]] | * [[SyntaxHighlight]] | ||
* [http://www.mediawiki.org/wiki/Extension:GoToCategory GoToCategory] | * [http://www.mediawiki.org/wiki/Extension:GoToCategory GoToCategory] | ||
Ligne 112 : | Ligne 117 : | ||
<filebox fn=LocalSettings.php lang=php> | <filebox fn=LocalSettings.php lang=php> | ||
wfLoadExtension( 'MonExtension' ); | wfLoadExtension( 'MonExtension' ); | ||
# charge le fichier | # charge le fichier extensions/MonExtension/extension.json | ||
</filebox> | </filebox> | ||
Ligne 138 : | Ligne 143 : | ||
<filebox fn='MyExtension.class.php' lang='php'> | <filebox fn='MyExtension.class.php' lang='php'> | ||
public static function onBeforePageDisplay(OutputPage &$out, Skin &$skin) { | public static function onBeforePageDisplay(OutputPage &$out, Skin &$skin) { | ||
$out->addModuleStyles( 'ext.MyExtension' ); | |||
// if the resource only contains style | |||
$out->addModuleStyles( 'ext.MyExtension' ); | $out->addModuleStyles( 'ext.MyExtension' ); | ||
return true; | return true; | ||
Ligne 166 : | Ligne 173 : | ||
"license-name": "AGPL-3.0", | "license-name": "AGPL-3.0", | ||
"type": "specialpage", | "type": "specialpage", | ||
"SpecialPages": { | "SpecialPages": { | ||
// key (MySpecialPage) has to match the name passed in the ctor | // key (MySpecialPage) has to match the name passed in the ctor | ||
// value has to match the autoloaded class name | // value has to match the autoloaded class name | ||
"MySpecialPage": "SpecialMySpecialPage" | "MySpecialPage": "SpecialMySpecialPage" | ||
}, | |||
"AutoloadClasses": { | |||
// key (SpecialMySpecialPage) has to match the class name in the SpecialMySpecialPage.php file and the SpecialPages value above | |||
"SpecialMySpecialPage": "SpecialMySpecialPage.php" | |||
}, | }, | ||
"MessagesDirs": { | "MessagesDirs": { | ||
// any key seems to work | |||
// key (MySpecialPage) has to match the name passed in the ctor | // key (MySpecialPage) has to match the name passed in the ctor | ||
"MySpecialPage": "i18n" | "MySpecialPage": "i18n" | ||
}, | |||
"ExtensionMessagesFiles": { | |||
"MySpecialPageAlias": "MySpecialPage.alias.php" | |||
}, | }, | ||
"manifest_version": 2 | "manifest_version": 2 | ||
Ligne 184 : | Ligne 195 : | ||
<filebox fn=MySpecialPage/src/Special.php> | <filebox fn=MySpecialPage/src/Special.php> | ||
<?php | <?php | ||
class SpecialMySpecialPage extends SpecialPage { | class SpecialMySpecialPage extends SpecialPage { // UnlistedSpecialPage, IncludableSpecialPage | ||
public function __construct() { | public function __construct() { | ||
// parent ctor parameters: $name = '', $restriction = '', $listed = true, $function = false, $file = '', $includable = false | // parent ctor parameters: $name = '', $restriction = '', $listed = true, $function = false, $file = '', $includable = false | ||
parent::__construct( 'MySpecialPage' ); | parent::__construct( 'MySpecialPage' ); | ||
} | } | ||
Ligne 206 : | Ligne 216 : | ||
<filebox fn=MySpecialPage/i18n/fr.json> | <filebox fn=MySpecialPage/i18n/fr.json> | ||
{ | { | ||
// doesn't seem to be used | |||
"@metadata": { | "@metadata": { | ||
"authors": "Me" | "authors": "Me" | ||
}, | }, | ||
"myspecialpage": " | // key has to match the SpecialPages key | ||
"myspecialpage-desc": " | // value would be the page title | ||
"myspecialpage-summary": " | "myspecialpage": "Ma page spéciale", | ||
"myspecialpage-desc": "Description de ma page spéciale.", | |||
"myspecialpage-summary": "Sommaire de ma page spéciale." | |||
</filebox> | </filebox> | ||
<kode lang='MySpecialPage/MySpecialPage.alias.php' lang=php> | |||
// localize url | |||
<?php | |||
$specialPageAliases = []; | |||
$specialPageAliases['en'] = [ | |||
'MySpecialPage' => [ 'MySpecialPage' ], | |||
]; | |||
$specialPageAliases['fr'] = [ | |||
'MySpecialPage' => [ 'MaPageSpéciale' ], | |||
]; | |||
</kode> | |||
<filebox fn='LocalSettings.php'> | <filebox fn='LocalSettings.php'> | ||
Ligne 219 : | Ligne 246 : | ||
</filebox> | </filebox> | ||
* [https://www.mediawiki.org/wiki/Category:Special_page_extensions List of special page extensions] | |||
* [https://www.mediawiki.org/wiki/Manual:$wgResourceModules Resource Modules] | * [https://www.mediawiki.org/wiki/Manual:$wgResourceModules Resource Modules] | ||
Ligne 252 : | Ligne 280 : | ||
[http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions] | [http://www.mediawiki.org/wiki/Manual:Tag_extensions Tag extensions] | ||
= [https://www.mediawiki.org/wiki/Manual:Database_access#Database_Abstraction_Layer | = [https://www.mediawiki.org/wiki/Manual:Database_access#Database_Abstraction_Layer Accès à la base de données] = | ||
<kode lang=php> | <kode lang=php> | ||
$ | $res = $dbr->newSelectQueryBuilder() | ||
->select( [ 'page_namespace', 'page_title', 'rev_timestamp' ] ) | |||
$dbr = | ->from( 'page' ) | ||
->join( 'revision', null, [ 'page_latest = rev_id' ] ) | |||
->where( 'page_is_redirect = 0' ) | |||
->andWhere( 'page_namespace = 0' ) | |||
->orderBy( 'rev_timestamp', SelectQueryBuilder::SORT_DESC ) | |||
->limit( 12 ) | |||
->caller( __METHOD__ ) | |||
->fetchResultSet(); | |||
foreach($res as $row) | |||
{} | |||
// count | |||
$res = $dbr->newSelectQueryBuilder() | |||
->select( [ 'count(*)' ] ) | |||
->from( 'page' ) | |||
->leftJoin( 'categorylinks', null, [ 'cl_from = page_id' ] ) | |||
->where( 'cl_from is NULL' ) | |||
->andWhere( 'page_is_redirect = 0' ) | |||
->andWhere( 'page_namespace = 0' ) | |||
->caller( __METHOD__ ) | |||
->fetchResultSet(); | |||
$nb = $res->fetchRow()[0]; | |||
</kode> | |||
<kode lang='php'> | |||
$querySQL = <<<EOD | |||
select count(*) | |||
from page | |||
left join categorylinks | |||
on cl_from = page_id | |||
where cl_from is NULL | |||
and page_is_redirect = 0 | |||
and page_namespace = 0 | |||
EOD; | |||
$res = $dbr->query( $querySQL ); | $res = $dbr->query( $querySQL ); | ||
</kode> | </kode> | ||
= Formation du code HTML = | = Formation du code HTML = | ||
<kode lang=php> | <kode lang=php> | ||
// <p class="myclass"> | |||
Html::openElement('p', ['class' => 'myclass']); | |||
// </p> | |||
Html::closeElement('p'); | |||
// <p class="myclass">content</p> | |||
Html::element('p', ['class' => 'myclass'], 'content' ); | |||
</kode> | |||
= User = | |||
<kode lang='php'> | |||
// in special page | |||
if ( $this->getUser()->isAnon() ) { | |||
$this->simpleCategoriesBlock(); | |||
} | |||
</kode> | </kode> | ||
=Désactiver le cache pour les pages qui utilise l'extension= | = [http://www.mediawiki.org/wiki/Extensions_FAQ#How_do_I_disable_caching_for_pages_using_my_extension.3F Désactiver le cache pour les pages qui utilise l'extension] = | ||
<kode lang=php> | <kode lang=php> | ||
function wfSomeHookFunction( $parser, $foo, $bar ) { | function wfSomeHookFunction( $parser, $foo, $bar ) { | ||
$parser->disableCache(); | |||
} | } | ||
</kode> | </kode> | ||
=timestamp UTC → date locale= | =timestamp UTC → date locale= |
Dernière version du 22 janvier 2023 à 16:03
Extensions utiles
Native
Additional
To test
Création
Les dossiers et fichiers relatifs aux extensions doivent être placés dans /extensions.
extension.json
extension.json |
{ "@comment": "Tout ce qui commence par @ sera ignoré", "name": "My Extension", "version": "1.0", "author": "Moi", "license-name": "CC-BY-NC-SA-4.0", "url": "https://www.mediawiki.org/wiki/Extension:MyExtension", "description": "My message", "type": "parserhook", "require": { "MediaWiki": ">= 1.27" }, "Hooks": { "ParserFirstCallInit": [ "MyExtensionClass::onParserFirstCallInit" ], "BeforePageDisplay": [ "MyExtensionClass::onBeforePageDisplay" ] }, "AutoloadClasses": { "MyExtensionClass": "MyExtension.class.php" }, "config": { "configElement1": "valeur", "configElement2": false }, "manifest_version": 1 } |
- name: nom affiché dans Spécial:Version
- license-name
- type : api, antispam, datavalues, media, parserhook, semantic, skin, specialpage, variable, other
- manifest_version: version du schema d'extension.json, seule la version 1 est supportée
MyExtension.class.php
MyExtension.class.php |
<?php class MyExtensionClass { public static function onParserFirstCallInit( Parser &$parser ) { global $configElement1, $configElement2; if ( $configElement2 === false ) { /* ... */ } return true; } public static function onBeforePageDisplay(OutputPage &$out, Skin &$skin) { $out->addModules('...'); return true; } } |
MyExtension.php
Fichier de compatibilité utilisé seulement si l'extension est chargée avec require_once "$IP/extensions/MyExtension/MyExtension.php"; |
MyExtension.php |
<?php if ( function_exists( 'wfLoadExtension' ) ) { wfLoadExtension( 'MyExtension' ); // Keep i18n globals so mergeMessageFileList.php doesn't break $wgMessagesDirs['MyExtension'] = __DIR__ . '/i18n'; return true; } else { die( 'This version of the MyExtension extension requires MediaWiki 1.25+' ); } |
Ancienne méthode
MyExtension.php |
<?php // Check environment if ( !defined( 'MEDIAWIKI' ) ) { echo( "This is an extension to the MediaWiki package and cannot be run standalone.\n" ); die( -1 ); } /* code de l'extension */ // pas de fermeture de la balise php |
Chargement de l'extension
LocalSettings.php |
wfLoadExtension( 'MonExtension' ); # charge le fichier extensions/MonExtension/extension.json |
Ressources
extension.json |
"ResourceModules": { "ext.MyExtension": { "scripts": [ "dossier/script.js", "script.js" ], "styles": "styles/style1.css" } }, "ResourceFileModulePaths": { "localBasePath": "", "remoteExtPath": "MyExtension", "remoteSkinPath": "MyExtension" }, |
- localBasePath: Important. Base path to prepend to all local paths, relative to current directory
- remoteExtPath: Optionnel. Base path to prepend to all remote paths, relative to $wgExtensionAssetsPath ($wgScriptPath/extensions)
- remoteSkinPath: Optionnel. Base path to prepend to all remote paths, relative to $wgStylePath ($wgScriptPath/skins)
MyExtension.class.php |
public static function onBeforePageDisplay(OutputPage &$out, Skin &$skin) { $out->addModuleStyles( 'ext.MyExtension' ); // if the resource only contains style $out->addModuleStyles( 'ext.MyExtension' ); return true; } |
Si des erreurs du type Fatal exception of type MWException apparaissent dans la Browser Console de Firefox,
forcer l'affichage du détail des erreurs dans MediaWiki:
LocalSettings.php |
$wgShowExceptionDetails = true; |
Cela peut être du à :
- des mauvais chemins
- des problèmes de droits en lecture
Special pages
Built-in special pages are located in the includes/specials directory. Source code: includes/specialpage/SpecialPage.php |
MySpecialPage/extension.json |
{ "name": "MySpecialPage", "version": "1.0", "author": "Me", "url": "https://www.mediawiki.org/wiki/Extension:MySpecialPage", "descriptionmsg": "myspecialpage-desc", "description": "My Special Page description.", "license-name": "AGPL-3.0", "type": "specialpage", "SpecialPages": { // key (MySpecialPage) has to match the name passed in the ctor // value has to match the autoloaded class name "MySpecialPage": "SpecialMySpecialPage" }, "AutoloadClasses": { // key (SpecialMySpecialPage) has to match the class name in the SpecialMySpecialPage.php file and the SpecialPages value above "SpecialMySpecialPage": "SpecialMySpecialPage.php" }, "MessagesDirs": { // any key seems to work // key (MySpecialPage) has to match the name passed in the ctor "MySpecialPage": "i18n" }, "ExtensionMessagesFiles": { "MySpecialPageAlias": "MySpecialPage.alias.php" }, "manifest_version": 2 |
MySpecialPage/src/Special.php |
<?php class SpecialMySpecialPage extends SpecialPage { // UnlistedSpecialPage, IncludableSpecialPage public function __construct() { // parent ctor parameters: $name = '', $restriction = '', $listed = true, $function = false, $file = '', $includable = false parent::__construct( 'MySpecialPage' ); } public function execute( $par ) { $this->setHeaders(); $output = $this->getOutput(); # Get request data from, e.g. $request = $this->getRequest(); $param = $request->getText( 'param' ); $output->addWikiTextAsInterface( '= Titre =' ); $output->addHTML( "<div>" ); |
MySpecialPage/i18n/fr.json |
{ // doesn't seem to be used "@metadata": { "authors": "Me" }, // key has to match the SpecialPages key // value would be the page title "myspecialpage": "Ma page spéciale", "myspecialpage-desc": "Description de ma page spéciale.", "myspecialpage-summary": "Sommaire de ma page spéciale." |
// localize url <?php $specialPageAliases = []; $specialPageAliases['en'] = [ 'MySpecialPage' => [ 'MySpecialPage' ], ]; $specialPageAliases['fr'] = [ 'MySpecialPage' => [ 'MaPageSpéciale' ], ]; |
LocalSettings.php |
// has to match the folder name: extensions/MySpecialPage wfLoadExtension( 'MySpecialPage' ); |
Parser un string Mediawiki
$output = $parser->recursiveTagParse("=Titre=", $frame ); // <h1>Titre</h1> |
Créer des nouvelles balises
$wgHooks['ParserFirstCallInit'][] = 'newTags'; function newTags( Parser $parser ) { $parser->setHook( 'nouvelleBalise', 'renduPourLaNouvelleBalise' ); return true; } function renduPourLaNouvelleBalise( $input, array $args, Parser $parser, PPFrame $frame ) { $nb = 5; if (array_key_exists('nb', $args) && is_numeric ($args['nb']) && $args['nb'] > 0) { $nb = $args['nb']; } return '<strong>' . htmlspecialchars( $input ) . '</strong>'; } |
<nouvelleBalise nb=5 />
Accès à la base de données
$res = $dbr->newSelectQueryBuilder() ->select( [ 'page_namespace', 'page_title', 'rev_timestamp' ] ) ->from( 'page' ) ->join( 'revision', null, [ 'page_latest = rev_id' ] ) ->where( 'page_is_redirect = 0' ) ->andWhere( 'page_namespace = 0' ) ->orderBy( 'rev_timestamp', SelectQueryBuilder::SORT_DESC ) ->limit( 12 ) ->caller( __METHOD__ ) ->fetchResultSet(); foreach($res as $row) {} // count $res = $dbr->newSelectQueryBuilder() ->select( [ 'count(*)' ] ) ->from( 'page' ) ->leftJoin( 'categorylinks', null, [ 'cl_from = page_id' ] ) ->where( 'cl_from is NULL' ) ->andWhere( 'page_is_redirect = 0' ) ->andWhere( 'page_namespace = 0' ) ->caller( __METHOD__ ) ->fetchResultSet(); $nb = $res->fetchRow()[0]; |
$querySQL = <<<EOD select count(*) from page left join categorylinks on cl_from = page_id where cl_from is NULL and page_is_redirect = 0 and page_namespace = 0 EOD; $res = $dbr->query( $querySQL ); |
Formation du code HTML
// <p class="myclass"> Html::openElement('p', ['class' => 'myclass']); // </p> Html::closeElement('p'); // <p class="myclass">content</p> Html::element('p', ['class' => 'myclass'], 'content' ); |
User
// in special page if ( $this->getUser()->isAnon() ) { $this->simpleCategoriesBlock(); } |
Désactiver le cache pour les pages qui utilise l'extension
function wfSomeHookFunction( $parser, $foo, $bar ) { $parser->disableCache(); } |
timestamp UTC → date locale
$timestamp = ... // timestamp UTC récupéré dans la BdD : 20120530111700 // récupération du context, utile pour connaitre la langue et l'utilisateur $context = RequestContext::getMain(); // convertion du timestamp de la base de donnée vers le timestamp Mediawiki $timestamp = wfTimestamp( TS_MW, $row->rev_timestamp ); // utilisation des préférences de l'utilisateur pour la conversion du timestamp en date $date = $context->getLanguage()->userTimeAndDate( $timestamp, $context->getUser() ); // 30 mai 2012 à 13:17 |
Manipulation autour de timestamp et de date:
// convertion du timestamp Mediawiki en timestamp UNIX $unixTimestamp = wfTimestamp( TS_UNIX, $timestamp); // 1338376620 // date en anglais date("l j F Y - H:i", $unixTimestamp); // Wednesday 30 May 2012 - 13:17 // date suivant la locale strftime("%A %e %B %G - %H:%M", $unixTimestamp); // conversion en heure GMT + ajout du décalage du fuseau horaire $offset = date("Z"); // 7200 gmstrftime("%A %e %B %G - %H:%M", $unixTimestamp + $offset); |
Crédits
Hook
AJAX
## Abort if AJAX is not enabled if ( !$wgUseAjax ) { trigger_error( 'Please enable AJAX : «$wgUseAjax = true;» in LocalSettings.php', E_USER_WARNING ); return; } |
Publier une extension
Page de l'extension sur mediawiki.org
Exemples
Compter le nombre de pages sans catégories
// jointure de categorylinks dans page avec cl_from = page_id // résultat: cl_from IS NULL pour les pages sans catégories // seulement les articles: page_namespace = 0 // pas les redirection: page_is_redirect = 0 $query = "select page_namespace, page_title, cl_from from page left outer join categorylinks on cl_from = page_id where page_namespace = 0 and page_is_redirect = 0 and cl_from IS NULL;"; $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->query( $query ); // liens vers les sans catégories $output .= $dbr->numRows( $res ) . " pages"; |
Inspiré du fichier « includes/specials/SpecialUncategorizedpages.php » |
Liens interne
$output .= Linker::linkKnown( SpecialPage::getTitleFor( 'Allpages' ), "Toutes les pages !!!"); $title = Title::newFromText("Special:Uncategorizedpages"); $output .= "<a href=\"" . $title->getFullURL() . "\">Sans catégories</a>"; $output .= $parser->recursiveTagParse( "[[Special:Uncategorizedpages|Sans catégories]]", $frame ); |
Nombre d'articles
// colonne ss_good_articles de la table site_stats // An approximate count of pages matching the following criteria: // in namespace 0 // not a redirect // contains the text '[[' $nbPages = SiteStats::articles(); // {{NUMBEROFARTICLES}} // colonne ss_total_pages de la table site_stats // Total pages, theoretically equal to SELECT COUNT(*) FROM page; except faster $nbPages = SiteStats::pages(); // {{NUMBEROFPAGES}} // requête SQL pour un résultat précis mais peut poser un problème de performance $query = "select count(*) from page where page_namespace = 0 and page_is_redirect = 0"; $dbr = wfGetDB( DB_SLAVE ); $res = $dbr->query( $query ); $nbPages = $res->fetchRow()[0]; |
Fichiers:
- includes/specials/SpecialAllPages.php
- includes/SiteStats.php