26use InvalidArgumentException;
31use MediaWiki\Languages\LanguageNameUtils;
43use Wikimedia\Bcp47Code\Bcp47CodeValue;
44use Wikimedia\RemexHtml\Tokenizer\Attributes;
45use Wikimedia\RemexHtml\Tokenizer\PlainAttributes;
53 private const MAX_TTS = 900;
72 $options->assertRequiredOptions( self::REGISTER_OPTIONS );
76 # Syntax for arguments (see Parser::setFunctionHook):
77 # "name for lookup in localized magic words array",
79 # optional Parser::SFH_NO_HASH to omit the hash from calls (e.g. {{int:...}}
80 # instead of {{#int:...}})
82 'ns',
'nse',
'urlencode',
'lcfirst',
'ucfirst',
'lc',
'uc',
83 'localurl',
'localurle',
'fullurl',
'fullurle',
'canonicalurl',
84 'canonicalurle',
'formatnum',
'grammar',
'gender',
'plural',
'formal',
85 'bidi',
'numberingroup',
'language',
86 'padleft',
'padright',
'anchorencode',
'defaultsort',
'filepath',
87 'pagesincategory',
'pagesize',
'protectionlevel',
'protectionexpiry',
88 # The following are the "parser function" forms of magic
89 # variables defined in CoreMagicVariables. The no-args form will
90 # go through the magic variable code path (and be cached); the
91 # presence of arguments will cause the parser function form to
92 # be invoked. (Note that the actual implementation will pass
93 # a Parser object as first argument, in addition to the
94 # parser function parameters.)
96 # For this group, the first parameter to the parser function is
97 # "page title", and the no-args form (and the magic variable)
98 # defaults to "current page title".
99 'pagename',
'pagenamee',
100 'fullpagename',
'fullpagenamee',
101 'subpagename',
'subpagenamee',
102 'rootpagename',
'rootpagenamee',
103 'basepagename',
'basepagenamee',
104 'talkpagename',
'talkpagenamee',
105 'subjectpagename',
'subjectpagenamee',
106 'pageid',
'revisionid',
'revisionday',
107 'revisionday2',
'revisionmonth',
'revisionmonth1',
'revisionyear',
111 'namespace',
'namespacee',
'namespacenumber',
'talkspace',
'talkspacee',
112 'subjectspace',
'subjectspacee',
114 # More parser functions corresponding to CoreMagicVariables.
115 # For this group, the first parameter to the parser function is
116 # "raw" (uses the 'raw' format if present) and the no-args form
117 # (and the magic variable) defaults to 'not raw'.
118 'numberofarticles',
'numberoffiles',
120 'numberofactiveusers',
125 # These magic words already contain the hash, and the no-args form
126 # is the same as passing an empty first argument
132 foreach ( $noHashFunctions as $func ) {
140 $parser->
setFunctionHook(
'formatdate', [ self::class,
'formatDate' ] );
142 if ( $allowDisplayTitle ) {
145 [ self::class,
'displaytitle' ],
149 if ( $allowSlowParserFunctions ) {
152 [ self::class,
'pagesinnamespace' ],
164 public static function intFunction( $parser, $part1 =
'', ...$params ) {
165 if ( strval( $part1 ) !==
'' ) {
167 ->inLanguage( $parser->
getOptions()->getUserLangObj() );
168 return [ $message->plain(),
'noparse' => false ];
170 return [
'found' => false ];
181 public static function formatDate( $parser, $date, $defaultPref =
null ) {
185 $date = trim( $date );
187 $pref = $parser->
getOptions()->getDateFormat();
191 if ( $pref ==
'default' && $defaultPref ) {
192 $pref = $defaultPref;
195 $date = $df->reformat( $pref, $date, [
'match-whole' ] );
199 public static function ns( $parser, $part1 =
'' ) {
200 if ( intval( $part1 ) || $part1 ==
"0" ) {
201 $index = intval( $part1 );
203 $index = $parser->
getContentLanguage()->getNsIndex( str_replace(
' ',
'_', $part1 ) );
205 if ( $index !==
false ) {
208 return [
'found' => false ];
212 public static function nse( $parser, $part1 =
'' ) {
213 $ret = self::ns( $parser, $part1 );
214 if ( is_string( $ret ) ) {
215 $ret =
wfUrlencode( str_replace(
' ',
'_', $ret ) );
232 public static function urlencode( $parser, $s =
'', $arg =
null ) {
238 switch (
$magicWords->matchStartToEnd( $arg ??
'' ) ) {
241 $func =
'wfUrlencode';
242 $s = str_replace(
' ',
'_', $s );
247 $func =
'rawurlencode';
260 public static function lcfirst( $parser, $s =
'' ) {
264 public static function ucfirst( $parser, $s =
'' ) {
273 public static function lc( $parser, $s =
'' ) {
282 public static function uc( $parser, $s =
'' ) {
286 public static function localurl( $parser, $s =
'', $arg =
null ) {
287 return self::urlFunction(
'getLocalURL', $s, $arg );
290 public static function localurle( $parser, $s =
'', $arg =
null ) {
291 $temp = self::urlFunction(
'getLocalURL', $s, $arg );
292 if ( !is_string( $temp ) ) {
295 return htmlspecialchars( $temp, ENT_COMPAT );
299 public static function fullurl( $parser, $s =
'', $arg =
null ) {
300 return self::urlFunction(
'getFullURL', $s, $arg );
303 public static function fullurle( $parser, $s =
'', $arg =
null ) {
304 $temp = self::urlFunction(
'getFullURL', $s, $arg );
305 if ( !is_string( $temp ) ) {
308 return htmlspecialchars( $temp, ENT_COMPAT );
313 return self::urlFunction(
'getCanonicalURL', $s, $arg );
317 $temp = self::urlFunction(
'getCanonicalURL', $s, $arg );
318 if ( !is_string( $temp ) ) {
321 return htmlspecialchars( $temp, ENT_COMPAT );
325 public static function urlFunction( $func, $s =
'', $arg =
null ) {
326 # Due to order of execution of a lot of bits, the values might be encoded
327 # before arriving here; if that's true, then the title can't be created
328 # and the variable will fail. If we can't get a decent title from the first
329 # attempt, url-decode and try for a second.
330 $title = Title::newFromText( $s ) ?? Title::newFromURL( urldecode( $s ) );
331 if ( $title !==
null ) {
332 # Convert NS_MEDIA -> NS_FILE
336 if ( $arg !==
null ) {
337 $text = $title->$func( $arg );
339 $text = $title->$func();
343 return [
'found' => false ];
354 public static function formatnum( $parser, $num =
'', $arg1 =
'', $arg2 =
'' ) {
366 if ( in_array(
'rawsuffix', $modifiers,
true ) ) {
367 $func = [ $targetLanguage,
'parseFormattedNumber' ];
369 if ( in_array(
'nocommafysuffix', $modifiers,
true ) ) {
370 $func = [ $targetLanguage,
'formatNumNoSeparators' ];
372 $func = [ $targetLanguage,
'formatNum' ];
373 $func = self::getLegacyFormatNum( $parser, $func );
375 if ( in_array(
'lossless', $modifiers,
true ) ) {
376 $potentiallyLossyFunc = $func;
377 $func =
static function ( $num ) use ( $targetLanguage, $potentiallyLossyFunc ) {
378 $formatted = $potentiallyLossyFunc( $num );
379 $parsed = $targetLanguage->parseFormattedNumber( $formatted );
380 if ( $num === $parsed ) {
397 private static function getLegacyFormatNum( $parser, $callback ) {
402 return static function ( $number ) use ( $parser, $callback ) {
403 $validNumberRe =
'(-(?=[\d\.]))?(\d+|(?=\.\d))(\.\d*)?([Ee][-+]?\d+)?';
405 !is_numeric( $number ) &&
406 $number !== (string)NAN &&
407 $number !== (
string)INF &&
408 $number !== (string)-INF
413 return preg_replace_callback(
"/{$validNumberRe}/",
static function ( $m ) use ( $callback ) {
414 return $callback( $m[0] );
417 return $callback( $number );
427 public static function grammar( $parser, $case =
'', $word =
'' ) {
438 public static function gender( $parser, $username, ...$forms ) {
440 if ( count( $forms ) === 0 ) {
442 } elseif ( count( $forms ) === 1 ) {
446 $username = trim( $username );
452 $title = Title::newFromText( $username,
NS_USER );
459 $user = User::newFromName( $username );
462 $gender = $genderCache->getGenderOf( $user, __METHOD__ );
463 } elseif ( $username ===
'' && $parser->
getOptions()->isMessage() ) {
464 $gender = $genderCache->getGenderOf( $parser->
getOptions()->getUserIdentity(), __METHOD__ );
476 public static function plural( $parser, $text =
'', ...$forms ) {
478 settype( $text, ctype_digit( $text ) ?
'int' :
'float' );
483 public static function formal(
Parser $parser,
string ...$forms ): string {
484 $index = $parser->getTargetLanguage()->getFormalityIndex();
485 return $forms[$index] ?? $forms[0];
493 public static function bidi( $parser, $text =
'' ) {
506 public static function displaytitle( $parser, $text =
'', $uarg =
'' ) {
513 [
'displaytitle_noerror',
'displaytitle_noreplace' ] );
526 $bad = [
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'div',
'blockquote',
'ol',
'ul',
'li',
'hr',
527 'table',
'tr',
'th',
'td',
'dl',
'dd',
'caption',
'p',
'ruby',
'rb',
'rt',
'rtc',
'rp',
'br' ];
530 if ( $restrictDisplayTitle ) {
533 $htmlTagsCallback =
static function ( Attributes $attr ): Attributes {
534 $decoded = $attr->getValues();
536 if ( isset( $decoded[
'style'] ) ) {
541 if ( preg_match(
'/(display|user-select|visibility)\s*:/i', $decoded[
'style'] ) ) {
542 $decoded[
'style'] =
'/* attempt to bypass $wgRestrictDisplayTitle */';
546 return new PlainAttributes( $decoded );
549 $htmlTagsCallback =
null;
556 'attrCallback' => $htmlTagsCallback,
557 'removeTags' => $bad,
563 if ( !$restrictDisplayTitle ||
564 ( $title instanceof
Title
568 $old = $parser->
getOutput()->getPageProperty(
'displaytitle' );
569 if ( $old ===
null || $arg !==
'displaytitle_noreplace' ) {
570 $parser->
getOutput()->setDisplayTitle( $text );
572 if ( $old !==
null && $old !== $text && !$arg ) {
575 return '<span class="error">' .
576 $parser->
msg(
'duplicate-displaytitle',
587 'restricted-displaytitle',
604 private static function matchAgainstMagicword(
607 $value = trim( strval( $value ) );
608 if ( $value ===
'' ) {
611 $mwObject = $magicWordFactory->
get( $magicword );
612 return $mwObject->matchStartToEnd( $value );
627 if ( $raw !==
null && $raw !==
'' ) {
628 if ( !$magicWordFactory ) {
631 if ( self::matchAgainstMagicword( $magicWordFactory,
'rawsuffix', $raw ) ) {
635 return $language->formatNum( $num );
639 return self::formatRaw( SiteStats::pages(), $raw, $parser->
getTargetLanguage() );
643 return self::formatRaw( SiteStats::users(), $raw, $parser->
getTargetLanguage() );
647 return self::formatRaw( SiteStats::activeUsers(), $raw, $parser->
getTargetLanguage() );
651 return self::formatRaw( SiteStats::articles(), $raw, $parser->
getTargetLanguage() );
655 return self::formatRaw( SiteStats::images(), $raw, $parser->
getTargetLanguage() );
659 return self::formatRaw(
660 SiteStats::numberingroup(
'sysop' ),
667 return self::formatRaw( SiteStats::edits(), $raw, $parser->
getTargetLanguage() );
671 return self::formatRaw(
672 SiteStats::pagesInNs( intval( $namespace ) ),
679 return self::formatRaw(
680 SiteStats::numberingroup( strtolower( $name ) ),
694 private static function makeTitle(
Parser $parser, ?
string $t ) {
699 $title = Title::newFromText( $t );
712 public static function namespace( $parser, $title = null ) {
713 $t = self::makeTitle( $parser, $title );
717 return str_replace(
'_',
' ', $t->getNsText() );
720 public static function namespacee( $parser, $title =
null ) {
721 $t = self::makeTitle( $parser, $title );
729 $t = self::makeTitle( $parser, $title );
733 return (
string)$t->getNamespace();
736 public static function talkspace( $parser, $title =
null ) {
737 $t = self::makeTitle( $parser, $title );
738 if ( $t ===
null || !$t->canHaveTalkPage() ) {
741 return str_replace(
'_',
' ', $t->getTalkNsText() );
744 public static function talkspacee( $parser, $title =
null ) {
745 $t = self::makeTitle( $parser, $title );
746 if ( $t ===
null || !$t->canHaveTalkPage() ) {
753 $t = self::makeTitle( $parser, $title );
757 return str_replace(
'_',
' ', $t->getSubjectNsText() );
761 $t = self::makeTitle( $parser, $title );
775 public static function pagename( $parser, $title =
null ) {
776 $t = self::makeTitle( $parser, $title );
783 public static function pagenamee( $parser, $title =
null ) {
784 $t = self::makeTitle( $parser, $title );
792 $t = self::makeTitle( $parser, $title );
800 $t = self::makeTitle( $parser, $title );
808 $t = self::makeTitle( $parser, $title );
816 $t = self::makeTitle( $parser, $title );
824 $t = self::makeTitle( $parser, $title );
832 $t = self::makeTitle( $parser, $title );
840 $t = self::makeTitle( $parser, $title );
848 $t = self::makeTitle( $parser, $title );
856 $t = self::makeTitle( $parser, $title );
857 if ( $t ===
null || !$t->canHaveTalkPage() ) {
864 $t = self::makeTitle( $parser, $title );
865 if ( $t ===
null || !$t->canHaveTalkPage() ) {
872 $t = self::makeTitle( $parser, $title );
880 $t = self::makeTitle( $parser, $title );
897 public static function pagesincategory( $parser, $name =
'', $arg1 =
'', $arg2 =
'' ) {
901 'pagesincategory_all',
902 'pagesincategory_pages',
903 'pagesincategory_subcats',
904 'pagesincategory_files'
920 $type =
'pagesincategory_all';
923 $title = Title::makeTitleSafe(
NS_CATEGORY, $name );
924 if ( !$title ) { # invalid title
928 ->getLanguageConverterFactory()
930 $languageConverter->findVariantLink( $name, $title,
true );
933 $name = $title->getDBkey();
935 if ( !isset( $cache[$name] ) ) {
936 $category = Category::newFromTitle( $title );
938 $allCount = $subcatCount = $fileCount = $pageCount = 0;
940 $allCount = $category->getMemberCount();
941 $subcatCount = $category->getSubcatCount();
942 $fileCount = $category->getFileCount();
943 $pageCount = $category->getPageCount( Category::COUNT_CONTENT_PAGES );
945 $cache[$name][
'pagesincategory_all'] = $allCount;
946 $cache[$name][
'pagesincategory_pages'] = $pageCount;
947 $cache[$name][
'pagesincategory_subcats'] = $subcatCount;
948 $cache[$name][
'pagesincategory_files'] = $fileCount;
951 $count = $cache[$name][$type];
964 public static function pagesize( $parser, $page =
'', $raw =
null ) {
965 $title = Title::newFromText( $page );
967 if ( !is_object( $title ) || $title->isExternal() ) {
972 $rev = self::getCachedRevisionObject( $parser, $title, ParserOutputFlags::VARY_REVISION_SHA1 );
973 $length = $rev ? $rev->getSize() : 0;
974 if ( $length ===
null ) {
994 $titleObject = Title::newFromText( $title ) ?? $parser->
getTitle();
997 $restrictions = $restrictionStore->getRestrictions( $titleObject, strtolower( $type ) );
998 # RestrictionStore::getRestrictions returns an array, its possible it may have
999 # multiple values in the future
1000 return implode(
',', $restrictions );
1018 $titleObject = Title::newFromText( $title ) ?? $parser->
getTitle();
1023 return $restrictionStore->getRestrictionExpiry( $titleObject, strtolower( $type ) ) ??
'';
1036 public static function language( $parser, $code =
'', $inLanguage =
'' ) {
1037 if ( $code ===
'' ) {
1040 if ( $inLanguage ===
'' ) {
1041 $inLanguage = LanguageNameUtils::AUTONYMS;
1044 ->getLanguageNameUtils()
1045 ->getLanguageName( $code, $inLanguage );
1046 return $lang !==
'' ? $lang : LanguageCode::bcp47( $code );
1060 public static function dir(
Parser $parser,
string $code =
'',
string $arg =
'' ): string {
1064 if ( $code ===
'' ) {
1067 if ( $arg !==
'' ) {
1071 if (
$magicWords->matchStartToEnd( $arg ) ===
'language_option_bcp47' ) {
1073 $code =
new Bcp47CodeValue( $code );
1077 $lang = $languageFactory->getLanguage( $code );
1078 }
catch ( InvalidArgumentException ) {
1083 return $lang->getDir();
1094 public static function bcp47(
Parser $parser,
string $code =
'' ): string {
1095 if ( $code ===
'' ) {
1098 return LanguageCode::bcp47( $code );
1112 $parser, $string, $length, $padding =
'0', $direction = STR_PAD_RIGHT
1115 $lengthOfPadding = mb_strlen( $padding );
1116 if ( $lengthOfPadding == 0 ) {
1120 # The remaining length to add counts down to 0 as padding is added
1121 $length = min( (
int)$length, 500 ) - mb_strlen( $string );
1122 if ( $length <= 0 ) {
1127 # $finalPadding is just $padding repeated enough times so that
1128 # mb_strlen( $string ) + mb_strlen( $finalPadding ) == $length
1130 while ( $length > 0 ) {
1131 # If $length < $lengthofPadding, truncate $padding so we get the
1132 # exact length desired.
1133 $finalPadding .= mb_substr( $padding, 0, $length );
1134 $length -= $lengthOfPadding;
1137 if ( $direction == STR_PAD_LEFT ) {
1138 return $finalPadding . $string;
1140 return $string . $finalPadding;
1144 public static function padleft( $parser, $string =
'', $length = 0, $padding =
'0' ) {
1145 return self::pad( $parser, $string, $length, $padding, STR_PAD_LEFT );
1148 public static function padright( $parser, $string =
'', $length = 0, $padding =
'0' ) {
1149 return self::pad( $parser, $string, $length, $padding );
1160 return Sanitizer::safeEncodeAttribute( $section );
1163 public static function special( $parser, $text ) {
1164 [ $page, $subpage ] = MediaWikiServices::getInstance()->getSpecialPageFactory()->
1165 resolveAlias( $text );
1167 $title = SpecialPage::getTitleFor( $page, $subpage );
1168 return $title->getPrefixedText();
1171 $title = Title::makeTitleSafe(
NS_SPECIAL, $text );
1172 return $title ? $title->getPrefixedText() : self::special( $parser,
'Badtitle' );
1177 return wfUrlencode( str_replace(
' ',
'_', self::special( $parser, $text ) ) );
1192 [
'defaultsort_noerror',
'defaultsort_noreplace' ] );
1196 $text = trim( $text );
1197 if ( $text ===
'' ) {
1200 $old = $parser->
getOutput()->getPageProperty(
'defaultsort' );
1201 if ( $old ===
null || $arg !==
'defaultsort_noreplace' ) {
1202 $parser->
getOutput()->setPageProperty(
'defaultsort', $text );
1205 if ( $old ===
null || $old == $text || $arg ) {
1209 return '<span class="error">' .
1210 $parser->
msg(
'duplicate-defaultsort',
1230 public static function filepath( $parser, $name =
'', $argA =
'', $argB =
'' ) {
1231 $file = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $name );
1233 if ( $argA ==
'nowiki' ) {
1240 $isNowiki = ( $argB ==
'nowiki' );
1244 $url = $file->getFullUrl();
1247 if ( count( $parsedWidthParam ) ) {
1248 $mto = $file->transform( $parsedWidthParam );
1250 if ( $mto && !$mto->isError() ) {
1252 $urlUtils = MediaWikiServices::getInstance()->getUrlUtils();
1257 return [
$url,
'nowiki' => true ];
1272 public static function tagObj( $parser, $frame, $args ) {
1273 if ( !count( $args ) ) {
1276 $tagName = strtolower( trim( $parser->
killMarkers(
1277 $frame->expand( array_shift( $args ) )
1281 if ( count( $args ) ) {
1285 $inner = $frame->expand( array_shift( $args ), $processNowiki );
1286 if ( $processNowiki ) {
1299 foreach ( $args as $arg ) {
1300 $bits = $arg->splitArg();
1301 if ( strval( $bits[
'index'] ) ===
'' ) {
1302 $name = trim( $frame->expand( $bits[
'name'], PPFrame::STRIP_COMMENTS ) );
1303 $value = trim( $frame->expand( $bits[
'value'] ) );
1304 if ( preg_match(
'/^(?:["\'](.+)["\']|""|\'\')$/s', $value, $m ) ) {
1305 $value = $m[1] ??
'';
1307 $attributes[$name] = $value;
1312 if ( !in_array( $tagName, $stripList ) ) {
1315 foreach ( $attributes as $name => $value ) {
1316 $attrText .=
' ' . htmlspecialchars( $name ) .
1317 '="' . htmlspecialchars( $parser->
killMarkers( $value ), ENT_COMPAT ) .
'"';
1319 if ( $inner ===
null ) {
1320 return "<$tagName$attrText/>";
1322 return "<$tagName$attrText>$inner</$tagName>";
1328 'attributes' => $attributes,
1329 'close' =>
"</$tagName>",
1347 private static function getCachedRevisionObject( $parser, $title, $vary ) {
1352 $revisionRecord =
null;
1354 $isSelfReferential = $title->equals( $parser->
getTitle() );
1355 if ( $isSelfReferential ) {
1366 if ( $parserRevisionRecord && $parserRevisionRecord->isCurrent() ) {
1367 $revisionRecord = $parserRevisionRecord;
1372 if ( !$revisionRecord ) {
1381 if ( !$revisionRecord ) {
1383 $revisionRecord =
null;
1386 $parserOutput->addTemplate(
1388 $revisionRecord ? $revisionRecord->getPageId() : 0,
1389 $revisionRecord ? $revisionRecord->getId() : 0
1393 if ( $isSelfReferential ) {
1394 wfDebug( __METHOD__ .
": used current revision, setting {$vary->value}" );
1396 $parserOutput->setOutputFlag( $vary );
1397 if ( $vary === ParserOutputFlags::VARY_REVISION_SHA1 && $revisionRecord ) {
1399 $sha1 = $revisionRecord->getSha1();
1400 }
catch ( RevisionAccessException ) {
1403 $parserOutput->setRevisionUsedSha1Base36( $sha1 );
1407 return $revisionRecord;
1417 public static function pageid( $parser, $title =
null ) {
1418 $t = self::makeTitle( $parser, $title );
1421 } elseif ( !$t->canExist() || $t->isExternal() ) {
1427 if ( $t->equals( $parser->
getTitle() ) ) {
1430 $parserOutput->setOutputFlag( ParserOutputFlags::VARY_PAGE_ID );
1431 $id = $parser->
getTitle()->getArticleID();
1433 $parserOutput->setSpeculativePageIdUsed( $id );
1440 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
1441 $pdbk = $t->getPrefixedDBkey();
1442 $id = $linkCache->getGoodLinkID( $pdbk );
1443 if ( $id != 0 || $linkCache->isBadLink( $pdbk ) ) {
1444 $parserOutput->addLink( $t, $id );
1451 $id = $t->getArticleID();
1452 $parserOutput->addLink( $t, $id );
1468 $t = self::makeTitle( $parser, $title );
1469 if ( $t ===
null || $t->isExternal() ) {
1473 $services = MediaWikiServices::getInstance();
1475 $t->equals( $parser->
getTitle() ) &&
1476 $services->getMainConfig()->get( MainConfigNames::MiserMode ) &&
1477 !$parser->
getOptions()->getInterfaceMessage() &&
1479 $services->getNamespaceInfo()->isSubject( $t->getNamespace() )
1486 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_REVISION_EXISTS );
1494 if ( $t->equals( $parser->
getTitle() ) && $title ===
null ) {
1497 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_REVISION_ID );
1502 $id = $rev->getId();
1506 $id = $parser->
getOptions()->getSpeculativeRevId();
1508 $parser->
getOutput()->setSpeculativeRevIdUsed( $id );
1513 $rev = self::getCachedRevisionObject( $parser, $t, ParserOutputFlags::VARY_REVISION_ID );
1514 return $rev ? $rev->getId() :
'';
1517 private static function getRevisionTimestampSubstring(
1530 if ( $title->equals( $parser->
getTitle() ) && !$parser->getOptions()->getInterfaceMessage() ) {
1545 if ( $resNow !== $resThen ) {
1548 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_REVISION_TIMESTAMP );
1554 $rev = self::getCachedRevisionObject( $parser, $title, ParserOutputFlags::VARY_REVISION_TIMESTAMP );
1573 $t = self::makeTitle( $parser, $title );
1574 if ( $t ===
null || $t->isExternal() ) {
1577 return strval( (
int)self::getRevisionTimestampSubstring(
1578 $parser, $t, 6, 2, self::MAX_TTS
1590 $t = self::makeTitle( $parser, $title );
1591 if ( $t ===
null || $t->isExternal() ) {
1594 return self::getRevisionTimestampSubstring(
1595 $parser, $t, 6, 2, self::MAX_TTS
1607 $t = self::makeTitle( $parser, $title );
1608 if ( $t ===
null || $t->isExternal() ) {
1611 return self::getRevisionTimestampSubstring(
1612 $parser, $t, 4, 2, self::MAX_TTS
1624 $t = self::makeTitle( $parser, $title );
1625 if ( $t ===
null || $t->isExternal() ) {
1628 return strval( (
int)self::getRevisionTimestampSubstring(
1629 $parser, $t, 4, 2, self::MAX_TTS
1641 $t = self::makeTitle( $parser, $title );
1642 if ( $t ===
null || $t->isExternal() ) {
1645 return self::getRevisionTimestampSubstring(
1646 $parser, $t, 0, 4, self::MAX_TTS
1658 $t = self::makeTitle( $parser, $title );
1659 if ( $t ===
null || $t->isExternal() ) {
1662 return self::getRevisionTimestampSubstring(
1663 $parser, $t, 0, 14, self::MAX_TTS
1675 $t = self::makeTitle( $parser, $title );
1676 if ( $t ===
null || $t->isExternal() ) {
1682 if ( $t->equals( $parser->
getTitle() ) ) {
1684 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_USER );
1691 $rev = self::getCachedRevisionObject( $parser, $t, ParserOutputFlags::VARY_USER );
1692 $user = ( $rev !== null ) ? $rev->getUser() :
null;
1693 return $user ? $user->getName() :
'';
1709 $titleObject = Title::newFromText( $title ) ?? $parser->
getTitle();
1710 $restrictionStore = MediaWikiServices::getInstance()->getRestrictionStore();
1711 if ( $restrictionStore->areCascadeProtectionSourcesLoaded( $titleObject )
1715 $sources = $restrictionStore->getCascadeProtectionSources( $titleObject );
1716 $titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
1717 foreach ( $sources[0] as $sourcePageIdentity ) {
1718 $names[] = $titleFormatter->getPrefixedText( $sourcePageIdentity );
1720 return implode(
'|', $names );
1725 public static function interwikilink( $parser, $prefix =
'', $title =
'', $linkText =
null ) {
1726 $services = MediaWikiServices::getInstance();
1729 $services->getInterwikiLookup()->isValidInterwiki( $prefix )
1731 if ( $linkText !==
null ) {
1732 $linkText = Parser::stripOuterParagraph(
1733 # FIXME T382287: when
using Parsoid
this may leave
1734 # strip markers behind for embedded extension tags.
1738 [ $title, $frag ] = array_pad( explode(
'#', $title, 2 ), 2,
'' );
1740 $parser->
getOutput()->addInterwikiLink( $target );
1742 'text' => Linker::link( $target, $linkText ),
1747 return [
'found' => false ];
1751 $services = MediaWikiServices::getInstance();
1752 $extraInterlanguageLinkPrefixes = $services->getMainConfig()->get(
1753 MainConfigNames::ExtraInterlanguageLinkPrefixes
1757 $services->getInterwikiLookup()->isValidInterwiki( $prefix ) &&
1759 $services->getLanguageNameUtils()->getLanguageName(
1760 $prefix, LanguageNameUtils::AUTONYMS, LanguageNameUtils::DEFINED
1761 ) || in_array( $prefix, $extraInterlanguageLinkPrefixes,
true )
1765 [ $title, $frag ] = array_pad( explode(
'#', $title, 2 ), 2,
'' );
1768 NS_MAIN, $title, $frag, $prefix
1774 return [
'found' => false ];
1779class_alias( CoreParserFunctions::class,
'CoreParserFunctions' );
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
$magicWords
@phpcs-require-sorted-array
if(!defined('MW_SETUP_CALLBACK'))
A class containing constants representing the names of configuration variables.
const AllowSlowParserFunctions
Name constant for the AllowSlowParserFunctions setting, for use with Config::get()
const AllowDisplayTitle
Name constant for the AllowDisplayTitle setting, for use with Config::get()
const RestrictDisplayTitle
Name constant for the RestrictDisplayTitle setting, for use with Config::get()
Parent class for all special pages.