Manual:Tag extensions/ko

From MediaWiki.org
Jump to: navigation, search
Gnome-preferences-other.svg 확장기능: 태그 확장기능 파서함수 훅(hook) 특수문서 스킨 특수 명령 API
MediaWiki extensions

간단한 문자열 처리나 본격적인 정보검색을 할 때, 내장된 위키 마크업 언어의 확장을 통한 기능추가가 유용하게 사용됩니다. 이를 위해, 태그 확장기능은 사용자로 하여금 사용자 맞춤 태그를 생성하고 사용할 수 있도록 도와줍니다.

예를들어 간단한 태그중 하나인 <donation /> 태그는, 기부문서에 삽입되어 사용될 수 있습니다.

구문해석 함수훅(Hook) 기능과 더불어 미디어위키의 기능성 확장을 위한 가장 효과적인 방법입니다.

이미 사용자들에 의해 작성된 수많은 확장기능들 보려면 Extension Matrix 를 참고해 주십시요. 확장기능을 만들기 전에 다른 사용자들이 이미 그 확장기능을 만들지는 않았는지 Extension Matrix 에서 확인하여야 합니다.

간단한 형태의 태그 확장기능은, 파서가 구문을 분석할때 특정 태그를 실제 HTML 태그로 변환 해주는 적당한 함수를 자동으로 호출하도록, 파서에 후킹(Hooking)콜백 함수로 이루어져 있습니다.

Contents

예제 [edit]

<?php
 
$wgHooks['ParserFirstCallInit'][] = 'wfSampleParserInit';
 
// 파서에 콜백 함수를 후킹(Hook)할 수 있도록 등록하는 함수
function wfSampleParserInit( Parser $parser ) {
        // 파서가 <sample> 태그를 발견하면, '''wfSampleRender''' 콜백함수를 실행하게 합니다.
        $parser->setHook( 'sample', 'wfSampleRender' );
        // 이 함수는 항상 '''참(true)''' 값만 반환합니다.
        // 여기서 반환값은 별다른 의미를 가지진 않습니다.
        return true;
}
 
// 실행
function wfSampleRender( $input, array $args, Parser $parser, PPFrame $frame ) {
        // Nothing exciting here, just escape the user-provided input and throw it back out again
        return htmlspecialchars( $input );
}

이 코드는 <sample> 를 위한 콜백 함수를 등록하는 예제입니다. 사용자가 문서에 <sample arg1="xxx" arg2="xxx">...input...</sample> 태그를 붙이면, 파서는 wfSampleRender() 함수를 호출하여, 다음 매개변수를 전달합니다.

$input
<sample></sample> 태그의 내용
만약 <sample /> 처럼 태그가 닫혀있을때는 null 값이 전달됩니다.
$args
HTML 태그 속성과 같은 태그 매개변수들
속성이름이 키값인 연관배열(associative array) 입니다.
$parser
부모 파서의 객체
전체 문맥에서의 제목을 얻거나, 위키 문장을 해석하거나, 중괄호를 확장시키거나, 연결관계나 의존관계를 등록하기 위해 좀더 고급 확장기능을 작성할때 사용됩니다.
$frame
부모 프레임 객체(a PPFrame object)
확장기능이 호출된 당시의 자세한 문맥상의 정보를 파서에게 제공하기 위해 $paser 와 함께 사용됩니다.


Attributes [edit]

Let's look at another example:

<?php
 
$wgHooks['ParserFirstCallInit'][] = 'wfSampleSetup';
 
function wfSampleSetup( Parser $parser ) {
        $parser->setHook( 'sample', 'wfSampleRender' );
       return true;
}
 
function wfSampleRender( $input, array $args, Parser $parser, PPFrame $frame ) {
        $attr = array();    
        // This time, make a list of attributes and their values,
        // and dump them, along with the user input
        foreach( $args as $name => $value )
                $attr[] = '<strong>' . ( $name ) . '</strong> = ' . htmlspecialchars( $value );
        return implode( '<br />', $attr ) . "\n\n" . htmlspecialchars( $input );
 
/* The following lines can be used to get the variable values directly:
        $to = $args['to'] ;
        $email = $args['email'] ;
*/
}

This example dumps the attributes passed to the tag, along with their values. It's quite evident that this allows for flexible specification of new, custom tags. You might, for example, define a tag extension that allows a user to inject a contact form on their user page, using something like <emailform to="User" email="user@foo.com" />.

There is a veritable plethora of tag extensions available for MediaWiki, some of which are listed on this site; others can be found via a quick web search. While a number of these are quite specialised for their use case, there are a great deal of well-loved and well-used extensions providing varying degrees of functionality.

Conventions [edit]

