« Extensions MediaWiki » : différence entre les versions

De Banane Atomic
Aller à la navigationAller à la recherche
 
(41 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:Highlightjs_Integration Highlightjs Integration], git
== Native ==
* [[ReplaceText]], native
* [https://www.mediawiki.org/wiki/Extension:CodeEditor CodeEditor]
* [[WikiEditor]], native
* [https://www.mediawiki.org/wiki/Extension:MultimediaViewer MultimediaViewer]
* [https://www.mediawiki.org/wiki/Extension:NativeSvgHandler NativeSvgHandler], git
* [[ReplaceText]]
* [https://www.mediawiki.org/wiki/Extension:SimpleMathJax SimpleMathJax], git
* [[WikiEditor]]
----
 
* [[MobileFrontend]], git
== 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]]
* [[Math_extension_mediawiki|Math]]
* [[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 /usr/share/webapps/mediawiki/extensions/MonExtension/extension.json
# 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 152 : Ligne 159 :
* des problèmes de droits en lecture
* des problèmes de droits en lecture


= [https://www.mediawiki.org/wiki/Manual:Special_pages Page Spéciale] =
= [https://www.mediawiki.org/wiki/Manual:Special_pages Special pages] =
<filebox fn=extension.json lang=javascript>
{{info | Built-in special pages are located in the {{boxx|includes/specials}} directory.<br>
"type": "specialpage",
Source code: {{boxx|includes/specialpage/SpecialPage.php}}}}
"AutoloadClasses": {
 
     "SpecialMyExtension": "SpecialMyExtension.php"
<filebox fn=MySpecialPage/extension.json>
},
{
"MessagesDirs": {
    "name": "MySpecialPage",
     "MyExtension": "/i18n"
    "version": "1.0",
},
    "author": "Me",
"ResourceModules": {
     "url": "https://www.mediawiki.org/wiki/Extension:MySpecialPage",
     "ext.MyExtension.specialpage": {
    "descriptionmsg": "myspecialpage-desc",
         "styles": "MyExtension.css"
    "description": "My Special Page description.",
     }
     "license-name": "AGPL-3.0",
},
    "type": "specialpage",
"ResourceFileModulePaths": {
     "SpecialPages": {
    "localBasePath": "",
        // key (MySpecialPage) has to match the name passed in the ctor
     "remoteExtPath": "MyExtension"
        // value has to match the autoloaded class name
},
         "MySpecialPage": "SpecialMySpecialPage"
"SpecialPages": {
     },
    "MyExtension": "SpecialMyExtension"
    "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
</filebox>
</filebox>
<filebox fn=i18n/fr.json lang=javascript>
 
"myextension": "My Extension"
<filebox fn=MySpecialPage/src/Special.php>
</filebox>
<filebox fn=SpecialMyExtension.php lang=php>
<?php
<?php
class SpecialMyExtension extends SpecialPage {  // UnlistedSpecialPage
class SpecialMySpecialPage extends SpecialPage {  // UnlistedSpecialPage, IncludableSpecialPage


     public function __construct() {
     public function __construct() {
         parent::__construct( 'MyExtension' );
        // parent ctor parameters: $name = '', $restriction = '', $listed = true, $function = false, $file = '', $includable = false
         parent::__construct( 'MySpecialPage' );
     }
     }


     public function execute( $par ) {
     public function execute( $par ) {
         $this->setHeaders();
         $this->setHeaders();
         $this->outputHeader();
         $output = $this->getOutput();
          
 
        $out = $this->getOutput();
         # Get request data from, e.g.
         //$request = $this->getRequest();
$request = $this->getRequest();
         //$action = $par ? $par : $request->getVal( 'action', $par );
         $param = $request->getText( 'param' );
       
 
        $out->addModules( 'ext.MyExtension.specialpage' );
        $output->addWikiTextAsInterface( '= Titre =' );
        $output->addHTML( "<div>" );
</filebox>
 
<filebox fn=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."
</filebox>
 
<kode lang='MySpecialPage/MySpecialPage.alias.php' lang=php>
// localize url
<?php
$specialPageAliases = [];
 
$specialPageAliases['en'] = [
    'MySpecialPage' => [ 'MySpecialPage' ],
];
 
$specialPageAliases['fr'] = [
    'MySpecialPage' => [ 'MaPageSpéciale' ],
];
</kode>


        $out->addWikiTextAsInterface( '= Titre =' );
<filebox fn='LocalSettings.php'>
        $out->addHTML( "<div>" );
// has to match the folder name: extensions/MySpecialPage
wfLoadExtension( 'MySpecialPage' );
</filebox>
</filebox>
* <tt>/usr/share/webapps/mediawiki/includes/specialpage/SpecialPage.php</tt>
 
* [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 232 : 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 Requête dans la base de données] =
= [https://www.mediawiki.org/wiki/Manual:Database_access#Database_Abstraction_Layer Accès à la base de données] =
<kode lang=php>
<kode lang=php>
$querySQL = "SELECT colonne1 FROM table1";
$res = $dbr->newSelectQueryBuilder()
    ->select( [ 'page_namespace', 'page_title', 'rev_timestamp' ] )
$dbr = wfGetDB( DB_SLAVE );
    ->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 );
$count = $dbr->numRows( $res );
if( $count > 0 ) {
while( $row = $dbr->fetchObject( $res ) )
{
$valeur = $row->colonne1;
}
} else { ... }
</kode>
</kode>


= Formation du code HTML =
= Formation du code HTML =
<kode lang=php>
<kode lang=php>
Xml::openElement( 'p', array( 'class' => 'maclasse' ) );
// <p class="myclass">
Xml::closeElement( 'p' );
Html::openElement('p', ['class' => 'myclass']);


Xml::tags( 'p', array( 'class' => 'maclasse' ), "contenue" );
// </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();
    $parser->disableCache();
}
}
</kode>
</kode>
[http://www.mediawiki.org/wiki/Extensions_FAQ#How_do_I_disable_caching_for_pages_using_my_extension.3F How do I disable caching for pages using my extension]


=timestamp UTC &rarr; date locale=
=timestamp UTC &rarr; 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

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