23use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
32use Wikimedia\WrappedString;
33use Wikimedia\WrappedStringList;
51 use ProtectedHookAccessorTrait;
206 ResourceLoaderModule::TYPE_COMBINED => ResourceLoaderModule::ORIGIN_ALL,
289 'Accept-Encoding' =>
null,
355 $this->getHookContainer()
365 public function redirect( $url, $responsecode =
'302' ) {
366 # Strip newlines as a paranoia check for header injection in PHP<5.1.2
367 $this->mRedirect = str_replace(
"\n",
'', $url );
368 $this->mRedirectCode = (string)$responsecode;
377 return $this->mRedirect;
389 $this->copyrightUrl = $url;
398 $this->mStatusCode = $statusCode;
409 $this->mMetatags[] = [ $name, $val ];
419 return $this->mMetatags;
430 $this->mLinktags[] = $linkarr;
440 return $this->mLinktags;
449 $this->mCanonicalUrl = $url;
460 return $this->mCanonicalUrl;
471 $this->mScripts .= $script;
483 $this->
addScript( Html::linkedScript(
$file, $this->CSP->getNonce() ) );
493 $this->mScripts .= Html::inlineScript(
"\n$script\n", $this->CSP->getNonce() ) .
"\n";
505 $type = ResourceLoaderModule::TYPE_COMBINED
508 $filteredModules = [];
510 $module = $resourceLoader->getModule( $val );
514 if ( $this->mTarget && !in_array( $this->mTarget, $module->getTargets() ) ) {
518 $filteredModules[] = $val;
521 return $filteredModules;
525 static $warnings = [];
526 if ( isset( $warnings[$this->mTarget][$moduleName] ) ) {
529 $warnings[$this->mTarget][$moduleName] =
true;
531 'Module "{module}" not loadable on target "{target}".',
533 'module' => $moduleName,
534 'target' => $this->mTarget,
548 public function getModules( $filter =
false, $position =
null, $param =
'mModules',
549 $type = ResourceLoaderModule::TYPE_COMBINED
551 $modules = array_values( array_unique( $this->$param ) );
563 $this->mModules = array_merge( $this->mModules, (array)
$modules );
574 return $this->
getModules( $filter,
null,
'mModuleStyles',
575 ResourceLoaderModule::TYPE_STYLES
589 $this->mModuleStyles = array_merge( $this->mModuleStyles, (array)
$modules );
596 return $this->mTarget;
605 $this->mTarget = $target;
616 if ( !$this->contentOverrides ) {
619 $key = $target->getNamespace() .
':' . $target->getDBkey();
620 return $this->contentOverrides[$key] ??
null;
624 $key = $target->getNamespace() .
':' . $target->getDBkey();
625 $this->contentOverrides[$key] =
$content;
636 $this->contentOverrideCallbacks[] = $callback;
647 $this->mAdditionalHtmlClasses = array_merge( $this->mAdditionalHtmlClasses, (array)$classes );
656 return $this->mHeadItems;
672 $this->mHeadItems[$name] = $value;
682 $this->mHeadItems = array_merge( $this->mHeadItems, (array)$values );
692 return isset( $this->mHeadItems[$name] );
702 $this->mAdditionalBodyClasses = array_merge( $this->mAdditionalBodyClasses, (array)$classes );
713 $this->mArticleBodyOnly = $only;
722 return $this->mArticleBodyOnly;
733 $this->mProperties[$name] = $value;
744 return $this->mProperties[$name] ??
null;
759 if ( !$timestamp || $timestamp ==
'19700101000000' ) {
760 wfDebug( __METHOD__ .
": CACHE DISABLED, NO TIMESTAMP" );
764 if ( !$config->get(
'CachePages' ) ) {
765 wfDebug( __METHOD__ .
": CACHE DISABLED" );
771 'page' => $timestamp,
772 'user' => $this->
getUser()->getTouched(),
773 'epoch' => $config->get(
'CacheEpoch' )
775 if ( $config->get(
'UseCdn' ) ) {
778 $config->get(
'CdnMaxAge' )
781 $this->getHookRunner()->onOutputPageCheckLastModified( $modifiedTimes, $this );
783 $maxModified = max( $modifiedTimes );
784 $this->mLastModified =
wfTimestamp( TS_RFC2822, $maxModified );
786 $clientHeader = $this->
getRequest()->getHeader(
'If-Modified-Since' );
787 if ( $clientHeader ===
false ) {
788 wfDebug( __METHOD__ .
": client did not send If-Modified-Since header",
'private' );
792 # IE sends sizes after the date like this:
793 # Wed, 20 Aug 2003 06:51:19 GMT; length=5202
794 # this breaks strtotime().
795 $clientHeader = preg_replace(
'/;.*$/',
'', $clientHeader );
797 Wikimedia\suppressWarnings();
798 $clientHeaderTime = strtotime( $clientHeader );
799 Wikimedia\restoreWarnings();
800 if ( !$clientHeaderTime ) {
802 .
": unable to parse the client's If-Modified-Since header: $clientHeader" );
805 $clientHeaderTime =
wfTimestamp( TS_MW, $clientHeaderTime );
809 foreach ( $modifiedTimes as $name => $value ) {
810 if ( $info !==
'' ) {
813 $info .=
"$name=" .
wfTimestamp( TS_ISO_8601, $value );
816 wfDebug( __METHOD__ .
": client sent If-Modified-Since: " .
817 wfTimestamp( TS_ISO_8601, $clientHeaderTime ),
'private' );
818 wfDebug( __METHOD__ .
": effective Last-Modified: " .
819 wfTimestamp( TS_ISO_8601, $maxModified ),
'private' );
820 if ( $clientHeaderTime < $maxModified ) {
821 wfDebug( __METHOD__ .
": STALE, $info",
'private' );
826 # Give a 304 Not Modified response code and disable body output
827 wfDebug( __METHOD__ .
": NOT MODIFIED, $info",
'private' );
828 ini_set(
'zlib.output_compression', 0 );
829 $this->
getRequest()->response()->statusHeader( 304 );
851 return $reqTime - $maxAge;
861 $this->mLastModified =
wfTimestamp( TS_RFC2822, $timestamp );
872 $policy = Article::formatRobotPolicy( $policy );
874 if ( isset( $policy[
'index'] ) ) {
877 if ( isset( $policy[
'follow'] ) ) {
889 return "{$this->mIndexPolicy},{$this->mFollowPolicy}";
899 $policy = trim( $policy );
900 if ( in_array( $policy, [
'index',
'noindex' ] ) ) {
901 $this->mIndexPolicy = $policy;
911 return $this->mIndexPolicy;
921 $policy = trim( $policy );
922 if ( in_array( $policy, [
'follow',
'nofollow' ] ) ) {
923 $this->mFollowPolicy = $policy;
933 return $this->mFollowPolicy;
943 if ( $name instanceof
Message ) {
944 $this->mHTMLtitle = $name->setContext( $this->
getContext() )->text();
946 $this->mHTMLtitle = $name;
956 return $this->mHTMLtitle;
965 $this->mRedirectedFrom =
$t;
981 if ( $name instanceof
Message ) {
982 $name = $name->setContext( $this->
getContext() )->text();
985 # change "<script>foo&bar</script>" to "<script>foo&bar</script>"
986 # but leave "<i>foobar</i>" alone
987 $nameWithTags = Sanitizer::normalizeCharReferences( Sanitizer::removeHTMLtags( $name ) );
988 $this->mPageTitle = $nameWithTags;
990 # change "<i>foo&bar</i>" to "foo&bar"
992 $this->
msg(
'pagetitle' )->plaintextParams( Sanitizer::stripAllTags( $nameWithTags ) )
993 ->inContentLanguage()
1003 return $this->mPageTitle;
1014 $this->displayTitle = $html;
1026 $html = $this->displayTitle;
1027 if ( $html ===
null ) {
1028 $html = $this->
getTitle()->getPrefixedText();
1031 return Sanitizer::normalizeCharReferences( Sanitizer::removeHTMLtags( $html ) );
1042 $nsPrefix = $this->
getTitle()->getNsText() .
':';
1043 $prefix = preg_quote( $nsPrefix,
'/' );
1045 return preg_replace(
"/^$prefix/i",
'', $text );
1054 $t = Title::castFromPageReference(
$t );
1077 if ( $str instanceof
Message ) {
1078 $this->mSubtitle[] = $str->setContext( $this->
getContext() )->parse();
1080 $this->mSubtitle[] = $str;
1095 if ( $page->isRedirect() ) {
1096 $query[
'redirect'] =
'no';
1100 $query[
'redirect'] =
'no';
1103 $target = TitleValue::castPageToLinkTarget( $page );
1104 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
1106 ->rawParams( $linkRenderer->makeLink( $target,
null, [], $query ) );
1123 $this->mSubtitle = [];
1130 return implode(
"<br />\n\t\t\t\t", $this->mSubtitle );
1138 $this->mPrintable =
true;
1147 return $this->mPrintable;
1154 $this->mDoNothing =
true;
1163 return $this->mDoNothing;
1172 return $this->mNewSectionLink;
1181 return $this->mHideNewSectionLink;
1196 $this->mFeedLinks = [];
1207 if ( $this->
getConfig()->
get(
'Feed' ) ) {
1208 return $this->
getConfig()->get(
'AdvertisedFeedTypes' );
1224 $this->mFeedLinks = [];
1227 $query =
"feed=$type";
1228 if ( is_string( $val ) ) {
1229 $query .=
'&' . $val;
1231 $this->mFeedLinks[
$type] = $this->
getTitle()->getLocalURL( $query );
1243 $this->mFeedLinks[$format] = $href;
1252 return count( $this->mFeedLinks ) > 0;
1260 return $this->mFeedLinks;
1269 return $this->mFeedLinksAppendQuery;
1280 $this->mIsArticle = $newVal;
1282 $this->mIsArticleRelated = $newVal;
1293 return $this->mIsArticle;
1303 $this->mIsArticleRelated = $newVal;
1305 $this->mIsArticle =
false;
1315 return $this->mIsArticleRelated;
1324 $this->mHasCopyright = $hasCopyright;
1337 return $this->
isArticle() || $this->mHasCopyright;
1347 $this->mLanguageLinks = array_merge( $this->mLanguageLinks, $newLinkArray );
1357 $this->mLanguageLinks = $newLinkArray;
1366 return $this->mLanguageLinks;
1375 if ( !$categories ) {
1381 # Set all the values to 'normal'.
1382 $categories = array_fill_keys( array_keys( $categories ),
'normal' );
1384 # Mark hidden categories
1385 foreach (
$res as $row ) {
1386 if ( isset( $row->pp_value ) ) {
1387 $categories[$row->page_title] =
'hidden';
1391 # Add the remaining categories to the skin
1392 if ( $this->getHookRunner()->onOutputPageMakeCategoryLinks(
1393 $this, $categories, $this->mCategoryLinks )
1395 $services = MediaWikiServices::getInstance();
1396 $linkRenderer = $services->getLinkRenderer();
1397 $languageConverter = $services->getLanguageConverterFactory()
1398 ->getLanguageConverter( $services->getContentLanguage() );
1399 foreach ( $categories as $category =>
$type ) {
1401 $category = (string)$category;
1402 $origcategory = $category;
1407 $languageConverter->findVariantLink( $category,
$title,
true );
1409 if ( $category != $origcategory && array_key_exists( $category, $categories ) ) {
1412 $text = $languageConverter->convertHtml(
$title->getText() );
1424 # Add the links to a LinkBatch
1426 $linkBatchFactory = MediaWikiServices::getInstance()->getLinkBatchFactory();
1427 $lb = $linkBatchFactory->newLinkBatch();
1428 $lb->setArray( $arr );
1430 # Fetch existence plus the hiddencat property
1432 $fields = array_merge(
1433 LinkCache::getSelectFields(),
1434 [
'page_namespace',
'page_title',
'pp_value' ]
1437 $res =
$dbr->select( [
'page',
'page_props' ],
1439 $lb->constructSet(
'page',
$dbr ),
1442 [
'page_props' => [
'LEFT JOIN', [
1443 'pp_propname' =>
'hiddencat',
1448 # Add the results to the link cache
1449 $linkCache = MediaWikiServices::getInstance()->getLinkCache();
1450 $lb->addResultToCache( $linkCache,
$res );
1461 $this->mCategoryLinks = [];
1474 return $this->mCategoryLinks;
1487 if (
$type ===
'all' ) {
1488 $allCategories = [];
1489 foreach ( $this->mCategories as $categories ) {
1490 $allCategories = array_merge( $allCategories, $categories );
1492 return $allCategories;
1494 if ( !isset( $this->mCategories[
$type] ) ) {
1495 throw new InvalidArgumentException(
'Invalid category type given: ' .
$type );
1497 return $this->mCategories[
$type];
1510 $this->mIndicators = $indicators + $this->mIndicators;
1512 ksort( $this->mIndicators );
1524 return $this->mIndicators;
1537 $text = $this->
msg(
'helppage-top-gethelp' )->escaped();
1539 if ( $overrideBaseUrl ) {
1542 $toUrlencoded =
wfUrlencode( str_replace(
' ',
'_', $to ) );
1543 $helpUrl =
"https://www.mediawiki.org/wiki/Special:MyLanguage/$toUrlencoded";
1546 $link = Html::rawElement(
1550 'target' =>
'_blank',
1551 'class' =>
'mw-helplink',
1569 ResourceLoaderModule::TYPE_SCRIPTS,
1570 ResourceLoaderModule::ORIGIN_CORE_INDIVIDUAL
1575 if ( $this->
getConfig()->
get(
'AllowSiteCSSOnRestrictedPages' ) ) {
1576 $styleOrigin = ResourceLoaderModule::ORIGIN_USER_SITEWIDE;
1578 $styleOrigin = ResourceLoaderModule::ORIGIN_CORE_INDIVIDUAL;
1581 ResourceLoaderModule::TYPE_STYLES,
1593 if (
$type == ResourceLoaderModule::TYPE_COMBINED ) {
1594 return min( array_values( $this->mAllowedModules ) );
1596 return $this->mAllowedModules[
$type] ?? ResourceLoaderModule::ORIGIN_ALL;
1619 $this->mBodytext = $text . $this->mBodytext;
1628 $this->mBodytext .= $text;
1640 public function addElement( $element, array $attribs = [], $contents =
'' ) {
1641 $this->
addHTML( Html::element( $element, $attribs, $contents ) );
1648 $this->mBodytext =
'';
1657 return $this->mBodytext;
1667 if ( !$this->mParserOptions ) {
1668 if ( !$this->
getUser()->isSafeToLoad() ) {
1672 $po = ParserOptions::newFromAnon();
1673 $po->setAllowUnsafeRawHtml(
false );
1674 $po->isBogus =
true;
1678 $this->mParserOptions = ParserOptions::newFromContext( $this->
getContext() );
1679 $this->mParserOptions->setAllowUnsafeRawHtml(
false );
1682 return $this->mParserOptions;
1693 $val = $revid ===
null ? null : intval( $revid );
1694 return wfSetVar( $this->mRevisionId, $val,
true );
1703 return $this->mRevisionId;
1713 return $this->mRevisionId == 0 || $this->mRevisionId == $this->
getTitle()->getLatestRevID();
1724 return wfSetVar( $this->mRevisionTimestamp, $timestamp,
true );
1734 return $this->mRevisionTimestamp;
1746 $val = [
'time' =>
$file->getTimestamp(),
'sha1' =>
$file->getSha1() ];
1748 return wfSetVar( $this->mFileVersion, $val,
true );
1757 return $this->mFileVersion;
1767 return $this->mTemplateIds;
1777 return $this->mImageTimeKeys;
1822 $wrapperClass, $text
1874 $text,
$title, $linestart, $interface
1878 'enableSectionEditLinks' =>
false,
1879 'wrapperDivClass' => $wrapperClass ??
'',
1892 $this->mLanguageLinks =
1903 $this->mHeadItems = array_merge( $this->mHeadItems, $parserOutput->
getHeadItems() );
1907 $this->mPreventClickjacking = $this->mPreventClickjacking
1910 foreach ( $scriptSrcs as $src ) {
1911 $this->
getCSP()->addScriptSrc( $src );
1914 foreach ( $defaultSrcs as $src ) {
1915 $this->
getCSP()->addDefaultSrc( $src );
1918 foreach ( $styleSrcs as $src ) {
1919 $this->
getCSP()->addStyleSrc( $src );
1929 if ( $this->
getConfig()->
get(
'ImagePreconnect' ) && count( $parserOutput->
getImages() ) ) {
1931 $repoGroup = MediaWikiServices::getInstance()->getRepoGroup();
1932 $repoGroup->forEachForeignRepo(
static function ( $repo ) use ( &$preconnect ) {
1933 $preconnect[] =
wfParseUrl( $repo->getZoneUrl(
'thumb' ) )[
'host'];
1935 $preconnect[] =
wfParseUrl( $repoGroup->getLocalRepo()->getZoneUrl(
'thumb' ) )[
'host'];
1936 foreach ( $preconnect as $host ) {
1938 $this->
addLink( [
'rel' =>
'preconnect',
'href' =>
'//' . $host ] );
1945 foreach ( (array)$parserOutput->
getTemplateIds() as $ns => $dbks ) {
1946 if ( isset( $this->mTemplateIds[$ns] ) ) {
1947 $this->mTemplateIds[$ns] = $dbks + $this->mTemplateIds[$ns];
1949 $this->mTemplateIds[$ns] = $dbks;
1954 $this->mImageTimeKeys[$dbk] = $data;
1958 $parserOutputHooks = $this->
getConfig()->get(
'ParserOutputHooks' );
1960 list( $hookName, $data ) = $hookInfo;
1961 if ( isset( $parserOutputHooks[$hookName] ) ) {
1962 $parserOutputHooks[$hookName]( $this, $parserOutput, $data );
1972 if ( !$this->limitReportJSData ) {
1979 $this->getHookRunner()->onLanguageLinks( $this->
getTitle(), $this->mLanguageLinks, $linkFlags );
1980 $this->getHookRunner()->onOutputPageParserOutput( $this, $parserOutput );
1987 $this->mEnableTOC =
true;
2016 $text = $parserOutput->
getText( $poOptions );
2017 $this->getHookRunner()->onOutputPageBeforeHTML( $this, $text );
2038 $this->
addHTML( $template->getHTML() );
2054 $text, $this->
getTitle(), $linestart,
false
2056 'enableSectionEditLinks' =>
false,
2057 'wrapperDivClass' =>
''
2075 $text, $this->
getTitle(), $linestart,
true
2077 'enableSectionEditLinks' =>
false,
2078 'wrapperDivClass' =>
''
2116 throw new MWException(
'Empty $mTitle in ' . __METHOD__ );
2121 $oldInterface = $popts->setInterfaceMessage( (
bool)$interface );
2123 $parserOutput = MediaWikiServices::getInstance()->getParser()->getFreshParser()->parse(
2125 $linestart,
true, $this->mRevisionId
2128 $popts->setInterfaceMessage( $oldInterface );
2130 return $parserOutput;
2139 $this->mCdnMaxage = min( $maxage, $this->mCdnMaxageLimit );
2152 $this->mCdnMaxageLimit = min( $maxage, $this->mCdnMaxageLimit );
2169 $minTTL = $minTTL ?: IExpiringStore::TTL_MINUTE;
2170 $maxTTL = $maxTTL ?: $this->
getConfig()->get(
'CdnMaxAge' );
2172 if ( $mtime ===
null || $mtime ===
false ) {
2176 $age = MWTimestamp::time() - (int)
wfTimestamp( TS_UNIX, $mtime );
2177 $adaptiveTTL = max( 0.9 * $age, $minTTL );
2178 $adaptiveTTL = min( $adaptiveTTL, $maxTTL );
2191 return wfSetVar( $this->mEnableClientCache, $state );
2201 if ( !$this->cacheIsFinal ) {
2211 return $this->mEnableClientCache;
2224 $this->cacheIsFinal =
true;
2233 if ( self::$cacheVaryCookies ===
null ) {
2235 self::$cacheVaryCookies = array_values( array_unique( array_merge(
2236 SessionManager::singleton()->getVaryCookies(),
2240 $config->get(
'CacheVaryCookies' )
2242 $this->getHookRunner()->onGetCacheVaryCookies( $this, self::$cacheVaryCookies );
2244 return self::$cacheVaryCookies;
2256 if ( $request->getCookie( $cookieName,
'',
'' ) !==
'' ) {
2257 wfDebug( __METHOD__ .
": found $cookieName" );
2261 wfDebug( __METHOD__ .
": no cache-varying cookies found" );
2275 if ( $option !==
null && count( $option ) > 0 ) {
2277 'The $option parameter to addVaryHeader is ignored since MediaWiki 1.34',
2280 if ( !array_key_exists(
$header, $this->mVaryHeader ) ) {
2281 $this->mVaryHeader[
$header] =
null;
2297 foreach ( SessionManager::singleton()->getVaryHeaders() as
$header => $options ) {
2300 return 'Vary: ' . implode(
', ', array_keys( $this->mVaryHeader ) );
2309 $this->mLinkHeader[] =
$header;
2318 if ( !$this->mLinkHeader ) {
2322 return 'Link: ' . implode(
',', $this->mLinkHeader );
2338 $languageConverter = MediaWikiServices::getInstance()->getLanguageConverterFactory()
2339 ->getLanguageConverter(
$title->getPageLanguage() );
2340 if ( !$this->
getRequest()->getCheck(
'variant' ) && $languageConverter->hasVariants() ) {
2356 $this->mPreventClickjacking = $enable;
2365 $this->mPreventClickjacking =
false;
2375 return $this->mPreventClickjacking;
2387 if ( $config->get(
'BreakFrames' ) ) {
2389 } elseif ( $this->mPreventClickjacking && $config->get(
'EditPageFrameOptions' ) ) {
2390 return $config->get(
'EditPageFrameOptions' );
2404 return $config->get(
'OriginTrials' );
2410 $expiry = $config->get(
'ReportToExpiry' );
2416 $endpoints = $config->get(
'ReportToEndpoints' );
2418 if ( !$endpoints ) {
2422 $output = [
'max_age' => $expiry,
'endpoints' => [] ];
2424 foreach ( $endpoints as $endpoint ) {
2425 $output[
'endpoints'][] = [
'url' => $endpoint ];
2428 return json_encode( $output, JSON_UNESCAPED_SLASHES );
2434 $features = $config->get(
'FeaturePolicyReportOnly' );
2435 return implode(
';', $features );
2448 # don't serve compressed data to clients who can't handle it
2449 # maintain different caches for logged-in users and non-logged in ones
2452 if ( $this->mEnableClientCache ) {
2453 if ( !$config->get(
'UseCdn' ) ) {
2454 $privateReason =
'config';
2455 } elseif ( $response->hasCookies() ) {
2456 $privateReason =
'set-cookies';
2459 } elseif ( SessionManager::getGlobalSession()->isPersistent() ) {
2460 $privateReason =
'session';
2462 $privateReason =
'printable';
2463 } elseif ( $this->mCdnMaxage == 0 ) {
2464 $privateReason =
'no-maxage';
2466 $privateReason =
'cache-vary-cookies';
2468 $privateReason =
false;
2471 if ( $privateReason ===
false ) {
2472 # We'll purge the proxy cache for anons explicitly, but require end user agents
2473 # to revalidate against the proxy on each visit.
2474 # IMPORTANT! The CDN needs to replace the Cache-Control header with
2475 # Cache-Control: s-maxage=0, must-revalidate, max-age=0
2477 ": local proxy caching; {$this->mLastModified} **",
'private' );
2478 # start with a shorter timeout for initial testing
2479 # header( "Cache-Control: s-maxage=2678400, must-revalidate, max-age=0" );
2480 $response->header(
"Cache-Control: " .
2481 "s-maxage={$this->mCdnMaxage}, must-revalidate, max-age=0" );
2483 # We do want clients to cache if they can, but they *must* check for updates
2484 # on revisiting the page, after the max-age period.
2485 wfDebug( __METHOD__ .
": private caching ($privateReason); {$this->mLastModified} **",
'private' );
2487 if ( $response->hasCookies() || SessionManager::getGlobalSession()->isPersistent() ) {
2488 $response->header(
'Expires: ' . gmdate(
'D, d M Y H:i:s', 0 ) .
' GMT' );
2489 $response->header(
"Cache-Control: private, must-revalidate, max-age=0" );
2492 'Expires: ' . gmdate(
'D, d M Y H:i:s', time() + $config->get(
'LoggedOutMaxAge' ) ) .
' GMT'
2495 "Cache-Control: private, must-revalidate, max-age={$config->get( 'LoggedOutMaxAge' )}"
2499 if ( $this->mLastModified ) {
2500 $response->header(
"Last-Modified: {$this->mLastModified}" );
2503 wfDebug( __METHOD__ .
": no caching **",
'private' );
2505 # In general, the absence of a last modified header should be enough to prevent
2506 # the client from using its cache. We send a few other things just to make sure.
2507 $response->header(
'Expires: ' . gmdate(
'D, d M Y H:i:s', 0 ) .
' GMT' );
2508 $response->header(
'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
2509 $response->header(
'Pragma: no-cache' );
2519 foreach ( $sk->getDefaultModules() as $group =>
$modules ) {
2520 if ( $group ===
'styles' ) {
2521 foreach (
$modules as $key => $moduleMembers ) {
2541 if ( $this->mDoNothing ) {
2542 return $return ?
'' :
null;
2548 if ( $this->mRedirect !=
'' ) {
2549 # Standards require redirect URLs to be absolute
2552 $redirect = $this->mRedirect;
2553 $code = $this->mRedirectCode;
2556 if ( $this->getHookRunner()->onBeforePageRedirect( $this, $redirect, $code ) ) {
2557 if ( $code ==
'301' || $code ==
'303' ) {
2558 if ( !$config->get(
'DebugRedirects' ) ) {
2559 $response->statusHeader( $code );
2563 if ( $config->get(
'VaryOnXFP' ) ) {
2568 $response->header(
"Content-Type: text/html; charset=utf-8" );
2569 if ( $config->get(
'DebugRedirects' ) ) {
2570 $url = htmlspecialchars( $redirect );
2571 $content =
"<!DOCTYPE html>\n<html>\n<head>\n"
2572 .
"<title>Redirect</title>\n</head>\n<body>\n"
2573 .
"<p>Location: <a href=\"$url\">$url</a></p>\n"
2574 .
"</body>\n</html>\n";
2581 $response->header(
'Location: ' . $redirect );
2586 } elseif ( $this->mStatusCode ) {
2587 $response->statusHeader( $this->mStatusCode );
2590 # Buffer output; final headers may depend on later processing
2593 $response->header(
'Content-type: ' . $config->get(
'MimeType' ) .
'; charset=UTF-8' );
2594 $response->header(
'Content-language: ' .
2595 MediaWikiServices::getInstance()->getContentLanguage()->getHtmlCode() );
2598 if ( $linkHeader ) {
2599 $response->header( $linkHeader );
2604 if ( $frameOptions ) {
2605 $response->header(
"X-Frame-Options: $frameOptions" );
2609 foreach ( $originTrials as $originTrial ) {
2610 $response->header(
"Origin-Trial: $originTrial",
false );
2615 $response->header(
"Report-To: $reportTo" );
2619 if ( $featurePolicyReportOnly ) {
2620 $response->header(
"Feature-Policy-Report-Only: $featurePolicyReportOnly" );
2623 if ( $this->mArticleBodyOnly ) {
2624 $this->CSP->sendHeaders();
2625 echo $this->mBodytext;
2628 if ( $this->
getRequest()->getBool(
'safemode' ) ) {
2635 MWDebug::addModules( $this );
2639 $this->getHookRunner()->onBeforePageDisplay( $this, $sk );
2641 $this->CSP->sendHeaders();
2645 }
catch ( Exception $e ) {
2653 $this->getHookRunner()->onAfterFinalPageOutput( $this );
2654 }
catch ( Exception $e ) {
2662 return ob_get_clean();
2681 if ( $htmlTitle !==
false ) {
2687 $this->mRedirect =
'';
2711 if ( $msg instanceof
Message ) {
2712 if ( $params !== [] ) {
2713 trigger_error(
'Argument ignored: $params. The message parameters argument '
2714 .
'is discarded when the $msg argument is a Message object instead of '
2715 .
'a string.', E_USER_NOTICE );
2717 $this->
addHTML( $msg->parseAsBlock() );
2732 $services = MediaWikiServices::getInstance();
2733 $permissionManager = $services->getPermissionManager();
2734 foreach ( $errors as $key => $error ) {
2735 $errors[$key] = (array)$error;
2744 if ( in_array( $action, [
'read',
'edit',
'createpage',
'createtalk',
'upload' ] )
2745 && $this->
getUser()->isAnon() && count( $errors ) == 1 && isset( $errors[0][0] )
2746 && ( $errors[0][0] ==
'badaccess-groups' || $errors[0][0] ==
'badaccess-group0' )
2747 && ( $permissionManager->groupHasPermission(
'user', $action )
2748 || $permissionManager->groupHasPermission(
'autoconfirmed', $action ) )
2750 $displayReturnto =
null;
2752 # Due to T34276, if a user does not have read permissions,
2753 # $this->getTitle() will just give Special:Badtitle, which is
2754 # not especially useful as a returnto parameter. Use the title
2755 # from the request instead, if there was one.
2757 $returnto = Title::newFromText( $request->getText(
'title' ) );
2758 if ( $action ==
'edit' ) {
2759 $msg =
'whitelistedittext';
2760 $displayReturnto = $returnto;
2761 } elseif ( $action ==
'createpage' || $action ==
'createtalk' ) {
2762 $msg =
'nocreatetext';
2763 } elseif ( $action ==
'upload' ) {
2764 $msg =
'uploadnologintext';
2766 $msg =
'loginreqpagetext';
2767 $displayReturnto = Title::newMainPage();
2773 $query[
'returnto'] = $returnto->getPrefixedText();
2775 if ( !$request->wasPosted() ) {
2776 $returntoquery = $request->getValues();
2777 unset( $returntoquery[
'title'] );
2778 unset( $returntoquery[
'returnto'] );
2779 unset( $returntoquery[
'returntoquery'] );
2780 $query[
'returntoquery'] =
wfArrayToCgi( $returntoquery );
2785 $linkRenderer = $services->getLinkRenderer();
2787 $loginLink = $linkRenderer->makeKnownLink(
2789 $this->
msg(
'loginreqlink' )->text(),
2795 $this->
addHTML( $this->
msg( $msg )->rawParams( $loginLink )->params( $loginUrl )->parse() );
2797 # Don't return to a page the user can't read otherwise
2798 # we'll end up in a pointless loop
2799 if ( $displayReturnto && $this->
getAuthority()->probablyCan(
'read', $displayReturnto ) ) {
2817 $this->
addWikiMsg(
'versionrequiredtext', $version );
2829 if ( $status->isGood() ) {
2832 return $this->formatPermissionsErrorMessage( $status->toLegacyErrorArray(), $action );
2844 if ( $action ==
null ) {
2845 $text = $this->msg(
'permissionserrorstext', count( $errors ) )->plain() .
"\n\n";
2847 $action_desc = $this->msg(
"action-$action" )->plain();
2849 'permissionserrorstext-withaction',
2852 )->plain() .
"\n\n";
2855 if ( count( $errors ) > 1 ) {
2856 $text .=
'<ul class="permissions-errors">' .
"\n";
2858 foreach ( $errors as $error ) {
2860 $text .= $this->msg( ...$error )->plain();
2865 $text .=
"<div class=\"permissions-errors\">\n" .
2866 $this->msg( ...reset( $errors ) )->plain() .
2883 $config = $this->getConfig();
2884 if ( $lag >= $config->get(
'DatabaseReplicaLagWarning' ) ) {
2885 $lag = floor( $lag );
2886 $message = $lag < $config->get(
'DatabaseReplicaLagCritical' )
2890 $wrap = Html::rawElement(
'div', [
'class' =>
"mw-{$message}" ],
"\n$1\n" );
2891 $this->wrapWikiMsg(
"$wrap\n", [ $message, $this->getLanguage()->formatNum( $lag ) ] );
2902 $this->prepareErrorPage( $this->msg(
'internalerror' ) );
2904 $this->addHTML( $message );
2916 $linkRenderer = MediaWikiServices::getInstance()
2917 ->getLinkRendererFactory()->createFromLegacyOptions( $options );
2918 $link = $this->msg(
'returnto' )->rawParams(
2919 $linkRenderer->makeLink(
$title, $text, [], $query ) )->escaped();
2920 $this->addHTML(
"<p id=\"mw-returnto\">{$link}</p>\n" );
2931 public function returnToMain( $unused =
null, $returnto =
null, $returntoquery =
null ) {
2932 if ( $returnto ==
null ) {
2933 $returnto = $this->getRequest()->getText(
'returnto' );
2936 if ( $returntoquery ==
null ) {
2937 $returntoquery = $this->getRequest()->getText(
'returntoquery' );
2940 if ( $returnto ===
'' ) {
2941 $returnto = Title::newMainPage();
2944 if ( is_object( $returnto ) ) {
2945 $linkTarget = TitleValue::castPageToLinkTarget( $returnto );
2947 $linkTarget = Title::newFromText( $returnto );
2952 if ( !is_object( $linkTarget ) || $linkTarget->isExternal() ) {
2953 $linkTarget = Title::newMainPage();
2956 $this->addReturnTo( $linkTarget,
wfCgiToArray( $returntoquery ) );
2960 if ( !$this->rlClientContext ) {
2963 $this->getLanguage()->getCode(),
2964 $this->getSkin()->getSkinName(),
2965 $this->getUser()->isRegistered() ? $this->getUser()->getName() :
null,
2969 $this->isPrintable(),
2970 $this->getRequest()->getBool(
'handheld' )
2973 $this->getResourceLoader(),
2976 if ( $this->contentOverrideCallbacks ) {
2978 $this->rlClientContext->setContentOverrideCallback(
function (
$title ) {
2979 foreach ( $this->contentOverrideCallbacks as $callback ) {
2982 $text = ContentHandler::getContentText(
$content );
2983 if ( strpos( $text,
'</script>' ) !==
false ) {
2988 Xml::encodeJsCall(
'mw.log.error', [
2989 "Cannot preview $title due to script-closing tag."
3000 return $this->rlClientContext;
3015 if ( !$this->rlClient ) {
3016 $context = $this->getRlClientContext();
3017 $rl = $this->getResourceLoader();
3018 $this->addModules( [
3022 $this->addModuleStyles( [
3029 $exemptGroups = [
'site' => [],
'noscript' => [],
'private' => [],
'user' => [] ];
3031 $moduleStyles = $this->getModuleStyles(
true );
3035 $userBatch = [
'user.styles',
'user' ];
3036 $siteBatch = array_diff( $moduleStyles, $userBatch );
3038 ResourceLoaderWikiModule::preloadTitleInfo( $context,
$dbr, $siteBatch );
3039 ResourceLoaderWikiModule::preloadTitleInfo( $context,
$dbr, $userBatch );
3042 $moduleStyles = array_filter( $moduleStyles,
3043 static function ( $name ) use ( $rl, $context, &$exemptGroups, &$exemptStates ) {
3044 $module = $rl->getModule( $name );
3046 $group = $module->getGroup();
3047 if ( isset( $exemptGroups[$group] ) ) {
3048 $exemptStates[$name] =
'ready';
3049 if ( !$module->isKnownEmpty( $context ) ) {
3051 $exemptGroups[$group][] = $name;
3059 $this->rlExemptStyleModules = $exemptGroups;
3062 'target' => $this->getTarget(),
3063 'nonce' => $this->CSP->getNonce(),
3071 'safemode' => ( $this->getAllowedModules( ResourceLoaderModule::TYPE_COMBINED )
3072 <= ResourceLoaderModule::ORIGIN_CORE_INDIVIDUAL
3075 $rlClient->
setConfig( $this->getJSVars() );
3076 $rlClient->setModules( $this->getModules(
true ) );
3077 $rlClient->setModuleStyles( $moduleStyles );
3078 $rlClient->setExemptStates( $exemptStates );
3079 $this->rlClient = $rlClient;
3081 return $this->rlClient;
3090 $config = $this->getConfig();
3091 $userdir = $this->getLanguage()->getDir();
3092 $services = MediaWikiServices::getInstance();
3093 $sitedir = $services->getContentLanguage()->getDir();
3096 $htmlAttribs = Sanitizer::mergeAttributes( Sanitizer::mergeAttributes(
3097 $this->getRlClient()->getDocumentAttributes(),
3099 ), [
'class' => implode(
' ', $this->mAdditionalHtmlClasses ) ] );
3100 $pieces[] = Html::htmlHeader( $htmlAttribs );
3101 $pieces[] = Html::openElement(
'head' );
3103 if ( $this->getHTMLTitle() ==
'' ) {
3104 $this->setHTMLTitle( $this->msg(
'pagetitle', $this->getPageTitle() )->inContentLanguage() );
3107 if ( !Html::isXmlMimeType( $config->get(
'MimeType' ) ) ) {
3116 $pieces[] = Html::element(
'meta', [
'charset' =>
'UTF-8' ] );
3119 $pieces[] = Html::element(
'title',
null, $this->getHTMLTitle() );
3120 $pieces[] = $this->getRlClient()->getHeadHtml( $htmlAttribs[
'class'] ??
null );
3121 $pieces[] = $this->buildExemptModules();
3122 $pieces = array_merge( $pieces, array_values( $this->getHeadLinksArray() ) );
3123 $pieces = array_merge( $pieces, array_values( $this->mHeadItems ) );
3125 $pieces[] = Html::closeElement(
'head' );
3127 $bodyClasses = $this->mAdditionalBodyClasses;
3128 $bodyClasses[] =
'mediawiki';
3130 # Classes for LTR/RTL directionality support
3131 $bodyClasses[] = $userdir;
3132 $bodyClasses[] =
"sitedir-$sitedir";
3134 $underline = $services->getUserOptionsLookup()->getOption( $this->getUser(),
'underline' );
3135 if ( $underline < 2 ) {
3139 $bodyClasses[] =
'mw-underline-' . ( $underline ?
'always' :
'never' );
3145 $bodyClasses[] =
'mw-hide-empty-elt';
3148 $bodyClasses[] =
'skin-' . Sanitizer::escapeClass( $sk->
getSkinName() );
3150 'action-' . Sanitizer::escapeClass( Action::getActionName( $this->
getContext() ) );
3153 $bodyClasses[] =
'skin--responsive';
3159 $bodyAttrs[
'class'] = implode(
' ', $bodyClasses );
3163 if ( method_exists( $sk,
'addToBodyAttributes' ) ) {
3165 $sk->addToBodyAttributes( $this, $bodyAttrs );
3166 wfDeprecated(
'Skin::addToBodyAttributes method to add body attributes',
'1.35' );
3170 $this->getHookRunner()->onOutputPageBodyAttributes( $this, $sk, $bodyAttrs );
3172 $pieces[] = Html::openElement(
'body', $bodyAttrs );
3174 return self::combineWrappedStrings( $pieces );
3183 if ( $this->mResourceLoader ===
null ) {
3185 $this->mResourceLoader = MediaWikiServices::getInstance()->getResourceLoader();
3187 return $this->mResourceLoader;
3203 $this->getRlClientContext(),
3207 $this->CSP->getNonce()
3219 $chunks = array_filter( $chunks,
'strlen' );
3220 return WrappedString::join(
"\n", $chunks );
3232 $chunks[] = $this->getRlClient()->getBodyHtml();
3235 $chunks[] = $this->mScripts;
3237 if ( $this->limitReportJSData ) {
3240 [
'wgPageParseReport' => $this->limitReportJSData ]
3242 $this->CSP->getNonce()
3248 $chunks[] = $extraHtml;
3250 return self::combineWrappedStrings( $chunks );
3260 return $this->mJsConfigVars;
3270 if ( is_array(
$keys ) ) {
3271 foreach (
$keys as $key => $value ) {
3272 $this->mJsConfigVars[$key] = $value;
3277 $this->mJsConfigVars[
$keys] = $value;
3292 $canonicalSpecialPageName =
false; # T23115
3293 $services = MediaWikiServices::getInstance();
3296 $ns =
$title->getNamespace();
3297 $nsInfo = $services->getNamespaceInfo();
3298 $canonicalNamespace = $nsInfo->exists( $ns )
3299 ? $nsInfo->getCanonicalName( $ns )
3302 $sk = $this->getSkin();
3305 $relevantTitle = $sk->getRelevantTitle();
3308 list( $canonicalSpecialPageName, ) =
3309 $services->getSpecialPageFactory()->
3310 resolveAlias(
$title->getDBkey() );
3311 } elseif ( $this->canUseWikiPage() ) {
3312 $wikiPage = $this->getWikiPage();
3313 $curRevisionId = $wikiPage->getLatest();
3314 $articleId = $wikiPage->getId();
3320 $separatorTransTable =
$lang->separatorTransformTable();
3321 $separatorTransTable = $separatorTransTable ?: [];
3322 $compactSeparatorTransTable = [
3323 implode(
"\t", array_keys( $separatorTransTable ) ),
3324 implode(
"\t", $separatorTransTable ),
3326 $digitTransTable =
$lang->digitTransformTable();
3327 $digitTransTable = $digitTransTable ?: [];
3328 $compactDigitTransTable = [
3329 implode(
"\t", array_keys( $digitTransTable ) ),
3330 implode(
"\t", $digitTransTable ),
3333 $user = $this->getUser();
3338 'wgBreakFrames' => $this->getFrameOptions() ==
'DENY',
3341 'wgSeparatorTransformTable' => $compactSeparatorTransTable,
3342 'wgDigitTransformTable' => $compactDigitTransTable,
3343 'wgDefaultDateFormat' =>
$lang->getDefaultDateFormat(),
3344 'wgMonthNames' =>
$lang->getMonthNamesArray(),
3347 'wgRequestId' => WebRequest::getRequestId(),
3350 'wgCSPNonce' => $this->CSP->getNonce(),
3355 'wgCanonicalNamespace' => $canonicalNamespace,
3356 'wgCanonicalSpecialPageName' => $canonicalSpecialPageName,
3357 'wgNamespaceNumber' =>
$title->getNamespace(),
3358 'wgPageName' =>
$title->getPrefixedDBkey(),
3359 'wgTitle' =>
$title->getText(),
3360 'wgCurRevisionId' => $curRevisionId,
3361 'wgRevisionId' => (int)$this->getRevisionId(),
3362 'wgArticleId' => $articleId,
3363 'wgIsArticle' => $this->isArticle(),
3364 'wgIsRedirect' =>
$title->isRedirect(),
3365 'wgAction' => Action::getActionName( $this->
getContext() ),
3366 'wgUserName' => $user->isAnon() ? null : $user->getName(),
3367 'wgUserGroups' => $services->getUserGroupManager()->getUserEffectiveGroups( $user ),
3368 'wgCategories' => $this->getCategories(),
3369 'wgPageContentLanguage' =>
$lang->getCode(),
3370 'wgPageContentModel' =>
$title->getContentModel(),
3371 'wgRelevantPageName' => $relevantTitle->getPrefixedDBkey(),
3372 'wgRelevantArticleId' => $relevantTitle->getArticleID(),
3374 if ( $user->isRegistered() ) {
3375 $vars[
'wgUserId'] = $user->getId();
3376 $vars[
'wgUserEditCount'] = $user->getEditCount();
3377 $userReg = $user->getRegistration();
3378 $vars[
'wgUserRegistration'] = $userReg ? (int)
wfTimestamp( TS_UNIX, $userReg ) * 1000 :
null;
3382 $userNewMsgRevId = $this->getLastSeenUserTalkRevId();
3385 if ( $userNewMsgRevId ) {
3386 $vars[
'wgUserNewMsgRevisionId'] = $userNewMsgRevId;
3389 $languageConverter = $services->getLanguageConverterFactory()
3390 ->getLanguageConverter( $services->getContentLanguage() );
3391 if ( $languageConverter->hasVariants() ) {
3392 $vars[
'wgUserVariant'] = $languageConverter->getPreferredVariant();
3395 $vars[
'wgIsProbablyEditable'] = $this->
getAuthority()->probablyCan(
'edit',
$title );
3396 $vars[
'wgRelevantPageIsProbablyEditable'] = $relevantTitle &&
3397 $this->
getAuthority()->probablyCan(
'edit', $relevantTitle );
3398 foreach (
$title->getRestrictionTypes() as
$type ) {
3401 $vars[
'wgRestriction' . ucfirst(
$type )] =
$title->getRestrictions(
$type );
3403 if (
$title->isMainPage() ) {
3404 $vars[
'wgIsMainPage'] =
true;
3407 $relevantUser = $sk->getRelevantUser();
3408 if ( $relevantUser ) {
3409 $vars[
'wgRelevantUserName'] = $relevantUser->getName();
3413 $titleFormatter = $services->getTitleFormatter();
3415 if ( $this->mRedirectedFrom ) {
3417 $vars[
'wgRedirectedFrom'] = $titleFormatter->getPrefixedDBkey( $this->mRedirectedFrom );
3424 $this->getHookRunner()->onMakeGlobalVariablesScript( $vars, $this );
3427 return array_merge( $vars, $this->getJsConfigVars() );
3436 $services = MediaWikiServices::getInstance();
3437 $user = $this->getUser();
3438 $userHasNewMessages = $services
3439 ->getTalkPageNotificationManager()
3440 ->userHasNewMessages( $user );
3441 if ( !$userHasNewMessages ) {
3445 $timestamp = $services
3446 ->getTalkPageNotificationManager()
3447 ->getLatestSeenMessageTimestamp( $user );
3449 if ( !$timestamp ) {
3453 $revRecord = $services->getRevisionLookup()->getRevisionByTimestamp(
3454 $user->getTalkPage(),
3458 if ( !$revRecord ) {
3462 return $revRecord->getId();
3475 $request = $this->getRequest();
3477 $request->getRawVal(
'action' ) !==
'submit' ||
3478 !$request->wasPosted()
3483 $user = $this->getUser();
3485 if ( !$user->isRegistered() ) {
3489 if ( !$user->matchEditToken( $request->getVal(
'wpEditToken' ) ) ) {
3506 $config = $this->getConfig();
3508 $canonicalUrl = $this->mCanonicalUrl;
3510 $tags[
'meta-generator'] = Html::element(
'meta', [
3511 'name' =>
'generator',
3515 if ( $config->get(
'ReferrerPolicy' ) !==
false ) {
3518 foreach ( array_reverse( (array)$config->get(
'ReferrerPolicy' ) ) as $i => $policy ) {
3519 $tags[
"meta-referrer-$i"] = Html::element(
'meta', [
3520 'name' =>
'referrer',
3521 'content' => $policy,
3526 $p =
"{$this->mIndexPolicy},{$this->mFollowPolicy}";
3527 if ( $p !==
'index,follow' ) {
3530 $tags[
'meta-robots'] = Html::element(
'meta', [
3536 # Browser based phonenumber detection
3537 if ( $config->get(
'BrowserFormatDetection' ) !==
false ) {
3538 $tags[
'meta-format-detection'] = Html::element(
'meta', [
3539 'name' =>
'format-detection',
3540 'content' => $config->get(
'BrowserFormatDetection' ),
3544 foreach ( $this->mMetatags as $tag ) {
3545 if ( strncasecmp( $tag[0],
'http:', 5 ) === 0 ) {
3547 $tag[0] = substr( $tag[0], 5 );
3548 } elseif ( strncasecmp( $tag[0],
'og:', 3 ) === 0 ) {
3553 $tagName =
"meta-{$tag[0]}";
3554 if ( isset( $tags[$tagName] ) ) {
3555 $tagName .= $tag[1];
3557 $tags[$tagName] = Html::element(
'meta',
3560 'content' => $tag[1]
3565 foreach ( $this->mLinktags as $tag ) {
3566 $tags[] = Html::element(
'link', $tag );
3569 # Universal edit button
3570 if ( $config->get(
'UniversalEditButton' ) && $this->isArticleRelated() ) {
3573 $msg = $this->msg(
'edit' )->text();
3574 $tags[
'universal-edit-button'] = Html::element(
'link', [
3575 'rel' =>
'alternate',
3576 'type' =>
'application/x-wiki',
3578 'href' => $this->
getTitle()->getEditURL(),
3581 $tags[
'alternative-edit'] = Html::element(
'link', [
3584 'href' => $this->
getTitle()->getEditURL(),
3589 # Generally the order of the favicon and apple-touch-icon links
3590 # should not matter, but Konqueror (3.5.9 at least) incorrectly
3591 # uses whichever one appears later in the HTML source. Make sure
3592 # apple-touch-icon is specified first to avoid this.
3593 if ( $config->get(
'AppleTouchIcon' ) !==
false ) {
3594 $tags[
'apple-touch-icon'] = Html::element(
'link', [
3595 'rel' =>
'apple-touch-icon',
3596 'href' => $config->get(
'AppleTouchIcon' )
3600 if ( $config->get(
'Favicon' ) !==
false ) {
3601 $tags[
'favicon'] = Html::element(
'link', [
3602 'rel' =>
'shortcut icon',
3603 'href' => $config->get(
'Favicon' )
3607 # OpenSearch description link
3608 $tags[
'opensearch'] = Html::element(
'link', [
3610 'type' =>
'application/opensearchdescription+xml',
3611 'href' =>
wfScript(
'opensearch_desc' ),
3612 'title' => $this->msg(
'opensearch-desc' )->inContentLanguage()->text(),
3615 # Real Simple Discovery link, provides auto-discovery information
3616 # for the MediaWiki API (and potentially additional custom API
3617 # support such as WordPress or Twitter-compatible APIs for a
3618 # blogging extension, etc)
3619 $tags[
'rsd'] = Html::element(
'link', [
3621 'type' =>
'application/rsd+xml',
3627 [
'action' =>
'rsd' ] ),
3633 $services = MediaWikiServices::getInstance();
3634 $languageConverterFactory = $services->getLanguageConverterFactory();
3635 $disableLangConversion = $languageConverterFactory->isConversionDisabled();
3636 if ( !$disableLangConversion ) {
3638 $languageConverter = $languageConverterFactory->getLanguageConverter(
$lang );
3639 if ( $languageConverter->hasVariants() ) {
3640 $variants = $languageConverter->getVariants();
3641 foreach ( $variants as $variant ) {
3642 $tags[
"variant-$variant"] = Html::element(
'link', [
3643 'rel' =>
'alternate',
3644 'hreflang' => LanguageCode::bcp47( $variant ),
3645 'href' => $this->
getTitle()->getLocalURL(
3646 [
'variant' => $variant ] )
3650 # x-default link per https:
3651 $tags[
"variant-x-default"] = Html::element(
'link', [
3652 'rel' =>
'alternate',
3653 'hreflang' =>
'x-default',
3654 'href' => $this->
getTitle()->getLocalURL() ] );
3659 if ( $this->copyrightUrl !==
null ) {
3660 $copyright = $this->copyrightUrl;
3663 if ( $config->get(
'RightsPage' ) ) {
3664 $copy = Title::newFromText( $config->get(
'RightsPage' ) );
3667 $copyright = $copy->getLocalURL();
3671 if ( !$copyright && $config->get(
'RightsUrl' ) ) {
3672 $copyright = $config->get(
'RightsUrl' );
3677 $tags[
'copyright'] = Html::element(
'link', [
3679 'href' => $copyright ]
3684 if ( $config->get(
'Feed' ) ) {
3687 foreach ( $this->getSyndicationLinks() as $format => $link ) {
3688 # Use the page name for the title. In principle, this could
3689 # lead to issues with having the same name for different feeds
3690 # corresponding to the same page, but we can't avoid that at
3693 $feedLinks[] = $this->feedLink(
3696 # Used messages:
'page-rss-feed' and
'page-atom-feed' (
for an easier grep)
3698 "page-{$format}-feed", $this->
getTitle()->getPrefixedText()
3703 # Recent changes feed should appear on every page (except recentchanges,
3704 # that would be redundant). Put it after the per-page feed to avoid
3705 # changing existing behavior. It's still available, probably via a
3706 # menu in your browser. Some sites might have a different feed they'd
3707 # like to promote instead of the RC feed (maybe like a "Recent New Articles"
3708 # or "Breaking news" one). For this, we see if $wgOverrideSiteFeed is defined.
3709 # If so, use it instead.
3710 $sitename = $config->get(
'Sitename' );
3711 $overrideSiteFeed = $config->get(
'OverrideSiteFeed' );
3712 if ( $overrideSiteFeed ) {
3713 foreach ( $overrideSiteFeed as
$type => $feedUrl ) {
3715 $feedLinks[] = $this->feedLink(
3718 $this->msg(
"site-{$type}-feed", $sitename )->text()
3721 } elseif ( !$this->
getTitle()->isSpecial(
'Recentchanges' ) ) {
3723 foreach ( $this->getAdvertisedFeedTypes() as $format ) {
3724 $feedLinks[] = $this->feedLink(
3726 $rctitle->getLocalURL( [
'feed' => $format ] ),
3727 # For grep:
'site-rss-feed',
'site-atom-feed'
3728 $this->msg(
"site-{$format}-feed", $sitename )->text()
3733 # Allow extensions to change the list pf feeds. This hook is primarily for changing,
3734 # manipulating or removing existing feed tags. If you want to add new feeds, you should
3735 # use OutputPage::addFeedLink() instead.
3736 $this->getHookRunner()->onAfterBuildFeedLinks( $feedLinks );
3738 $tags += $feedLinks;
3742 if ( $config->get(
'EnableCanonicalServerLink' ) ) {
3743 if ( $canonicalUrl !==
false ) {
3745 } elseif ( $this->isArticleRelated() ) {
3753 $action = Action::getActionName( $this->
getContext() );
3754 if ( in_array( $action, [
'history',
'info' ] ) ) {
3755 $query =
"action={$action}";
3759 $canonicalUrl = $this->
getTitle()->getCanonicalURL( $query );
3761 $reqUrl = $this->getRequest()->getRequestURL();
3765 if ( $canonicalUrl !==
false ) {
3766 $tags[] = Html::element(
'link', [
3767 'rel' =>
'canonical',
3768 'href' => $canonicalUrl
3777 $this->getHookRunner()->onOutputPageAfterGetHeadLinksArray( $tags, $this );
3791 return Html::element(
'link', [
3792 'rel' =>
'alternate',
3793 'type' =>
"application/$type+xml",
3808 public function addStyle( $style, $media =
'', $condition =
'', $dir =
'' ) {
3811 $options[
'media'] = $media;
3814 $options[
'condition'] = $condition;
3817 $options[
'dir'] = $dir;
3819 $this->styles[$style] = $options;
3830 if ( $flip ===
'flip' && $this->getLanguage()->isRTL() ) {
3831 # If wanted, and the interface is right-to-left, flip the CSS
3832 $style_css = CSSJanus::transform( $style_css,
true,
false );
3834 $this->mInlineStyles .= Html::inlineStyle( $style_css );
3862 $chunks[] = implode(
'', $this->buildCssLinksArray() ) . $this->mInlineStyles;
3866 $separateReq = [
'site.styles',
'user.styles' ];
3867 foreach ( $this->rlExemptStyleModules as $group => $moduleNames ) {
3868 if ( $moduleNames ) {
3869 $append[] = $this->makeResourceLoaderLink(
3870 array_diff( $moduleNames, $separateReq ),
3871 ResourceLoaderModule::TYPE_STYLES
3874 foreach ( array_intersect( $moduleNames, $separateReq ) as $name ) {
3877 $append[] = $this->makeResourceLoaderLink( $name,
3878 ResourceLoaderModule::TYPE_STYLES
3884 $chunks[] = Html::element(
3886 [
'name' =>
'ResourceLoaderDynamicStyles',
'content' =>
'' ]
3888 $chunks = array_merge( $chunks, $append );
3891 return self::combineWrappedStrings( $chunks );
3900 foreach ( $this->styles as
$file => $options ) {
3901 $link = $this->styleLink(
$file, $options );
3903 $links[
$file] = $link;
3917 if ( isset( $options[
'dir'] ) && $this->getLanguage()->getDir() != $options[
'dir'] ) {
3921 if ( isset( $options[
'media'] ) ) {
3922 $media = self::transformCssMedia( $options[
'media'] );
3923 if ( $media ===
null ) {
3930 if ( substr( $style, 0, 1 ) ==
'/' ||
3931 substr( $style, 0, 5 ) ==
'http:' ||
3932 substr( $style, 0, 6 ) ==
'https:' ) {
3935 $config = $this->getConfig();
3937 $url = self::transformResourcePath(
3939 $config->get(
'StylePath' ) .
'/' . $style
3943 $link = Html::linkedStyle( $url, $media );
3945 if ( isset( $options[
'condition'] ) ) {
3946 $condition = htmlspecialchars( $options[
'condition'] );
3947 $link =
"<!--[if $condition]>$link<![endif]-->";
3977 $remotePathPrefix = $config->
get(
'ResourceBasePath' );
3978 if ( $remotePathPrefix ===
'' ) {
3983 $remotePath = $remotePathPrefix;
3985 if ( strpos(
$path, $remotePath ) !== 0 || substr(
$path, 0, 2 ) ===
'//' ) {
3994 $uploadPath = $config->
get(
'UploadPath' );
3995 if ( strpos(
$path, $uploadPath ) === 0 ) {
3996 $localDir = $config->
get(
'UploadDirectory' );
3997 $remotePathPrefix = $remotePath = $uploadPath;
4000 $path = RelPath::getRelativePath(
$path, $remotePath );
4001 return self::transformFilePath( $remotePathPrefix, $localDir,
$path );
4017 $localFile =
"$localPath/$file";
4018 $url =
"$remotePathPrefix/$file";
4019 if ( file_exists( $localFile ) ) {
4020 $hash = md5_file( $localFile );
4021 if ( $hash ===
false ) {
4022 wfLogWarning( __METHOD__ .
": Failed to hash $localFile" );
4025 $url .=
'?' . substr( $hash, 0, 5 );
4041 $screenMediaQueryRegex =
'/^(?:only\s+)?screen\b/i';
4045 'printable' =>
'print',
4046 'handheld' =>
'handheld',
4048 foreach ( $switches as $switch => $targetMedia ) {
4050 if ( $media == $targetMedia ) {
4052 } elseif ( preg_match( $screenMediaQueryRegex, $media ) === 1 ) {
4066 if ( $targetMedia ==
'print' || $media ==
'screen' ) {
4085 $name = array_shift(
$args );
4086 $this->addWikiMsgArray( $name,
$args );
4098 $this->addHTML( $this->msg( $name,
$args )->parseAsBlock() );
4129 foreach ( $msgSpecs as $n => $spec ) {
4130 if ( is_array( $spec ) ) {
4132 $name = array_shift(
$args );
4137 $s = str_replace(
'$' . ( $n + 1 ), $this->msg( $name,
$args )->plain(),
$s );
4139 $this->addWikiTextAsInterface(
$s );
4148 return $this->mEnableTOC;
4158 public static function setupOOUI( $skinName =
'default', $dir =
'ltr' ) {
4159 $themes = ResourceLoaderOOUIModule::getSkinThemeMap();
4160 $theme = $themes[$skinName] ?? $themes[
'default'];
4162 $themeClass =
"OOUI\\{$theme}Theme";
4163 OOUI\Theme::setSingleton(
new $themeClass() );
4164 OOUI\Element::setDefaultDir( $dir );
4175 strtolower( $this->getSkin()->getSkinName() ),
4176 $this->getLanguage()->getDir()
4178 $this->addModuleStyles( [
4179 'oojs-ui-core.styles',
4180 'oojs-ui.styles.indicators',
4181 'mediawiki.widgets.styles',
4182 'oojs-ui-core.icons',
4197 return $this->CSP->getNonce();
4223 $this->getHookRunner()->onSkinAfterBottomScripts( $skin, $extraHtml );
4226 MWDebug::getDebugHTML( $skin ),
4227 $this->getBottomScripts( $extraHtml ),
4229 MWDebug::getHTMLDebugLog()
4230 . Html::closeElement(
'body' )
4231 . Html::closeElement(
'html' )
4234 return WrappedStringList::join(
"\n", $tail );
const MW_VERSION
The running version of MediaWiki.
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,...
wfParseUrl( $url)
parse_url() work-alike, but non-broken.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
wfReportTime( $nonce=null)
Returns a script tag that stores the amount of time it took MediaWiki to handle the request in millis...
wfSetVar(&$dest, $source, $force=false)
Sets dest to source and returns the original value of dest If source is NULL, it just returns the val...
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
wfCgiToArray( $query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
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.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
wfResetOutputBuffers( $resetGzipEncoding=true)
Clear away any user-level output buffers, discarding contents.
if(ini_get('mbstring.func_overload')) if(!defined('MW_ENTRY_POINT'))
Pre-config setup: Before loading LocalSettings.php.
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
setContext(IContextSource $context)
A mutable version of ResourceLoaderContext.
WebRequest clone which takes values from a provided array.
Implements some public methods and some protected utility functions which are required by multiple ch...
exists()
Returns true if file exists in the repository.
Marks HTML that shouldn't be escaped.
Content for JavaScript pages.
The Message class deals with fetching and processing of interface message into a variety of formats.
This is one of the Core classes and should be read at least once by any new developers.
isArticle()
Return whether the content displayed page is related to the source of the corresponding article on th...
addLinkHeader( $header)
Add an HTTP Link: header.
setFileVersion( $file)
Set the displayed file version.
$mScripts
Used for JavaScript (predates ResourceLoader)
getDisplayTitle()
Returns page display title.
getCdnCacheEpoch( $reqTime, $maxAge)
disable()
Disable output completely, i.e.
addLink(array $linkarr)
Add a new <link> tag to the page header.
addWikiMsg(... $args)
Add a wikitext-formatted message to the output.
ResourceLoader $mResourceLoader
ContentSecurityPolicy $CSP
static array $cacheVaryCookies
A cache of the names of the cookies that will influence the cache.
getCanonicalUrl()
Returns the URL to be used for the <link rel=canonical>> if one is set.
getPageTitle()
Return the "page title", i.e.
isArticleRelated()
Return whether this page is related an article on the wiki.
addCategoryLinksToLBAndGetResult(array $categories)
addWikiTextTitleInternal( $text, PageReference $title, $linestart, $interface, $wrapperClass=null)
Add wikitext with a custom Title object.
getLanguageLinks()
Get the list of language links.
addScriptFile( $file, $unused=null)
Add a JavaScript file to be loaded as <script> on this page.
allowClickjacking()
Turn off frame-breaking.
filterModules(array $modules, $position=null, $type=ResourceLoaderModule::TYPE_COMBINED)
Filter an array of modules to remove insufficiently trustworthy members, and modules which are no lon...
wrapWikiTextAsInterface( $wrapperClass, $text)
Convert wikitext in the user interface language to HTML and add it to the buffer with a <div class="$...
getSyndicationLinks()
Return URLs for each supported syndication format for this page.
setArticleFlag( $newVal)
Set whether the displayed content is related to the source of the corresponding article on the wiki S...
addMeta( $name, $val)
Add a new "<meta>" tag To add an http-equiv meta tag, precede the name with "http:".
addBacklinkSubtitle(PageReference $title, $query=[])
Add a subtitle containing a backlink to a page.
$mFeedLinks
Handles the Atom / RSS links.
setCopyrightUrl( $url)
Set the copyright URL to send with the output.
setRobotPolicy( $policy)
Set the robot policy for the page: http://www.robotstxt.org/meta.html
__construct(IContextSource $context)
Constructor for OutputPage.
setIndexPolicy( $policy)
Set the index policy for the page, but leave the follow policy un- touched.
tailElement( $skin)
The final bits that go to the bottom of a page HTML document including the closing tags.
getTemplateIds()
Get the templates used on this page.
formatPermissionStatus(PermissionStatus $status, string $action=null)
Format permission $status obtained from Authority for display.
static buildBacklinkSubtitle(PageReference $page, $query=[])
Build message object for a subtitle containing a backlink to a page.
setDisplayTitle( $html)
Same as page title but only contains name of the page, not any other text.
setPageTitle( $name)
"Page title" means the contents of <h1>.
output( $return=false)
Finally, all the text has been munged and accumulated into the object, let's actually output it:
PageReference $mRedirectedFrom
If the current page was reached through a redirect, $mRedirectedFrom contains the title of the redire...
redirect( $url, $responsecode='302')
Redirect to $url rather than displaying the normal page.
getRedirect()
Get the URL to redirect to, or an empty string if not redirect URL set.
setLastModified( $timestamp)
Override the last modified timestamp.
considerCacheSettingsFinal()
Set the expectation that cache control will not change after this point.
setLanguageLinks(array $newLinkArray)
Reset the language links and add new language links.
addFeedLink( $format, $href)
Add a feed link to the page header.
setCategoryLinks(array $categories)
Reset the category links (but not the category list) and add $categories.
getAdvertisedFeedTypes()
Return effective list of advertised feed types.
getFileVersion()
Get the displayed file version.
setSyndicated( $show=true)
Add or remove feed links in the page header This is mainly kept for backward compatibility,...
bool $mHideNewSectionLink
bool $mIsArticle
Is the displayed content related to the source of the corresponding wiki article.
adaptCdnTTL( $mtime, $minTTL=0, $maxTTL=0)
Get TTL in [$minTTL,$maxTTL] and pass it to lowerCdnMaxage()
showsCopyright()
Return whether the standard copyright should be shown for the current page.
sendCacheControl()
Send cache control HTTP headers.
setTarget( $target)
Sets ResourceLoader target for load.php links.
string[][] $mMetatags
Should be private.
addCategoryLinks(array $categories)
Add an array of categories, with names in the keys.
showLagWarning( $lag)
Show a warning about replica DB lag.
clearSubtitle()
Clear the subtitles.
wrapWikiMsg( $wrap,... $msgSpecs)
This function takes a number of message/argument specifications, wraps them in some overall structure...
showFatalError( $message)
Output an error page.
setCdnMaxage( $maxage)
Set the value of the "s-maxage" part of the "Cache-control" HTTP header.
getJsConfigVars()
Get the javascript config vars to include on this page.
getHTML()
Get the body HTML.
getFeaturePolicyReportOnly()
parseAsContent( $text, $linestart=true)
Parse wikitext in the page content language and return the HTML.
setCopyright( $hasCopyright)
Set whether the standard copyright should be shown for the current page.
array $mAllowedModules
What level of 'untrustworthiness' is allowed in CSS/JS modules loaded on this page?
addParserOutput(ParserOutput $parserOutput, $poOptions=[])
Add everything from a ParserOutput object.
getJSVars()
Get an array containing the variables to be set in mw.config in JavaScript.
bool $mPreventClickjacking
Controls if anti-clickjacking / frame-breaking headers will be sent.
haveCacheVaryCookies()
Check if the request has a cache-varying cookie header If it does, it's very important that we don't ...
isTOCEnabled()
Whether the output has a table of contents.
versionRequired( $version)
Display an error page indicating that a given version of MediaWiki is required to use it.
addContentOverride( $target, Content $content)
Force the given Content object for the given page, for things like page preview.
reduceAllowedModules( $type, $level)
Limit the highest level of CSS/JS untrustworthiness allowed.
addInlineStyle( $style_css, $flip='noflip')
Adds inline CSS styles Internal use only.
getRevisionTimestamp()
Get the timestamp of displayed revision.
preventClickjacking( $enable=true)
Set a flag which will cause an X-Frame-Options header appropriate for edit pages to be sent.
addWikiTextAsInterface( $text, $linestart=true, PageReference $title=null)
Convert wikitext in the user interface language to HTML and add it to the buffer.
bool $mPrintable
We have to set isPrintable().
setFollowPolicy( $policy)
Set the follow policy for the page, but leave the index policy un- touched.
getHeadItemsArray()
Get an array of head items.
isPrintable()
Return whether the page is "printable".
getBottomScripts( $extraHtml='')
JS stuff to put at the bottom of the <body>.
getModules( $filter=false, $position=null, $param='mModules', $type=ResourceLoaderModule::TYPE_COMBINED)
Get the list of modules to include on this page.
getFeedAppendQuery()
Will currently always return null.
bool $cacheIsFinal
See OutputPage::couldBePublicCached.
addModuleStyles( $modules)
Load the styles of one or more style-only ResourceLoader modules on this page.
setHTMLTitle( $name)
"HTML title" means the contents of "<title>".
loadSkinModules( $sk)
Transfer styles and JavaScript modules from skin.
array $mAdditionalBodyClasses
Additional <body> classes; there are also <body> classes from other sources.
returnToMain( $unused=null, $returnto=null, $returntoquery=null)
Add a "return to" link pointing to a specified title, or the title indicated in the request,...
array $mHeadItems
Array of elements in "<head>".
isSyndicated()
Should we output feed links for this page?
$mLinkHeader
Link: header contents.
styleLink( $style, array $options)
Generate <link> tags for stylesheets.
addHtmlClasses( $classes)
Add a class to the <html> element.
parseAsInterface( $text, $linestart=true)
Parse wikitext in the user interface language and return the HTML.
setTitle(PageReference $t)
Set the Title object to use.
addParserOutputMetadata(ParserOutput $parserOutput)
Add all metadata associated with a ParserOutput object, but without the actual HTML.
bool $mEnableClientCache
Gwicke work on squid caching? Roughly from 2003.
static transformResourcePath(Config $config, $path)
Transform path to web-accessible static resource.
addElement( $element, array $attribs=[], $contents='')
Shortcut for adding an Html::element via addHTML.
makeResourceLoaderLink( $modules, $only, array $extraQuery=[])
Explicily load or embed modules on a page.
showPermissionsErrorPage(array $errors, $action=null)
Output a standard permission error page.
addSubtitle( $str)
Add $str to the subtitle.
static setupOOUI( $skinName='default', $dir='ltr')
Helper function to setup the PHP implementation of OOUI to use in this request.
setRevisionId( $revid)
Set the revision ID which will be seen by the wiki text parser for things such as embedded {{REVISION...
addParserOutputContent(ParserOutput $parserOutput, $poOptions=[])
Add the HTML and enhancements for it (like ResourceLoader modules) associated with a ParserOutput obj...
getPreventClickjacking()
Get the prevent-clickjacking flag.
enableOOUI()
Add ResourceLoader module styles for OOUI and set up the PHP implementation of it for use with MediaW...
getIndexPolicy()
Get the current index policy for the page as a string.
getCategories( $type='all')
Get the list of category names this page belongs to.
getIndicators()
Get the indicators associated with this page.
$mProperties
Additional key => value data.
parseInlineAsInterface( $text, $linestart=true)
Parse wikitext in the user interface language, strip paragraph wrapper, and return the HTML.
addWikiMsgArray( $name, $args)
Add a wikitext-formatted message to the output.
array $contentOverrides
Map Title to Content.
addBodyClasses( $classes)
Add a class to the <body> element.
addParserOutputText(ParserOutput $parserOutput, $poOptions=[])
Add the HTML associated with a ParserOutput object, without any metadata.
warnModuleTargetFilter( $moduleName)
string $mBodytext
Contains all of the "<body>" content.
addScript( $script)
Add raw HTML to the list of scripts (including <script> tag, etc.) Internal use only.
clearHTML()
Clear the body HTML.
array $mSubtitle
Contains the page subtitle.
addVaryHeader( $header, array $option=null)
Add an HTTP header that will influence on the cache.
addStyle( $style, $media='', $condition='', $dir='')
Add a local or specified stylesheet, with the given media options.
getLinkHeader()
Return a Link: header.
setPrintable()
Set the page as printable, i.e.
getResourceLoader()
Get a ResourceLoader object associated with this OutputPage.
feedLink( $type, $url, $text)
Generate a "<link rel/>" for a feed.
bool $mNoGallery
Comes from the parser.
getModuleStyles( $filter=false, $position=null)
Get the list of style-only modules to load on this page.
enableClientCache( $state)
Use enableClientCache(false) to force it to send nocache headers.
userCanPreview()
To make it harder for someone to slip a user a fake JavaScript or CSS preview, a random token is asso...
array $limitReportJSData
Profiling data.
parseInternal( $text, $title, $linestart, $interface)
Parse wikitext and return the HTML (internal implementation helper)
getFileSearchOptions()
Get the files used on this page.
array $mAdditionalHtmlClasses
Additional <html> classes; This should be rarely modified; prefer mAdditionalBodyClasses.
isRevisionCurrent()
Whether the revision displayed is the latest revision of the page.
addHTML( $text)
Append $text to the body HTML.
formatPermissionsErrorMessage(array $errors, $action=null)
Format a list of error messages.
string $mRevisionTimestamp
string null $copyrightUrl
The URL to send in a <link> element with rel=license.
getCSP()
Get the ContentSecurityPolicy object.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
getHTMLTitle()
Return the "HTML title", i.e.
disallowUserJs()
Do not allow scripts which can be modified by wiki users to load on this page; only allow scripts bun...
string $mHTMLtitle
Stores contents of "<title>" tag.
addJsConfigVars( $keys, $value=null)
Add one or more variables to be set in mw.config in JavaScript.
static transformCssMedia( $media)
Transform "media" attribute based on request parameters.
setCanonicalUrl( $url)
Set the URL to be used for the <link rel=canonical>>.
ParserOptions $mParserOptions
lazy initialised, use parserOptions()
addTemplate(&$template)
Add the output of a QuickTemplate to the output buffer.
getRlClient()
Call this to freeze the module queue and JS config and create a formatter.
static transformFilePath( $remotePathPrefix, $localPath, $file)
Utility method for transformResourceFilePath().
callable[] $contentOverrideCallbacks
int $mCdnMaxageLimit
Upper limit on mCdnMaxage.
ResourceLoaderClientHtml $rlClient
setArticleBodyOnly( $only)
Set whether the output should only contain the body of the article, without any skin,...
string[][] $mCategoryLinks
addInlineScript( $script)
Add a self-contained script tag with the given contents Internal use only.
addAcceptLanguage()
T23672: Add Accept-Language to Vary header if there's no 'variant' parameter in GET.
setStatusCode( $statusCode)
Set the HTTP status code to send with the output.
parserOptions()
Get/set the ParserOptions object to use for wikitext parsing.
getCacheVaryCookies()
Get the list of cookie names that will influence the cache.
getLastSeenUserTalkRevId()
Get the revision ID for the last user talk page revision viewed by the talk page owner.
ResourceLoaderContext $rlClientContext
showErrorPage( $title, $msg, $params=[])
Output a standard error page.
getLinkTags()
Returns the current <link> tags.
getArticleBodyOnly()
Return whether the output will contain only the body of the article.
setProperty( $name, $value)
Set an additional output property.
setRevisionTimestamp( $timestamp)
Set the timestamp of the revision which will be displayed.
checkLastModified( $timestamp)
checkLastModified tells the client to use the client-cached page if possible.
getVaryHeader()
Return a Vary: header on which to vary caches.
string $mLastModified
Used for sending cache control.
showNewSectionLink()
Show an "add new section" link?
bool $mDoNothing
Whether output is disabled.
string $mPageTitle
The contents of.
string $mPageLinkTitle
Used by skin template.
addHeadItem( $name, $value)
Add or replace a head item to the output.
getRevisionId()
Get the displayed revision ID.
setIndicators(array $indicators)
Add an array of indicators, with their identifiers as array keys and HTML contents as values.
bool $mEnableTOC
Whether parser output contains a table of contents.
lowerCdnMaxage( $maxage)
Set the value of the "s-maxage" part of the "Cache-control" HTTP header to $maxage if that is lower t...
getRobotPolicy()
Get the current robot policy for the page as a string in the form <index policy>,<follow policy>.
forceHideNewSectionLink()
Forcibly hide the new section link?
bool $mHasCopyright
Is the content subject to copyright.
string null $mTarget
ResourceLoader target for load.php links.
int $mCdnMaxage
Cache stuff.
setRedirectedFrom(PageReference $t)
Set $mRedirectedFrom, the page which redirected us to the current page.
getAllowedModules( $type)
Show what level of JavaScript / CSS untrustworthiness is allowed on this page.
string $displayTitle
The displayed title of the page.
prependHTML( $text)
Prepend $text to the body HTML.
addLanguageLinks(array $newLinkArray)
Add new language links.
array $mLanguageLinks
Array of Interwiki Prefixed (non DB key) Titles (e.g.
setArticleRelated( $newVal)
Set whether this page is related an article on the wiki Setting false will cause the change of "artic...
string $mInlineStyles
Inline CSS styles.
getFollowPolicy()
Get the current follow policy for the page as a string.
addModules( $modules)
Load one or more ResourceLoader modules on this page.
buildExemptModules()
Build exempt modules and legacy non-ResourceLoader styles.
getProperty( $name)
Get an additional output property.
headElement(Skin $sk, $includeStyle=true)
prepareErrorPage( $pageTitle, $htmlTitle=false)
Prepare this object to display an error page; disable caching and indexing, clear the current text an...
addContentOverrideCallback(callable $callback)
Add a callback for mapping from a Title to a Content object, for things like page preview.
int null $mRevisionId
To include the variable {{REVISIONID}}.
setFeedAppendQuery( $val)
Add default feeds to the page header This is mainly kept for backward compatibility,...
addReturnTo( $title, array $query=[], $text=null, $options=[])
Add a "return to" link pointing to a specified title.
getMetaTags()
Returns the current <meta> tags.
getOriginTrials()
Get the Origin-Trial header values.
string bool $mCanonicalUrl
bool $mArticleBodyOnly
Flag if output should only contain the body of the article.
setSubtitle( $str)
Replace the subtitle with $str.
couldBePublicCached()
Whether the output might become publicly cached.
array $rlExemptStyleModules
getCategoryLinks()
Get the list of category links, in a 2-D array with the following format: $arr[$type][] = $link,...
getFrameOptions()
Get the X-Frame-Options header value (without the name part), or false if there isn't one.
addHeadItems( $values)
Add one or more head items to the output.
static combineWrappedStrings(array $chunks)
Combine WrappedString chunks and filter out empty ones.
bool $mIsArticleRelated
Stores "article flag" toggle.
getUnprefixedDisplayTitle()
Returns page display title without namespace prefix if possible.
getCSPNonce()
Get (and set if not yet set) the CSP nonce.
array $mVaryHeader
Headers that cause the cache to vary.
hasHeadItem( $name)
Check if the header item $name is already set.
array $styles
An array of stylesheet filenames (relative from skins path), with options for CSS media,...
isDisabled()
Return whether the output will be completely disabled.
addWikiTextAsContent( $text, $linestart=true, PageReference $title=null)
Convert wikitext in the page content language to HTML and add it to the buffer.
Set options of the Parser.
preventClickjacking( $flag=null)
Get or set the prevent-clickjacking flag.
getExtraCSPStyleSrcs()
Get extra Content-Security-Policy 'style-src' directives.
getExtraCSPScriptSrcs()
Get extra Content-Security-Policy 'script-src' directives.
getText( $options=[])
Get the output HTML.
getExtraCSPDefaultSrcs()
Get extra Content-Security-Policy 'default-src' directives.
static stripOuterParagraph( $html)
Strip outer.
Load and configure a ResourceLoader client on an HTML page.
static makeLoad(ResourceLoaderContext $mainContext, array $modules, $only, array $extraQuery=[], $nonce=null)
Explicitly load or embed modules on a page.
setConfig(array $vars)
Set mw.config variables.
Context object that contains information about the state of a specific ResourceLoader web request.
Abstraction for ResourceLoader modules, with name registration and maxage functionality.
getOrigin()
Get this module's origin.
ResourceLoader is a loading system for JavaScript and CSS resources.
static makeInlineScript( $script, $nonce=null)
Make an HTML script that runs given JS code after startup and base modules.
static inDebugMode()
Determine whether debug mode is on.
static makeConfigSetScript(array $configuration)
Return JS code which will set the MediaWiki configuration array to the given value.
static makeLoaderQuery(array $modules, $lang, $skin, $user=null, $version=null, $debug=ResourceLoaderContext::DEBUG_OFF, $only=null, $printable=false, $handheld=false, array $extraQuery=[])
Build a query array (array representation of query string) for load.php.
The main skin class which provides methods and properties for all other skins.
getHtmlElementAttributes()
Return values for <html> element.
isResponsive()
Indicates if this skin is responsive.
getPageClasses( $title)
TODO: document.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Represents a title within MediaWiki.
while(( $__line=Maintenance::readconsole()) !==false) print
Interface for configuration instances.
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
Base interface for content objects.
Interface for objects which can provide a MediaWiki context on request.
getConfig()
Get the site configuration.
foreach( $mmfl['setupFiles'] as $fileName) if($queue) if(empty( $mmfl['quiet'])) $s
if(PHP_SAPI !='cli-server') if(!isset( $_SERVER['SCRIPT_FILENAME'])) $file
Item class for a filearchive table row.
if(!isset( $args[0])) $lang