While an extension can be a single file, it is recommended that, for each extension, a separate subdirectory extension_name of the extensions directory is created, containing three files:

  • a small setup file, extension_name.setup.php
  • an internationalisation file, extension_name.i18n.php
  • a extension_name.body.php file with the bulk of the code.

By convention, the setup file will add an element to the $wgAutoloadClasses array, which specifies which files are to be loaded:

$wgAutoloadClasses[extension_name] = dirname(__FILE__) . '/extension_name.body.php';

For more general instructions, see Manual:Developing_extensions.

Publishing your extensions [edit]

  1. Create a new page on this wiki named Extension:<extension_name> with information on your extension, how to install it, and screenshots of it in use. A convenient template has been created to hold this information called Template:Extension. See the template page for more information. You should also add as much detail as possible to the body of the page, and it is wise to check back fairly regularly to respond to user questions on the associated talk page. Also, make sure the page belongs to Category:Extensions.
  2. Extensions that create new hooks within the extension code should register them on extension hook registry.
  3. Notify the mediawiki-l mailing list.

See also publishing your extension.

FAQ [edit]

Security Concerns [edit]

You'll notice above that the input in the examples above is escaped using htmlspecialchars() before being returned. It is vital that all user input is treated in this manner before echoing it back to the clients, to avoid introducing vectors for arbitrary HTML injection, which can lead to cross-site scripting vulnerabilities.

Timing and extensions [edit]

If you change the code for an extension, all pages that use the extension will, theoretically, immediately reflect the results of new code. Technically speaking, this means your code is executed each and every time a page containing the extension is rendered.

In practice, this is often not the case, due to page caching - either by the MediaWiki software, the browser or by an intermediary proxy or firewall.

To bypass MediaWiki's parser cache and ensure a new version of the page is generated, click on edit, replace "action=edit" in the URL shown in the address bar of your browser by "action=purge" and submit the new URL. The page and all templates it references will be regenerated, ignoring all cached data. The purge action is needed if the main page itself is not modified, but the way it must be rendered has changed (the extension was modified, or only a referenced template was modified).

If this is not sufficient to get you a fresh copy of the page, you can normally bypass intermediary caches by adding '&rand=somerandomtext' to the end of the above URL. Make sure 'somerandomtext' is different every time.

How do I disable caching for pages using my extension? [edit]

Since MediaWiki 1.5, the parser is passed as the third parameter to an extension. This parser can be used to invalidate the cache like this:

function wfSampleSomeHookFunction( $text, array $args, Parser $parser, PPFrame $frame ) {
        $parser->disableCache();
        ...
}

Regenerating the page when another page is edited [edit]

Maybe you don't want to disable caching entirely, you just want the page to be regenerated whenever another page is edited, similar to the way that template transclusions are handled. This can be done using the parser object that is passed to your hook function. The following method was lifted from CoreParserFunctions.php and appears to work for this purpose.

/** Make the page being parsed have a dependency on $page via the templatelinks table. 
*/
function wfSampleaddTemplateLinkDependency( Parser $parser, $page )  {
                $title = Title::newFromText( $page );
                $rev = Revision::newFromTitle( $title );
                $id = $rev ? $rev->getPage() : 0;
                // Register dependency in templatelinks
                $parser->mOutput->addTemplate( $title, $id, $rev ? $rev->getId() : 0 );
}

How do I render wikitext in my extension? [edit]

Since version 1.16 [edit]

MediaWiki version: 1.16

Parser hook functions are passed a reference to the parser object and a frame object; these should be used to parse wikitext.

function wfSampleWonderfulHook( $text, array $args, Parser $parser, PPFrame $frame ) {
        $output = $parser->recursiveTagParse( $text, $frame );
        return '<div class="wonderful">' . $output . '</div>';
}

Parser::recursiveTagParse() has been around since version 1.8. Its advantages include simplicity (it takes just one argument and returns a string) and the fact that it parses extension tags in $text, so you can nest extension tags.

The second parameter to recursiveTagParse, $frame, is an optional argument introduced in MW 1.16 alpha (r55682).

  • If $frame is provided (using the value of $frame passed to your extension), then any template parameters in $text will be expanded. In other words, content such as {{{1}}} will be recognized and converted into the appropriate value.
  • If $frame is not provided (e.g., $parser->recursiveTagParse( $text )), or if $frame is set to false, then template parameters will not be expanded; {{{1}}} will not be altered. Although this unlikely to be the desired behavior, this was the only option available before MW 1.16.

