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' ],
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 ];
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 $callback( $m[0] );
394 return $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 ( $text ===
'' ) {
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( $parser->
killMarkers(
1254 $frame->expand( array_shift( $args ) )
1258 if ( count( $args ) ) {
1262 $inner = $frame->expand( array_shift( $args ), $processNowiki );
1263 if ( $processNowiki ) {
1276 foreach ( $args as $arg ) {
1277 $bits = $arg->splitArg();
1278 if ( strval( $bits[
'index'] ) ===
'' ) {
1279 $name = trim( $frame->expand( $bits[
'name'], PPFrame::STRIP_COMMENTS ) );
1280 $value = trim( $frame->expand( $bits[
'value'] ) );
1281 if ( preg_match(
'/^(?:["\'](.+)["\']|""|\'\')$/s', $value, $m ) ) {
1282 $value = $m[1] ??
'';
1284 $attributes[$name] = $value;
1289 if ( !in_array( $tagName, $stripList ) ) {
1292 foreach ( $attributes as $name => $value ) {
1293 $attrText .=
' ' . htmlspecialchars( $name ) .
1294 '="' . htmlspecialchars( $parser->
killMarkers( $value ), ENT_COMPAT ) .
'"';
1296 if ( $inner ===
null ) {
1297 return "<$tagName$attrText/>";
1299 return "<$tagName$attrText>$inner</$tagName>";
1305 'attributes' => $attributes,
1306 'close' =>
"</$tagName>",
1324 private static function getCachedRevisionObject( $parser, $title, $vary ) {
1329 $revisionRecord =
null;
1331 $isSelfReferential = $title->equals( $parser->
getTitle() );
1332 if ( $isSelfReferential ) {
1343 if ( $parserRevisionRecord && $parserRevisionRecord->isCurrent() ) {
1344 $revisionRecord = $parserRevisionRecord;
1349 if ( !$revisionRecord ) {
1358 if ( !$revisionRecord ) {
1360 $revisionRecord =
null;
1363 $parserOutput->addTemplate(
1365 $revisionRecord ? $revisionRecord->getPageId() : 0,
1366 $revisionRecord ? $revisionRecord->getId() : 0
1370 if ( $isSelfReferential ) {
1371 wfDebug( __METHOD__ .
": used current revision, setting $vary" );
1373 $parserOutput->setOutputFlag( $vary );
1374 if ( $vary === ParserOutputFlags::VARY_REVISION_SHA1 && $revisionRecord ) {
1376 $sha1 = $revisionRecord->getSha1();
1377 }
catch ( RevisionAccessException $e ) {
1380 $parserOutput->setRevisionUsedSha1Base36( $sha1 );
1384 return $revisionRecord;
1394 public static function pageid( $parser, $title =
null ) {
1395 $t = self::makeTitle( $parser, $title );
1398 } elseif ( !$t->canExist() || $t->isExternal() ) {
1404 if ( $t->equals( $parser->
getTitle() ) ) {
1407 $parserOutput->setOutputFlag( ParserOutputFlags::VARY_PAGE_ID );
1408 $id = $parser->
getTitle()->getArticleID();
1410 $parserOutput->setSpeculativePageIdUsed( $id );
1417 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
1418 $pdbk = $t->getPrefixedDBkey();
1419 $id = $linkCache->getGoodLinkID( $pdbk );
1420 if ( $id != 0 || $linkCache->isBadLink( $pdbk ) ) {
1421 $parserOutput->addLink( $t, $id );
1428 $id = $t->getArticleID();
1429 $parserOutput->addLink( $t, $id );
1445 $t = self::makeTitle( $parser, $title );
1446 if ( $t ===
null || $t->isExternal() ) {
1450 $services = MediaWikiServices::getInstance();
1452 $t->equals( $parser->
getTitle() ) &&
1453 $services->getMainConfig()->get( MainConfigNames::MiserMode ) &&
1454 !$parser->
getOptions()->getInterfaceMessage() &&
1456 $services->getNamespaceInfo()->isSubject( $t->getNamespace() )
1463 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_REVISION_EXISTS );
1471 if ( $t->equals( $parser->
getTitle() ) && $title ===
null ) {
1474 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_REVISION_ID );
1479 $id = $rev->getId();
1483 $id = $parser->
getOptions()->getSpeculativeRevId();
1485 $parser->
getOutput()->setSpeculativeRevIdUsed( $id );
1490 $rev = self::getCachedRevisionObject( $parser, $t, ParserOutputFlags::VARY_REVISION_ID );
1491 return $rev ? $rev->getId() :
'';
1494 private static function getRevisionTimestampSubstring(
1507 if ( $title->equals( $parser->
getTitle() ) && !$parser->getOptions()->getInterfaceMessage() ) {
1522 if ( $resNow !== $resThen ) {
1525 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_REVISION_TIMESTAMP );
1531 $rev = self::getCachedRevisionObject( $parser, $title, ParserOutputFlags::VARY_REVISION_TIMESTAMP );
1550 $t = self::makeTitle( $parser, $title );
1551 if ( $t ===
null || $t->isExternal() ) {
1554 return strval( (
int)self::getRevisionTimestampSubstring(
1555 $parser, $t, 6, 2, self::MAX_TTS
1567 $t = self::makeTitle( $parser, $title );
1568 if ( $t ===
null || $t->isExternal() ) {
1571 return self::getRevisionTimestampSubstring(
1572 $parser, $t, 6, 2, self::MAX_TTS
1584 $t = self::makeTitle( $parser, $title );
1585 if ( $t ===
null || $t->isExternal() ) {
1588 return self::getRevisionTimestampSubstring(
1589 $parser, $t, 4, 2, self::MAX_TTS
1601 $t = self::makeTitle( $parser, $title );
1602 if ( $t ===
null || $t->isExternal() ) {
1605 return strval( (
int)self::getRevisionTimestampSubstring(
1606 $parser, $t, 4, 2, self::MAX_TTS
1618 $t = self::makeTitle( $parser, $title );
1619 if ( $t ===
null || $t->isExternal() ) {
1622 return self::getRevisionTimestampSubstring(
1623 $parser, $t, 0, 4, self::MAX_TTS
1635 $t = self::makeTitle( $parser, $title );
1636 if ( $t ===
null || $t->isExternal() ) {
1639 return self::getRevisionTimestampSubstring(
1640 $parser, $t, 0, 14, self::MAX_TTS
1652 $t = self::makeTitle( $parser, $title );
1653 if ( $t ===
null || $t->isExternal() ) {
1659 if ( $t->equals( $parser->
getTitle() ) ) {
1661 $parser->
getOutput()->setOutputFlag( ParserOutputFlags::VARY_USER );
1668 $rev = self::getCachedRevisionObject( $parser, $t, ParserOutputFlags::VARY_USER );
1669 $user = ( $rev !== null ) ? $rev->getUser() :
null;
1670 return $user ? $user->getName() :
'';
1686 $titleObject = Title::newFromText( $title ) ?? $parser->
getTitle();
1687 $restrictionStore = MediaWikiServices::getInstance()->getRestrictionStore();
1688 if ( $restrictionStore->areCascadeProtectionSourcesLoaded( $titleObject )
1692 $sources = $restrictionStore->getCascadeProtectionSources( $titleObject );
1693 $titleFormatter = MediaWikiServices::getInstance()->getTitleFormatter();
1694 foreach ( $sources[0] as $sourcePageIdentity ) {
1695 $names[] = $titleFormatter->getPrefixedText( $sourcePageIdentity );
1697 return implode(
'|', $names );
1702 public static function interwikilink( $parser, $prefix =
'', $title =
'', $linkText =
null ) {
1703 $services = MediaWikiServices::getInstance();
1706 $services->getInterwikiLookup()->isValidInterwiki( $prefix )
1708 if ( $linkText !==
null ) {
1709 $linkText = Parser::stripOuterParagraph(
1710 # FIXME T382287: when
using Parsoid
this may leave
1711 # strip markers behind for embedded extension tags.
1715 [ $title, $frag ] = array_pad( explode(
'#', $title, 2 ), 2,
'' );
1717 $parser->
getOutput()->addInterwikiLink( $target );
1719 'text' => Linker::link( $target, $linkText ),
1724 return [
'found' => false ];
1728 $services = MediaWikiServices::getInstance();
1729 $extraInterlanguageLinkPrefixes = $services->getMainConfig()->get(
1730 MainConfigNames::ExtraInterlanguageLinkPrefixes
1734 $services->getInterwikiLookup()->isValidInterwiki( $prefix ) &&
1736 $services->getLanguageNameUtils()->getLanguageName(
1737 $prefix, LanguageNameUtils::AUTONYMS, LanguageNameUtils::DEFINED
1738 ) || in_array( $prefix, $extraInterlanguageLinkPrefixes,
true )
1742 [ $title, $frag ] = array_pad( explode(
'#', $title, 2 ), 2,
'' );
1745 NS_MAIN, $title, $frag, $prefix
1751 return [
'found' => false ];
1756class_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.