26use InvalidArgumentException;
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 ) {
142 if ( $allowDisplayTitle ) {
145 [ __CLASS__,
'displaytitle' ],
149 if ( $allowSlowParserFunctions ) {
152 [ __CLASS__,
'pagesinnamespace' ],
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 ];
353 public static function formatnum( $parser, $num =
'', $arg =
null ) {
360 $func = self::getLegacyFormatNum( $parser, $func );
363 $func = self::getLegacyFormatNum( $parser, $func );
374 private static function getLegacyFormatNum( $parser, $callback ) {
379 return static function ( $number ) use ( $parser, $callback ) {
380 $validNumberRe =
'(-(?=[\d\.]))?(\d+|(?=\.\d))(\.\d*)?([Ee][-+]?\d+)?';
382 !is_numeric( $number ) &&
383 $number !== (string)NAN &&
384 $number !== (
string)INF &&
385 $number !== (string)-INF
390 return preg_replace_callback(
"/{$validNumberRe}/",
static function ( $m ) use ( $callback ) {
391 return call_user_func( $callback, $m[0] );
394 return call_user_func( $callback, $number );
404 public static function grammar( $parser, $case =
'', $word =
'' ) {
415 public static function gender( $parser, $username, ...$forms ) {
417 if ( count( $forms ) === 0 ) {
419 } elseif ( count( $forms ) === 1 ) {
423 $username = trim( $username );
429 $title = Title::newFromText( $username,
NS_USER );
436 $user = User::newFromName( $username );
439 $gender = $genderCache->getGenderOf( $user, __METHOD__ );
440 } elseif ( $username ===
'' && $parser->
getOptions()->getInterfaceMessage() ) {
441 $gender = $genderCache->getGenderOf( $parser->
getOptions()->getUserIdentity(), __METHOD__ );
453 public static function plural( $parser, $text =
'', ...$forms ) {
455 settype( $text, ctype_digit( $text ) ?
'int' :
'float' );
460 public static function formal(
Parser $parser,
string ...$forms ): string {
461 $index = $parser->getTargetLanguage()->getFormalityIndex();
462 return $forms[$index] ?? $forms[0];
470 public static function bidi( $parser, $text =
'' ) {
483 public static function displaytitle( $parser, $text =
'', $uarg =
'' ) {
490 [
'displaytitle_noerror',
'displaytitle_noreplace' ] );
503 $bad = [
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'div',
'blockquote',
'ol',
'ul',
'li',
'hr',
504 'table',
'tr',
'th',
'td',
'dl',
'dd',
'caption',
'p',
'ruby',
'rb',
'rt',
'rtc',
'rp',
'br' ];
507 if ( $restrictDisplayTitle ) {
510 $htmlTagsCallback =
static function ( Attributes $attr ): Attributes {
511 $decoded = $attr->getValues();
513 if ( isset( $decoded[
'style'] ) ) {
518 if ( preg_match(
'/(display|user-select|visibility)\s*:/i', $decoded[
'style'] ) ) {
519 $decoded[
'style'] =
'/* attempt to bypass $wgRestrictDisplayTitle */';
523 return new PlainAttributes( $decoded );
526 $htmlTagsCallback =
null;
533 'attrCallback' => $htmlTagsCallback,
534 'removeTags' => $bad,
540 if ( !$restrictDisplayTitle ||
541 ( $title instanceof
Title
545 $old = $parser->
getOutput()->getPageProperty(
'displaytitle' );
546 if ( $old ===
null || $arg !==
'displaytitle_noreplace' ) {
547 $parser->
getOutput()->setDisplayTitle( $text );
549 if ( $old !==
null && $old !== $text && !$arg ) {
552 return '<span class="error">' .
553 $parser->
msg(
'duplicate-displaytitle',
564 'restricted-displaytitle',
581 private static function matchAgainstMagicword(
584 $value = trim( strval( $value ) );
585 if ( $value ===
'' ) {
588 $mwObject = $magicWordFactory->
get( $magicword );
589 return $mwObject->matchStartToEnd( $value );
604 if ( $raw !==
null && $raw !==
'' ) {
605 if ( !$magicWordFactory ) {
608 if ( self::matchAgainstMagicword( $magicWordFactory,
'rawsuffix', $raw ) ) {
612 return $language->formatNum( $num );
616 return self::formatRaw( SiteStats::pages(), $raw, $parser->
getTargetLanguage() );
620 return self::formatRaw( SiteStats::users(), $raw, $parser->
getTargetLanguage() );
624 return self::formatRaw( SiteStats::activeUsers(), $raw, $parser->
getTargetLanguage() );
628 return self::formatRaw( SiteStats::articles(), $raw, $parser->
getTargetLanguage() );
632 return self::formatRaw( SiteStats::images(), $raw, $parser->
getTargetLanguage() );
636 return self::formatRaw(
637 SiteStats::numberingroup(
'sysop' ),
644 return self::formatRaw( SiteStats::edits(), $raw, $parser->
getTargetLanguage() );
648 return self::formatRaw(
649 SiteStats::pagesInNs( intval( $namespace ) ),
656 return self::formatRaw(
657 SiteStats::numberingroup( strtolower( $name ) ),
671 private static function makeTitle(
Parser $parser, ?
string $t ) {
676 $title = Title::newFromText( $t );
689 public static function namespace( $parser, $title = null ) {
690 $t = self::makeTitle( $parser, $title );
694 return str_replace(
'_',
' ', $t->getNsText() );
697 public static function namespacee( $parser, $title =
null ) {
698 $t = self::makeTitle( $parser, $title );
706 $t = self::makeTitle( $parser, $title );
710 return (
string)$t->getNamespace();
713 public static function talkspace( $parser, $title =
null ) {
714 $t = self::makeTitle( $parser, $title );
715 if ( $t ===
null || !$t->canHaveTalkPage() ) {
718 return str_replace(
'_',
' ', $t->getTalkNsText() );
721 public static function talkspacee( $parser, $title =
null ) {
722 $t = self::makeTitle( $parser, $title );
723 if ( $t ===
null || !$t->canHaveTalkPage() ) {
730 $t = self::makeTitle( $parser, $title );
734 return str_replace(
'_',
' ', $t->getSubjectNsText() );
738 $t = self::makeTitle( $parser, $title );
752 public static function pagename( $parser, $title =
null ) {
753 $t = self::makeTitle( $parser, $title );
760 public static function pagenamee( $parser, $title =
null ) {
761 $t = self::makeTitle( $parser, $title );
769 $t = self::makeTitle( $parser, $title );
777 $t = self::makeTitle( $parser, $title );
785 $t = self::makeTitle( $parser, $title );
793 $t = self::makeTitle( $parser, $title );
801 $t = self::makeTitle( $parser, $title );
809 $t = self::makeTitle( $parser, $title );
817 $t = self::makeTitle( $parser, $title );
825 $t = self::makeTitle( $parser, $title );
833 $t = self::makeTitle( $parser, $title );
834 if ( $t ===
null || !$t->canHaveTalkPage() ) {
841 $t = self::makeTitle( $parser, $title );
842 if ( $t ===
null || !$t->canHaveTalkPage() ) {
849 $t = self::makeTitle( $parser, $title );
857 $t = self::makeTitle( $parser, $title );
874 public static function pagesincategory( $parser, $name =
'', $arg1 =
'', $arg2 =
'' ) {
878 'pagesincategory_all',
879 'pagesincategory_pages',
880 'pagesincategory_subcats',
881 'pagesincategory_files'
897 $type =
'pagesincategory_all';
900 $title = Title::makeTitleSafe(
NS_CATEGORY, $name );
901 if ( !$title ) { # invalid title
905 ->getLanguageConverterFactory()
907 $languageConverter->findVariantLink( $name, $title,
true );
910 $name = $title->getDBkey();
912 if ( !isset( $cache[$name] ) ) {
913 $category = Category::newFromTitle( $title );
915 $allCount = $subcatCount = $fileCount = $pageCount = 0;
917 $allCount = $category->getMemberCount();
918 $subcatCount = $category->getSubcatCount();
919 $fileCount = $category->getFileCount();
920 $pageCount = $category->getPageCount( Category::COUNT_CONTENT_PAGES );
922 $cache[$name][
'pagesincategory_all'] = $allCount;
923 $cache[$name][
'pagesincategory_pages'] = $pageCount;
924 $cache[$name][
'pagesincategory_subcats'] = $subcatCount;
925 $cache[$name][
'pagesincategory_files'] = $fileCount;
928 $count = $cache[$name][$type];
941 public static function pagesize( $parser, $page =
'', $raw =
null ) {
942 $title = Title::newFromText( $page );
944 if ( !is_object( $title ) || $title->isExternal() ) {
949 $rev = self::getCachedRevisionObject( $parser, $title, ParserOutputFlags::VARY_REVISION_SHA1 );
950 $length = $rev ? $rev->getSize() : 0;
951 if ( $length ===
null ) {
971 $titleObject = Title::newFromText( $title ) ?? $parser->
getTitle();
974 $restrictions = $restrictionStore->getRestrictions( $titleObject, strtolower( $type ) );
975 # RestrictionStore::getRestrictions returns an array, its possible it may have
976 # multiple values in the future
977 return implode(
',', $restrictions );
995 $titleObject = Title::newFromText( $title ) ?? $parser->
getTitle();
1000 return $restrictionStore->getRestrictionExpiry( $titleObject, strtolower( $type ) ) ??
'';
1013 public static function language( $parser, $code =
'', $inLanguage =
'' ) {
1014 if ( $code ===
'' ) {
1017 if ( $inLanguage ===
'' ) {
1018 $inLanguage = LanguageNameUtils::AUTONYMS;
1021 ->getLanguageNameUtils()
1022 ->getLanguageName( $code, $inLanguage );
1023 return $lang !==
'' ? $lang : LanguageCode::bcp47( $code );
1037 public static function dir(
Parser $parser,
string $code =
'',
string $arg =
'' ): string {
1041 if ( $code ===
'' ) {
1044 if ( $arg !==
'' ) {
1048 if (
$magicWords->matchStartToEnd( $arg ) ===
'language_option_bcp47' ) {
1050 $code =
new Bcp47CodeValue( $code );
1054 $lang = $languageFactory->getLanguage( $code );
1055 }
catch ( InvalidArgumentException $ex ) {
1060 return $lang->getDir();
1071 public static function bcp47(
Parser $parser,
string $code =
'' ): string {
1072 if ( $code ===
'' ) {
1075 return LanguageCode::bcp47( $code );
1089 $parser, $string, $length, $padding =
'0', $direction = STR_PAD_RIGHT
1092 $lengthOfPadding = mb_strlen( $padding );
1093 if ( $lengthOfPadding == 0 ) {
1097 # The remaining length to add counts down to 0 as padding is added
1098 $length = min( (
int)$length, 500 ) - mb_strlen( $string );
1099 if ( $length <= 0 ) {
1104 # $finalPadding is just $padding repeated enough times so that
1105 # mb_strlen( $string ) + mb_strlen( $finalPadding ) == $length
1107 while ( $length > 0 ) {
1108 # If $length < $lengthofPadding, truncate $padding so we get the
1109 # exact length desired.
1110 $finalPadding .= mb_substr( $padding, 0, $length );
1111 $length -= $lengthOfPadding;
1114 if ( $direction == STR_PAD_LEFT ) {
1115 return $finalPadding . $string;
1117 return $string . $finalPadding;
1121 public static function padleft( $parser, $string =
'', $length = 0, $padding =
'0' ) {
1122 return self::pad( $parser, $string, $length, $padding, STR_PAD_LEFT );
1125 public static function padright( $parser, $string =
'', $length = 0, $padding =
'0' ) {
1126 return self::pad( $parser, $string, $length, $padding );
1137 return Sanitizer::safeEncodeAttribute( $section );
1140 public static function special( $parser, $text ) {
1141 [ $page, $subpage ] = MediaWikiServices::getInstance()->getSpecialPageFactory()->
1142 resolveAlias( $text );
1144 $title = SpecialPage::getTitleFor( $page, $subpage );
1145 return $title->getPrefixedText();
1148 $title = Title::makeTitleSafe(
NS_SPECIAL, $text );
1149 return $title ? $title->getPrefixedText() : self::special( $parser,
'Badtitle' );
1154 return wfUrlencode( str_replace(
' ',
'_', self::special( $parser, $text ) ) );
1169 [
'defaultsort_noerror',
'defaultsort_noreplace' ] );
1173 $text = trim( $text );
1174 if ( strlen( $text ) == 0 ) {
1177 $old = $parser->
getOutput()->getPageProperty(
'defaultsort' );
1178 if ( $old ===
null || $arg !==
'defaultsort_noreplace' ) {
1179 $parser->
getOutput()->setPageProperty(
'defaultsort', $text );
1182 if ( $old ===
null || $old == $text || $arg ) {
1186 return '<span class="error">' .
1187 $parser->
msg(
'duplicate-defaultsort',
1207 public static function filepath( $parser, $name =
'', $argA =
'', $argB =
'' ) {
1208 $file = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $name );
1210 if ( $argA ==
'nowiki' ) {
1217 $isNowiki = ( $argB ==
'nowiki' );
1221 $url = $file->getFullUrl();
1224 if ( count( $parsedWidthParam ) ) {
1225 $mto = $file->transform( $parsedWidthParam );
1227 if ( $mto && !$mto->isError() ) {
1229 $urlUtils = MediaWikiServices::getInstance()->getUrlUtils();
1234 return [
$url,
'nowiki' => true ];
1249 public static function tagObj( $parser, $frame, $args ) {
1250 if ( !count( $args ) ) {
1253 $tagName = strtolower( trim( $frame->expand( array_shift( $args ) ) ) );
1256 if ( count( $args ) ) {
1257 $inner = $frame->expand( array_shift( $args ), $processNowiki );
1263 foreach ( $args as $arg ) {
1264 $bits = $arg->splitArg();
1265 if ( strval( $bits[
'index'] ) ===
'' ) {
1266 $name = trim( $frame->expand( $bits[
'name'], PPFrame::STRIP_COMMENTS ) );
1267 $value = trim( $frame->expand( $bits[
'value'] ) );
1268 if ( preg_match(
'/^(?:["\'](.+)["\']|""|\'\')$/s', $value, $m ) ) {
1269 $value = $m[1] ??
'';
1271 $attributes[$name] = $value;
1276 if ( !in_array( $tagName, $stripList ) ) {
1279 foreach ( $attributes as $name => $value ) {
1280 $attrText .=
' ' . htmlspecialchars( $name ) .
1281 '="' . htmlspecialchars( $value, ENT_COMPAT ) .
'"';
1283 if ( $inner ===
null ) {
1284 return "<$tagName$attrText/>";
1286 return "<$tagName$attrText>$inner</$tagName>";
1292 'attributes' => $attributes,
1293 'close' =>
"</$tagName>",
1311 private static function getCachedRevisionObject( $parser, $title, $vary ) {
1316 $revisionRecord =
null;
1318 $isSelfReferential = $title->equals( $parser->
getTitle() );
1319 if ( $isSelfReferential ) {
1330 if ( $parserRevisionRecord && $parserRevisionRecord->isCurrent() ) {
1331 $revisionRecord = $parserRevisionRecord;
1336 if ( !$revisionRecord ) {
1345 if ( !$revisionRecord ) {
1347 $revisionRecord =
null;
1350 $parserOutput->addTemplate(
1352 $revisionRecord ? $revisionRecord->getPageId() : 0,
1353 $revisionRecord ? $revisionRecord->getId() : 0
1357 if ( $isSelfReferential ) {
1358 wfDebug( __METHOD__ .
": used current revision, setting $vary" );
1360 $parserOutput->setOutputFlag( $vary );
1361 if ( $vary === ParserOutputFlags::VARY_REVISION_SHA1 && $revisionRecord ) {
1363 $sha1 = $revisionRecord->getSha1();
1364 }
catch ( RevisionAccessException $e ) {
1367 $parserOutput->setRevisionUsedSha1Base36( $sha1 );
1371 return $revisionRecord;
1381 public static function pageid( $parser, $title =
null ) {
1382 $t = self::makeTitle( $parser, $title );
1385 } elseif ( !$t->canExist() || $t->isExternal() ) {
1391 if ( $t->equals( $parser->
getTitle() ) ) {
1394 $parserOutput->setOutputFlag( ParserOutputFlags::VARY_PAGE_ID );
1395 $id = $parser->
getTitle()->getArticleID();
1397 $parserOutput->setSpeculativePageIdUsed( $id );
1404 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
1405 $pdbk = $t->getPrefixedDBkey();
1406 $id = $linkCache->getGoodLinkID( $pdbk );
1407 if ( $id != 0 || $linkCache->isBadLink( $pdbk ) ) {
1408 $parserOutput->addLink( $t, $id );
1415 $id = $t->getArticleID();
1416 $parserOutput->addLink( $t, $id );
1432 $t = self::makeTitle( $parser, $title );
1433 if ( $t ===
null || $t->isExternal() ) {
1437 $services = MediaWikiServices::getInstance();
1439 $t->equals( $parser->
getTitle() ) &&
1440 $services->getMainConfig()->get( MainConfigNames::MiserMode ) &&
1441 !$parser->
getOptions()->getInterfaceMessage() &&
1443 $services->getNamespaceInfo()->isSubject( $t->getNamespace() )
1450 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_REVISION_EXISTS );
1458 if ( $t->equals( $parser->
getTitle() ) && $title ===
null ) {
1461 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_REVISION_ID );
1466 $id = $rev->getId();
1470 $id = $parser->
getOptions()->getSpeculativeRevId();
1472 $parser->
getOutput()->setSpeculativeRevIdUsed( $id );
1477 $rev = self::getCachedRevisionObject( $parser, $t, ParserOutputFlags::VARY_REVISION_ID );
1478 return $rev ? $rev->getId() :
'';
1481 private static function getRevisionTimestampSubstring(
1494 if ( $title->equals( $parser->
getTitle() ) && !$parser->getOptions()->getInterfaceMessage() ) {
1509 if ( $resNow !== $resThen ) {
1512 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_REVISION_TIMESTAMP );
1518 $rev = self::getCachedRevisionObject( $parser, $title, ParserOutputFlags::VARY_REVISION_TIMESTAMP );
1537 $t = self::makeTitle( $parser, $title );
1538 if ( $t ===
null || $t->isExternal() ) {
1541 return strval( (
int)self::getRevisionTimestampSubstring(
1542 $parser, $t, 6, 2, self::MAX_TTS
1554 $t = self::makeTitle( $parser, $title );
1555 if ( $t ===
null || $t->isExternal() ) {
1558 return self::getRevisionTimestampSubstring(
1559 $parser, $t, 6, 2, self::MAX_TTS
1571 $t = self::makeTitle( $parser, $title );
1572 if ( $t ===
null || $t->isExternal() ) {
1575 return self::getRevisionTimestampSubstring(
1576 $parser, $t, 4, 2, self::MAX_TTS
1588 $t = self::makeTitle( $parser, $title );
1589 if ( $t ===
null || $t->isExternal() ) {
1592 return strval( (
int)self::getRevisionTimestampSubstring(
1593 $parser, $t, 4, 2, self::MAX_TTS
1605 $t = self::makeTitle( $parser, $title );
1606 if ( $t ===
null || $t->isExternal() ) {
1609 return self::getRevisionTimestampSubstring(
1610 $parser, $t, 0, 4, self::MAX_TTS
1622 $t = self::makeTitle( $parser, $title );
1623 if ( $t ===
null || $t->isExternal() ) {
1626 return self::getRevisionTimestampSubstring(
1627 $parser, $t, 0, 14, self::MAX_TTS
1639 $t = self::makeTitle( $parser, $title );
1640 if ( $t ===
null || $t->isExternal() ) {
1646 if ( $t->equals( $parser->
getTitle() ) ) {
1648 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_USER );
1655 $rev = self::getCachedRevisionObject( $parser, $t, ParserOutputFlags::VARY_USER );
1656 $user = ( $rev !== null ) ? $rev->getUser() :
null;
1657 return $user ? $user->getName() :
'';
1673 $titleObject = Title::newFromText( $title ) ?? $parser->
getTitle();
1674 $restrictionStore = MediaWikiServices::getInstance()->getRestrictionStore();
1675 if ( $restrictionStore->areCascadeProtectionSourcesLoaded( $titleObject )
1679 $sources = $restrictionStore->getCascadeProtectionSources( $titleObject );
1680 $titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
1681 foreach ( $sources[0] as $sourcePageIdentity ) {
1682 $names[] = $titleFormatter->getPrefixedText( $sourcePageIdentity );
1684 return implode(
'|', $names );
1689 public static function interwikilink( $parser, $prefix =
'', $title =
'', $linkText =
null ) {
1690 $services = MediaWikiServices::getInstance();
1693 $services->getInterwikiLookup()->isValidInterwiki( $prefix )
1695 if ( $linkText !==
null ) {
1696 $linkText = Parser::stripOuterParagraph(
1700 [ $title, $frag ] = array_pad( explode(
'#', $title, 2 ), 2,
'' );
1702 $parser->
getOutput()->addInterwikiLink( $target );
1704 'text' => Linker::link( $target, $linkText ),
1709 return [
'found' => false ];
1713 $services = MediaWikiServices::getInstance();
1714 $extraInterlanguageLinkPrefixes = $services->getMainConfig()->get(
1715 MainConfigNames::ExtraInterlanguageLinkPrefixes
1719 $services->getInterwikiLookup()->isValidInterwiki( $prefix ) &&
1721 $services->getLanguageNameUtils()->getLanguageName(
1722 $prefix, LanguageNameUtils::AUTONYMS, LanguageNameUtils::DEFINED
1723 ) || in_array( $prefix, $extraInterlanguageLinkPrefixes,
true )
1727 [ $title, $frag ] = array_pad( explode(
'#', $title, 2 ), 2,
'' );
1730 NS_MAIN, $title, $frag, $prefix
1736 return [
'found' => false ];
1741class_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
array $params
The job parameters.
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.