Extensions MediaWiki

De Banane Atomic
Aller à la navigationAller à la recherche

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

ResourceLoader Features

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."
Php.svg
// 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

Php.svg
$output = $parser->recursiveTagParse("=Titre=", $frame );
// <h1>Titre</h1>

Créer des nouvelles balises

Php.svg
$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 />

Tag extensions

Accès à la base de données

Php.svg
$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];
Php.svg
$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

Php.svg
// <p class="myclass">
Html::openElement('p', ['class' => 'myclass']);

// </p>
Html::closeElement('p');

// <p class="myclass">content</p>
Html::element('p', ['class' => 'myclass'], 'content' );

User

Php.svg
// in special page
if ( $this->getUser()->isAnon() ) {
    $this->simpleCategoriesBlock();
}

Désactiver le cache pour les pages qui utilise l'extension

Php.svg
function wfSomeHookFunction( $parser, $foo, $bar ) {
    $parser->disableCache();
}

timestamp UTC → date locale

Php.svg
$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:

Php.svg
// 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);

wfTimestamp
date
strftime

Crédits

[1]

Hook

[2]

AJAX

Php.svg
## 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

Php.svg
// 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

Php.svg
$output .= Linker::linkKnown( SpecialPage::getTitleFor( 'Allpages' ), "Toutes les pages !!!");

$title = Title::newFromText("Special:Uncategorizedpages");
$output .= "<a href=\"" . $title->getFullURL() . "\">Sans cat&eacute;gories</a>";

$output .= $parser->recursiveTagParse( "[[Special:Uncategorizedpages|Sans cat&eacute;gories]]", $frame );

Nombre d'articles

Php.svg
// 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