However, one step of parsing that is still skipped for tags, even when using recursiveTagParse, is Parser::preSaveTransform. preSaveTransform is the first step of parsing, responsible for making permanent changes to the about-to-be saved wikitext, such as:

  • Converting signatures (~~~, ~~~~, ~~~~~)
  • Expanding link labels, also known as the pipe-trick (e.g., changing [[Help:Contents|]] into [[Help:Contents|Contents]]). Without this step, shorthand links such as [[Help:Contents|]] are considered to be invalid, and are left in their wikitext form when parsed.
  • Expanding {{subst:}} templates.

The original call to preSaveTransform intentionally skips such conversions within all extension tags. If you need pre save transform to be done, you should consider using a parser function instead. All tag extensions can also be called as a parser function using {{#tag:tagname|attribute_name=value|input}} which will have pre save transform applied.

Version 1.8 to version 1.15 [edit]

MediaWiki versions: 1.8 – 1.15

The only difference before 1.16 is that the $frame argument was not available for Parser::recursiveTagParse().

function wfSampleWonderfulHook( $text, $args, $parser, $frame ) {
        $output = $parser->recursiveTagParse( $text );
        return '<div class="wonderful">' . $output . '</div>';
}

If the resulting inability to recognize template variables is a problem, see Extensions and Templates and bug 2257 for more information and workarounds.

How can I pass XML-style parameters in my extension tag? [edit]

Since version 1.5 [edit]

Since MediaWiki 1.5, XML-style parameters (tag attributes) are supported. The parameters are passed as the second parameter to the hook function, as an associative array. The value strings have already had HTML character entities decoded for you, so if you emit them back to HTML, don't forget to use htmlspecialchars( $codeToEncode, ENT_QUOTES ), to avoid the risk of HTML injection.

How can I avoid modification of my extension's HTML output? [edit]

The return value of a tag extension is considered almost parsed text, which means its not treated as pure html, but still modified slightly. There are two main things that are done to the output of a tag extension (Along with a couple other minor things):

  • Replace strip markers. Strip markers are certain items that look like UNIQe62a6957e0dbf6e-item-53--QINU which are inserted at various stages of processing wikitext to act as a marker to re-insert removed content at a later time. This is not something extensions usually need to worry about.
  • Parser::doBlockLevels which turns *'s into lists, and turns any line starting with a leading space into a <pre> among other things. This can sometimes be an issue in some extensions.

Tag extensions also support returning an array instead of just a string (Much like parser functions) in order to change how the return value is interpreted. The 0th value of the array must be the html. The "markerType" key can be set to nowiki in order to stop further parsing. Doing something like return array( $html, "markerType" => 'nowiki' ); would ensure that the $html value is not further modified and treated as just plain html.

How do I get my extension to show up on Special:Version? [edit]

In order for your extension to be displayed on the MediaWiki Special:Version page, you must assign extension credits within the PHP code.

To do this, add a $wgExtensionCredits variable as the first executable line of code before the hook line or function definition.

An example extension credit is:

<?php
/**
 * ExampleExtension - this extension is an example that does nothing
 *
 * To activate this extension, add the following into your LocalSettings.php file:
 * require_once('$IP/extensions/Example.php');
 *
 * @ingroup Extensions
 * @author John Doe <john.doe@example.com>
 * @version 1.0
 * @link https://www.mediawiki.org/wiki/Extension:MyExtension Documentation
 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 */
 
/**
 * Protect against register_globals vulnerabilities.
 * This line must be present before any global variable is referenced.
 */
if( !defined( 'MEDIAWIKI' ) ) {
        echo( "This is an extension to the MediaWiki package and cannot be run standalone.\n" );
        die( -1 );
}
 
// Extension credits that will show up on Special:Version    
$wgExtensionCredits['validextensionclass'][] = array(
        'path'           => __FILE__,
        'name'           => 'Example',
        'version'        => '1.0',
        'author'         => 'John Doe', 
        'url'            => 'https://www.mediawiki.org/wiki/Extension:MyExtension',
        'descriptionmsg' => 'myextensionmessage',
        'description'    => 'This extension is an example and performs no discernible function'
);
 
// Here is where we set up our extension
function wfExample(){
..
 
}

Replace validextensionclass with one of the following (unless your extension falls under multiple classes—then create a credit for each class):

  • 'specialpage'—reserved for additions to MediaWiki Special Pages;
  • 'parserhook'—used if your extension modifies, complements, or replaces the parser functions in MediaWiki;
  • 'variable'—extension that add multiple functionality to MediaWiki;
  • 'media'—used if your extension is a media handler of some sort
  • 'other'—all other extensions.

The myextensionmsg is the name of an interface/i18n message that describes your extension that will need to be defined in your extension's i18n.php file. If you omit this field, the description field will be used instead.

See also [edit]

언어: English  • Deutsch • Bahasa Indonesia • 日本語 • 한국어 • 中文(台灣)‎