33use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
64use Wikimedia\NonSerializable\NonSerializableTrait;
77 use ProtectedHookAccessorTrait;
78 use NonSerializableTrait;
106 private $fetchResult =
null;
141 private $mRevisionRecord =
null;
148 $this->mOldId = $oldId;
149 $this->mPage = $this->
newPage( $title );
152 $this->linkRenderer = $services->getLinkRenderer();
153 $this->revisionStore = $services->getRevisionStore();
154 $this->userNameUtils = $services->getUserNameUtils();
155 $this->userOptionsLookup = $services->getUserOptionsLookup();
156 $this->commentFormatter = $services->getCommentFormatter();
157 $this->wikiPageFactory = $services->getWikiPageFactory();
158 $this->jobQueueGroup = $services->getJobQueueGroup();
159 $this->archivedRevisionLookup = $services->getArchivedRevisionLookup();
160 $this->dbProvider = $services->getConnectionProvider();
161 $this->blockStore = $services->getDatabaseBlockStore();
162 $this->restrictionStore = $services->getRestrictionStore();
179 $t = Title::newFromID( $id );
180 return $t ===
null ? null :
new static( $t );
193 $title = Title::makeTitle(
NS_FILE, $title->getDBkey() );
199 ->onArticleFromTitle( $title, $page, $context );
201 switch ( $title->getNamespace() ) {
212 $page->setContext( $context );
225 $article = self::newFromTitle( $page->
getTitle(), $context );
226 $article->mPage = $page;
236 return $this->mRedirectedFrom;
244 $this->mRedirectedFrom = $from;
253 return $this->mPage->getTitle();
267 $this->mRedirectedFrom =
null; #
Title object if set
268 $this->mRedirectUrl =
false;
269 $this->mRevisionRecord =
null;
270 $this->fetchResult =
null;
274 $this->mPage->clear();
285 if ( $this->mOldId ===
null ) {
286 $this->mOldId = $this->getOldIDFromRequest();
289 return $this->mOldId;
298 $this->mRedirectUrl =
false;
300 $request = $this->getContext()->getRequest();
301 $oldid = $request->getIntOrNull(
'oldid' );
303 if ( $oldid ===
null ) {
307 if ( $oldid !== 0 ) {
308 # Load the given revision and check whether the page is another one.
309 # In that case, update this instance to reflect the change.
310 if ( $oldid === $this->mPage->getLatest() ) {
311 $this->mRevisionRecord = $this->mPage->getRevisionRecord();
313 $this->mRevisionRecord = $this->revisionStore->getRevisionById( $oldid );
314 if ( $this->mRevisionRecord !==
null ) {
315 $revPageId = $this->mRevisionRecord->getPageId();
317 if ( $this->mPage->getId() !== $revPageId ) {
318 $this->mPage = $this->wikiPageFactory->newFromID( $revPageId );
324 $oldRev = $this->mRevisionRecord;
325 if ( $request->getRawVal(
'direction' ) ===
'next' ) {
328 $nextRev = $this->revisionStore->getNextRevision( $oldRev );
330 $nextid = $nextRev->getId();
335 $this->mRevisionRecord =
null;
337 $this->mRedirectUrl = $this->
getTitle()->getFullURL(
'redirect=no' );
339 } elseif ( $request->getRawVal(
'direction' ) ===
'prev' ) {
342 $prevRev = $this->revisionStore->getPreviousRevision( $oldRev );
344 $previd = $prevRev->getId();
349 $this->mRevisionRecord =
null;
366 if ( $this->fetchResult ) {
367 return $this->mRevisionRecord;
370 $oldid = $this->getOldID();
373 if ( !$this->mRevisionRecord ) {
375 $this->mRevisionRecord = $this->mPage->getRevisionRecord();
377 if ( !$this->mRevisionRecord ) {
378 wfDebug( __METHOD__ .
" failed to find page data for title " .
379 $this->
getTitle()->getPrefixedText() );
382 $this->fetchResult = Status::newFatal(
'noarticletext' );
386 $this->mRevisionRecord = $this->revisionStore->getRevisionById( $oldid );
388 if ( !$this->mRevisionRecord ) {
389 wfDebug( __METHOD__ .
" failed to load revision, rev_id $oldid" );
391 $this->fetchResult = Status::newFatal( $this->getMissingRevisionMsg( $oldid ) );
397 if ( !$this->mRevisionRecord->userCan( RevisionRecord::DELETED_TEXT, $this->getContext()->getAuthority() ) ) {
398 wfDebug( __METHOD__ .
" failed to retrieve content of revision " . $this->mRevisionRecord->getId() );
402 $this->fetchResult =
new Status;
403 $title = $this->
getTitle()->getPrefixedDBkey();
405 if ( $this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ) {
406 $this->fetchResult->
fatal(
'rev-suppressed-text' );
408 $this->fetchResult->fatal(
'rev-deleted-text-permission', $title );
414 $this->fetchResult = Status::newGood( $this->mRevisionRecord );
415 return $this->mRevisionRecord;
424 # If no oldid, this is the current version.
425 if ( $this->getOldID() == 0 ) {
429 return $this->mPage->exists() &&
430 $this->mRevisionRecord &&
431 $this->mRevisionRecord->isCurrent();
443 if ( $this->fetchResult && $this->fetchResult->isOK() ) {
445 $rev = $this->fetchResult->getValue();
446 return $rev->getId();
448 return $this->mPage->getLatest();
457 $context = $this->getContext();
460 # Get variables from query string
461 # As side effect this will load the revision and update the title
462 # in a revision ID is passed in the request, so this should remain
463 # the first call of this method even if $oldid is used way below.
464 $oldid = $this->getOldID();
466 $authority = $context->getAuthority();
467 # Another check in case getOldID() is altering the title
468 $permissionStatus = PermissionStatus::newEmpty();
470 ->authorizeRead(
'read', $this->
getTitle(), $permissionStatus )
472 wfDebug( __METHOD__ .
": denied on secondary read check" );
476 $outputPage = $context->getOutput();
477 # getOldID() may as well want us to redirect somewhere else
478 if ( $this->mRedirectUrl ) {
479 $outputPage->redirect( $this->mRedirectUrl );
480 wfDebug( __METHOD__ .
": redirecting due to oldid" );
485 # If we got diff in the query, we want to see a diff page instead of the article.
486 if ( $context->getRequest()->getCheck(
'diff' ) ) {
487 wfDebug( __METHOD__ .
": showing diff page" );
488 $this->showDiffPage();
493 $this->showProtectionIndicator();
495 # Set page title (may be overridden from ParserOutput if title conversion is enabled or DISPLAYTITLE is used)
496 $outputPage->setPageTitle( Parser::formatPageTitle(
497 str_replace(
'_',
' ', $this->
getTitle()->getNsText() ),
502 $outputPage->setArticleFlag(
true );
503 # Allow frames by default
504 $outputPage->getMetadata()->setPreventClickjacking(
false );
506 $parserOptions = $this->getParserOptions();
509 # Allow extensions to vary parser options used for article rendering
511 ->onArticleParserOptions( $this, $parserOptions );
512 # Render printable version, use printable version cache
513 if ( $outputPage->isPrintable() ) {
514 $parserOptions->setIsPrintable(
true );
515 $poOptions[
'enableSectionEditLinks'] =
false;
516 $this->addMessageBoxStyles( $outputPage );
517 $outputPage->prependHTML(
519 $outputPage->msg(
'printableversion-deprecated-warning' )->escaped()
522 } elseif ( $this->viewIsRenderAction || !$this->isCurrent() ||
523 !$authority->probablyCan(
'edit', $this->getTitle() )
525 $poOptions[
'enableSectionEditLinks'] =
false;
528 # Try client and file cache
529 if ( $oldid === 0 && $this->mPage->checkTouched() ) {
530 # Try to stream the output from file cache
531 if ( $useFileCache && $this->tryFileCache() ) {
532 wfDebug( __METHOD__ .
": done file cache" );
533 # tell wgOut that output is taken care of
534 $outputPage->disable();
535 $this->mPage->doViewUpdates( $authority, $oldid );
541 $this->showRedirectedFromHeader();
542 $this->showNamespaceHeader();
544 if ( $this->viewIsRenderAction ) {
545 $poOptions += [
'absoluteURLs' => true ];
547 $poOptions += [
'includeDebugInfo' => true ];
551 $this->generateContentOutput( $authority, $parserOptions, $oldid, $outputPage, $poOptions );
554 $this->showViewError(
wfMessage(
'badrevision' )->text() );
561 # For the main page, overwrite the <title> element with the con-
562 # tents of 'pagetitle-view-mainpage' instead of the default (if
564 # This message always exists because it is in the i18n files
565 if ( $this->
getTitle()->isMainPage() ) {
566 $msg = $context->msg(
'pagetitle-view-mainpage' )->inContentLanguage();
567 if ( !$msg->isDisabled() ) {
568 $outputPage->setHTMLTitle( $msg->text() );
577 $outputPage->adaptCdnTTL( $this->mPage->getTimestamp(), 86_400 );
579 $this->showViewFooter();
580 $this->mPage->doViewUpdates( $authority, $oldid, $this->fetchRevisionRecord() );
582 # Load the postEdit module if the user just saved this revision
583 # See also EditPage::setPostEditCookie
584 $request = $context->getRequest();
585 $cookieKey = EditPage::POST_EDIT_COOKIE_KEY_PREFIX . $this->getRevIdFetched();
586 $postEdit = $request->getCookie( $cookieKey );
588 # Clear the cookie. This also prevents caching of the response.
589 $request->response()->clearCookie( $cookieKey );
590 $outputPage->addJsConfigVars(
'wgPostEdit', $postEdit );
591 $outputPage->addModules(
'mediawiki.action.view.postEdit' );
593 && $this->userOptionsLookup->getOption( $this->getContext()->getUser(),
'editrecovery' )
595 $outputPage->addModules(
'mediawiki.editRecovery.postEdit' );
605 $context = $this->getContext();
606 $outputPage = $context->getOutput();
608 $protectionIndicatorsAreEnabled = $context->getConfig()
611 if ( !$protectionIndicatorsAreEnabled || $title->isMainPage() ) {
615 $protection = $this->restrictionStore->getRestrictions( $title,
'edit' );
617 $cascadeProtection = $this->restrictionStore->getCascadeProtectionSources( $title )[1];
619 $isCascadeProtected = array_key_exists(
'edit', $cascadeProtection );
621 if ( !$protection && !$isCascadeProtected ) {
625 if ( $isCascadeProtected ) {
629 $protectionLevel = $cascadeProtection[
'edit'][0];
631 $protectionLevel = $protection[0];
638 $protectionLevel = htmlspecialchars( $protectionLevel );
640 $protectionExpiry = $this->restrictionStore->getRestrictionExpiry( $title,
'edit' );
641 $formattedProtectionExpiry = $context->getLanguage()
642 ->formatExpiry( $protectionExpiry ??
'' );
644 $protectionMsg =
'protection-indicator-title';
645 if ( $protectionExpiry ===
'infinity' || !$protectionExpiry ) {
646 $protectionMsg .=
'-infinity';
654 $protectionIndicatorId =
'protection-' . $protectionLevel;
655 $protectionIndicatorId .= ( $isCascadeProtected ?
'-cascade' :
'' );
658 $protectionMsg = $outputPage->msg( $protectionMsg, $protectionLevel, $formattedProtectionExpiry )->text();
662 $protectionHelpLink = $outputPage->msg( $protectionIndicatorId .
'-helppage' );
663 if ( $protectionHelpLink->isDisabled() ) {
664 $protectionHelpLink =
'https://mediawiki.org/wiki/Special:MyLanguage/Help:Protection';
666 $protectionHelpLink = $protectionHelpLink->text();
669 $outputPage->setIndicators( [
670 $protectionIndicatorId => Html::rawElement(
'a', [
671 'class' =>
'mw-protection-indicator-icon--lock',
672 'title' => $protectionMsg,
673 'href' => $protectionHelpLink
680 $outputPage->addModuleStyles(
'mediawiki.protectionIndicators.styles' );
695 private function generateContentOutput(
696 Authority $performer,
697 ParserOptions $parserOptions,
699 OutputPage $outputPage,
702 # Should the parser cache be used?
703 $useParserCache = true;
705 $parserOutputAccess = MediaWikiServices::getInstance()->getParserOutputAccess();
708 $this->getHookRunner()->onArticleViewHeader( $this, $outputDone, $useParserCache );
710 if ( $outputDone instanceof ParserOutput ) {
711 $pOutput = $outputDone;
715 $this->doOutputMetaData( $pOutput, $outputPage );
721 if ( !$this->mPage->exists() ) {
722 wfDebug( __METHOD__ .
": showing missing article" );
723 $this->showMissingArticle();
724 $this->mPage->doViewUpdates( $performer );
730 if ( $useParserCache && !$oldid ) {
731 $pOutput = $parserOutputAccess->getCachedParserOutput(
735 ParserOutputAccess::OPT_NO_AUDIENCE_CHECK
739 $this->doOutputFromParserCache( $pOutput, $parserOptions, $outputPage, $textOptions );
740 $this->doOutputMetaData( $pOutput, $outputPage );
745 $rev = $this->fetchRevisionRecord();
746 if ( !$this->fetchResult->isOK() ) {
747 $this->showViewError( $this->fetchResult->getWikiText(
748 false,
false, $this->getContext()->getLanguage()
753 # Are we looking at an old revision
755 $this->setOldSubtitle( $oldid );
757 if ( !$this->showDeletedRevisionHeader() ) {
758 wfDebug( __METHOD__ .
": cannot view deleted revision" );
765 if ( $useParserCache ) {
766 $pOutput = $parserOutputAccess->getCachedParserOutput(
770 ParserOutputAccess::OPT_NO_AUDIENCE_CHECK
774 $this->doOutputFromParserCache( $pOutput, $parserOptions, $outputPage, $textOptions );
775 $this->doOutputMetaData( $pOutput, $outputPage );
781 # Ensure that UI elements requiring revision ID have
782 # the correct version information. (This may be overwritten after creation of ParserOutput)
783 $outputPage->setRevisionId( $this->getRevIdFetched() );
784 $outputPage->setRevisionIsCurrent( $rev->isCurrent() );
785 # Preload timestamp to avoid a DB hit
786 $outputPage->getMetadata()->setRevisionTimestamp( $rev->getTimestamp() );
788 # Pages containing custom CSS or JavaScript get special treatment
789 if ( $this->
getTitle()->isSiteConfigPage() || $this->
getTitle()->isUserConfigPage() ) {
790 $dir = $this->
getContext()->getLanguage()->getDir();
791 $lang = $this->
getContext()->getLanguage()->getHtmlCode();
793 $outputPage->wrapWikiMsg(
794 "<div id='mw-clearyourcache' lang='$lang' dir='$dir' class='mw-content-$dir'>\n$1\n</div>",
797 $outputPage->addModuleStyles(
'mediawiki.action.styles' );
798 } elseif ( !$this->getHookRunner()->onArticleRevisionViewCustom(
806 $this->doOutputMetaData( $pOutput, $outputPage );
810 # Run the parse, protected by a pool counter
811 wfDebug( __METHOD__ .
": doing uncached parse" );
816 $opt |= ParserOutputAccess::OPT_NO_CHECK_CACHE;
819 $opt |= ParserOutputAccess::OPT_NO_AUDIENCE_CHECK;
822 $opt |= ParserOutputAccess::OPT_FOR_ARTICLE_VIEW;
827 $opt |= ParserOutputAccess::OPT_LINKS_UPDATE;
829 if ( !$rev->getId() || !$useParserCache ) {
831 $opt |= ParserOutputAccess::OPT_NO_CACHE;
834 $renderStatus = $parserOutputAccess->getParserOutput(
856 if ( $oldid === 0 || $oldid === $this->getPage()->getLatest() ) {
857 $parsoidCacheWarmingEnabled = $this->
getContext()->getConfig()
858 ->get( MainConfigNames::ParsoidCacheConfig )[
'WarmParsoidParserCache'];
860 if ( $parsoidCacheWarmingEnabled ) {
861 $parsoidJobSpec = ParsoidCachePrewarmJob::newSpec(
863 $this->getPage()->toPageRecord(),
864 [
'causeAction' =>
'view' ]
866 $this->jobQueueGroup->lazyPush( $parsoidJobSpec );
870 $this->doOutputFromRenderStatus(
878 if ( !$renderStatus->isOK() ) {
882 $pOutput = $renderStatus->getValue();
883 $this->doOutputMetaData( $pOutput, $outputPage );
887 private function doOutputMetaData( ?ParserOutput $pOutput, OutputPage $outputPage ) {
888 # Adjust title for main page & pages with displaytitle
890 $this->adjustDisplayTitle( $pOutput );
896 $pageLang = $pOutput->getLanguage();
898 $outputPage->setContentLangForJS( $pageLang );
902 # Check for any __NOINDEX__ tags on the page using $pOutput
903 $policy = $this->getRobotPolicy(
'view', $pOutput ?: null );
904 $outputPage->getMetadata()->setIndexPolicy( $policy[
'index'] );
905 $outputPage->setFollowPolicy( $policy[
'follow'] );
907 $this->mParserOutput = $pOutput;
916 private function doOutputFromParserCache(
917 ParserOutput $pOutput,
918 ParserOptions $pOptions,
919 OutputPage $outputPage,
922 # Ensure that UI elements requiring revision ID have
923 # the correct version information.
924 $oldid = $pOutput->getCacheRevisionId() ?? $this->getRevIdFetched();
925 $outputPage->setRevisionId( $oldid );
926 $outputPage->setRevisionIsCurrent( $oldid === $this->mPage->getLatest() );
927 $outputPage->addParserOutput( $pOutput, $pOptions, $textOptions );
928 # Preload timestamp to avoid a DB hit
929 $cachedTimestamp = $pOutput->getRevisionTimestamp();
930 if ( $cachedTimestamp !==
null ) {
931 $outputPage->getMetadata()->setRevisionTimestamp( $cachedTimestamp );
932 $this->mPage->setTimestamp( $cachedTimestamp );
943 private function doOutputFromRenderStatus(
945 Status $renderStatus,
946 OutputPage $outputPage,
947 ParserOptions $parserOptions,
951 if ( !$renderStatus->isOK() ) {
952 $this->showViewError( $renderStatus->getWikiText(
953 false,
'view-pool-error', $context->getLanguage()
958 $pOutput = $renderStatus->getValue();
961 if ( $renderStatus->hasMessage(
'view-pool-dirty-output' ) ) {
962 $outputPage->lowerCdnMaxage( $context->getConfig()->get( MainConfigNames::CdnMaxageStale ) );
963 $outputPage->setLastModified( $pOutput->getCacheTime() );
964 $staleReason = $renderStatus->hasMessage(
'view-pool-contention' )
965 ? $context->msg(
'view-pool-contention' )->escaped()
966 : $context->msg(
'view-pool-timeout' )->escaped();
967 $outputPage->addHTML(
"<!-- parser cache is expired, " .
968 "sending anyway due to $staleReason-->\n" );
971 $cachedId = $pOutput->getCacheRevisionId();
972 if ( $cachedId !==
null ) {
973 $outputPage->setRevisionId( $cachedId );
974 $outputPage->getMetadata()->setRevisionTimestamp( $pOutput->getTimestamp() );
978 $outputPage->addParserOutput( $pOutput, $parserOptions, $textOptions );
980 if ( $this->getRevisionRedirectTarget( $rev ) ) {
981 $outputPage->addSubtitle(
"<span id=\"redirectsub\">" .
982 $context->msg(
'redirectpagesub' )->parse() .
"</span>" );
990 private function getRevisionRedirectTarget( RevisionRecord $revision ) {
994 $content = $revision->getContent( SlotRecord::MAIN );
995 return $content ? $content->getRedirectTarget() :
null;
1002 $out = $this->getContext()->getOutput();
1004 # Adjust the title if it was set by displaytitle, -{T|}- or language conversion
1006 if ( strval( $titleText ) !==
'' ) {
1007 $out->setPageTitle( $titleText );
1008 $out->setDisplayTitle( $titleText );
1017 $context = $this->getContext();
1018 $outputPage = $context->getOutput();
1019 $outputPage->addBodyClasses(
'mw-article-diff' );
1020 $request = $context->getRequest();
1021 $diff = $request->getVal(
'diff' );
1022 $rcid = $request->getInt(
'rcid' );
1023 $purge = $request->getRawVal(
'action' ) ===
'purge';
1024 $unhide = $request->getInt(
'unhide' ) === 1;
1025 $oldid = $this->getOldID();
1027 $rev = $this->fetchRevisionRecord();
1032 $rev = $this->revisionStore->getRevisionById( $oldid );
1038 $outputPage->setPageTitleMsg( $context->msg(
'errorpagetitle' ) );
1039 $msg = $context->msg(
'difference-missing-revision' )
1043 $outputPage->addHTML( $msg );
1048 $services = MediaWikiServices::getInstance();
1050 $contentHandler = $services
1051 ->getContentHandlerFactory()
1052 ->getContentHandler(
1053 $rev->getMainContentModel()
1055 $de = $contentHandler->createDifferenceEngine(
1064 $diffType = $request->getVal(
'diff-type' );
1066 if ( $diffType ===
null ) {
1067 $diffType = $this->userOptionsLookup
1068 ->getOption( $context->getUser(),
'diff-type' );
1070 $de->setExtraQueryParams( [
'diff-type' => $diffType ] );
1073 $de->setSlotDiffOptions( [
1074 'diff-type' => $diffType,
1075 'expand-url' => $this->viewIsRenderAction,
1076 'inline-toggle' =>
true,
1078 $de->showDiffPage( $this->isDiffOnlyView() );
1082 [ , $new ] = $de->mapDiffPrevNext( $oldid, $diff );
1084 $this->mPage->doViewUpdates( $context->getAuthority(), (
int)$new );
1087 $context->getOutput()->addHelpLink(
'Help:Diff' );
1091 return $this->getContext()->getRequest()->getBool(
1093 $this->userOptionsLookup->getBoolOption( $this->getContext()->getUser(),
'diffonly' )
1105 $context = $this->getContext();
1106 $mainConfig = $context->getConfig();
1107 $articleRobotPolicies = $mainConfig->get( MainConfigNames::ArticleRobotPolicies );
1108 $namespaceRobotPolicies = $mainConfig->get( MainConfigNames::NamespaceRobotPolicies );
1109 $defaultRobotPolicy = $mainConfig->get( MainConfigNames::DefaultRobotPolicy );
1111 $ns = $title->getNamespace();
1113 # Don't index user and user talk pages for blocked users (T13443)
1115 $specificTarget =
null;
1116 $vagueTarget =
null;
1117 $titleText = $title->getText();
1118 if ( IPUtils::isValid( $titleText ) ) {
1119 $vagueTarget = $titleText;
1121 $specificTarget = $title->getRootText();
1123 $block = $this->blockStore->newFromTarget(
1124 $specificTarget, $vagueTarget,
false, DatabaseBlockStore::AUTO_NONE );
1127 'index' =>
'noindex',
1128 'follow' =>
'nofollow'
1133 if ( $this->mPage->getId() === 0 || $this->getOldID() ) {
1134 # Non-articles (special pages etc), and old revisions
1136 'index' =>
'noindex',
1137 'follow' =>
'nofollow'
1139 } elseif ( $context->getOutput()->isPrintable() ) {
1140 # Discourage indexing of printable versions, but encourage following
1142 'index' =>
'noindex',
1143 'follow' =>
'follow'
1145 } elseif ( $context->getRequest()->getInt(
'curid' ) ) {
1146 # For ?curid=x urls, disallow indexing
1148 'index' =>
'noindex',
1149 'follow' =>
'follow'
1153 # Otherwise, construct the policy based on the various config variables.
1154 $policy = self::formatRobotPolicy( $defaultRobotPolicy );
1156 if ( isset( $namespaceRobotPolicies[$ns] ) ) {
1157 # Honour customised robot policies for this namespace
1158 $policy = array_merge(
1160 self::formatRobotPolicy( $namespaceRobotPolicies[$ns] )
1163 if ( $title->canUseNoindex() && $pOutput && $pOutput->getIndexPolicy() ) {
1164 # __INDEX__ and __NOINDEX__ magic words, if allowed. Incorporates
1165 # a final check that we have really got the parser output.
1166 $policy = array_merge(
1168 [
'index' => $pOutput->getIndexPolicy() ]
1172 if ( isset( $articleRobotPolicies[$title->getPrefixedText()] ) ) {
1173 # (T16900) site config can override user-defined __INDEX__ or __NOINDEX__
1174 $policy = array_merge(
1176 self::formatRobotPolicy( $articleRobotPolicies[$title->getPrefixedText()] )
1191 if ( is_array( $policy ) ) {
1193 } elseif ( !$policy ) {
1198 foreach ( explode(
',', $policy ) as $var ) {
1199 $var = trim( $var );
1200 if ( $var ===
'index' || $var ===
'noindex' ) {
1201 $arr[
'index'] = $var;
1202 } elseif ( $var ===
'follow' || $var ===
'nofollow' ) {
1203 $arr[
'follow'] = $var;
1218 $context = $this->getContext();
1219 $redirectSources = $context->getConfig()->get( MainConfigNames::RedirectSources );
1220 $outputPage = $context->getOutput();
1221 $request = $context->getRequest();
1222 $rdfrom = $request->getVal(
'rdfrom' );
1225 $query = $request->getQueryValues();
1226 unset( $query[
'rdfrom'] );
1227 unset( $query[
'title'] );
1228 if ( $this->
getTitle()->isRedirect() ) {
1230 $query[
'redirect'] =
'no';
1232 $redirectTargetUrl = $this->
getTitle()->getLinkURL( $query );
1234 if ( $this->mRedirectedFrom ) {
1237 if ( $this->getHookRunner()->onArticleViewRedirect( $this ) ) {
1238 $redir = $this->linkRenderer->makeKnownLink(
1239 $this->mRedirectedFrom,
1242 [
'redirect' =>
'no' ]
1245 $outputPage->addSubtitle(
"<span class=\"mw-redirectedfrom\">" .
1246 $context->msg(
'redirectedfrom' )->rawParams( $redir )->parse()
1251 $outputPage->addJsConfigVars( [
1252 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
1254 $outputPage->addModules(
'mediawiki.action.view.redirect' );
1257 $outputPage->setCanonicalUrl( $this->
getTitle()->getCanonicalURL() );
1260 $outputPage->setRedirectedFrom( $this->mRedirectedFrom );
1264 } elseif ( $rdfrom ) {
1267 if ( $redirectSources && preg_match( $redirectSources, $rdfrom ) ) {
1268 $redir = $this->linkRenderer->makeExternalLink( $rdfrom, $rdfrom, $this->
getTitle() );
1269 $outputPage->addSubtitle(
"<span class=\"mw-redirectedfrom\">" .
1270 $context->msg(
'redirectedfrom' )->rawParams( $redir )->parse()
1274 $outputPage->addJsConfigVars( [
1275 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
1277 $outputPage->addModules(
'mediawiki.action.view.redirect' );
1291 if ( $this->
getTitle()->isTalkPage() && !$this->getContext()->msg(
'talkpageheader' )->isDisabled() ) {
1292 $this->getContext()->getOutput()->wrapWikiMsg(
1293 "<div class=\"mw-talkpageheader\">\n$1\n</div>",
1294 [
'talkpageheader' ]
1303 # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page
1305 && IPUtils::isValid( $this->
getTitle()->getText() )
1307 $this->getContext()->getOutput()->addWikiMsg(
'anontalkpagetext' );
1311 $patrolFooterShown = $this->showPatrolFooter();
1313 $this->getHookRunner()->onArticleViewFooter( $this, $patrolFooterShown );
1327 $context = $this->getContext();
1328 $mainConfig = $context->getConfig();
1329 $useNPPatrol = $mainConfig->get( MainConfigNames::UseNPPatrol );
1330 $useRCPatrol = $mainConfig->get( MainConfigNames::UseRCPatrol );
1331 $useFilePatrol = $mainConfig->get( MainConfigNames::UseFilePatrol );
1332 $fileMigrationStage = $mainConfig->get( MainConfigNames::FileSchemaMigrationStage );
1334 if ( !$this->getHookRunner()->onArticleShowPatrolFooter( $this ) ) {
1338 $outputPage = $context->getOutput();
1339 $user = $context->getUser();
1343 if ( !$context->getAuthority()->probablyCan(
'patrol', $title )
1344 || !( $useRCPatrol || $useNPPatrol
1345 || ( $useFilePatrol && $title->inNamespace(
NS_FILE ) ) )
1351 if ( $this->mRevisionRecord
1352 && !RecentChange::isInRCLifespan( $this->mRevisionRecord->getTimestamp(), 21600 )
1360 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1361 $key = $cache->makeKey(
'unpatrollable-page', $title->getArticleID() );
1362 if ( $cache->get( $key ) ) {
1366 $dbr = $this->dbProvider->getReplicaDatabase();
1367 $oldestRevisionRow = $dbr->newSelectQueryBuilder()
1368 ->select( [
'rev_id',
'rev_timestamp' ] )
1369 ->from(
'revision' )
1370 ->where( [
'rev_page' => $title->getArticleID() ] )
1371 ->orderBy( [
'rev_timestamp',
'rev_id' ] )
1372 ->caller( __METHOD__ )->fetchRow();
1373 $oldestRevisionTimestamp = $oldestRevisionRow ? $oldestRevisionRow->rev_timestamp :
false;
1379 $recentPageCreation =
false;
1380 if ( $oldestRevisionTimestamp
1381 && RecentChange::isInRCLifespan( $oldestRevisionTimestamp, 21600 )
1384 $recentPageCreation =
true;
1385 $rc = RecentChange::newFromConds(
1387 'rc_this_oldid' => intval( $oldestRevisionRow->rev_id ),
1395 $markPatrolledMsg = $context->msg(
'markaspatrolledtext' );
1403 $recentFileUpload =
false;
1404 if ( ( !$rc || $rc->getAttribute(
'rc_patrolled' ) ) && $useFilePatrol
1405 && $title->getNamespace() ===
NS_FILE ) {
1408 $newestUploadTimestamp = $dbr->newSelectQueryBuilder()
1409 ->select(
'img_timestamp' )
1411 ->where( [
'img_name' => $title->getDBkey() ] )
1412 ->caller( __METHOD__ )->fetchField();
1414 $newestUploadTimestamp = $dbr->newSelectQueryBuilder()
1415 ->select(
'fr_timestamp' )
1417 ->join(
'filerevision',
null,
'file_latest = fr_id' )
1418 ->where( [
'file_name' => $title->getDBkey() ] )
1419 ->caller( __METHOD__ )->fetchField();
1422 if ( $newestUploadTimestamp
1423 && RecentChange::isInRCLifespan( $newestUploadTimestamp, 21600 )
1426 $recentFileUpload =
true;
1427 $rc = RecentChange::newFromConds(
1430 'rc_log_type' =>
'upload',
1431 'rc_timestamp' => $newestUploadTimestamp,
1433 'rc_cur_id' => $title->getArticleID()
1439 $markPatrolledMsg = $context->msg(
'markaspatrolledtext-file' );
1444 if ( !$recentPageCreation && !$recentFileUpload ) {
1449 $cache->set( $key,
'1' );
1461 if ( $rc->getAttribute(
'rc_patrolled' ) ) {
1466 $cache->set( $key,
'1' );
1471 if ( $rc->getPerformerIdentity()->equals( $user ) ) {
1477 $outputPage->getMetadata()->setPreventClickjacking(
true );
1478 $outputPage->addModules(
'mediawiki.misc-authed-curate' );
1480 $link = $this->linkRenderer->makeKnownLink(
1482 new HtmlArmor(
'<button class="cdx-button cdx-button--action-progressive">'
1484 . $markPatrolledMsg->escaped() .
'</button>' ),
1487 'action' =>
'markpatrolled',
1488 'rcid' => $rc->getAttribute(
'rc_id' ),
1492 $outputPage->addModuleStyles(
'mediawiki.action.styles' );
1493 $outputPage->addHTML(
"<div class='patrollink' data-mw='interface'>$link</div>" );
1505 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1506 $cache->delete( $cache->makeKey(
'unpatrollable-page', $articleID ) );
1514 $context = $this->getContext();
1515 $send404Code = $context->getConfig()->get( MainConfigNames::Send404Code );
1517 $outputPage = $context->getOutput();
1519 $validUserPage =
false;
1523 $services = MediaWikiServices::getInstance();
1525 $contextUser = $context->getUser();
1527 # Show info in user (talk) namespace. Does the user exist? Are they blocked?
1528 if ( $title->getNamespace() ===
NS_USER
1531 $rootPart = $title->getRootText();
1532 $userFactory = $services->getUserFactory();
1533 $user = $userFactory->newFromNameOrIp( $rootPart );
1535 if ( $user && $user->isRegistered() && $user->isHidden() &&
1536 !$context->getAuthority()->isAllowed(
'hideuser' )
1543 if ( !( $user && $user->isRegistered() ) && !$this->userNameUtils->isIP( $rootPart ) ) {
1544 $this->addMessageBoxStyles( $outputPage );
1546 $outputPage->addHTML( Html::warningBox(
1547 $context->msg(
'userpage-userdoesnotexist-view',
wfEscapeWikiText( $rootPart ) )->parse(),
1548 'mw-userpage-userdoesnotexist'
1552 LogEventsList::showLogExtract(
1555 Title::makeTitleSafe(
NS_USER, $rootPart ),
1559 'showIfEmpty' =>
false,
1560 'msgKey' => [
'renameuser-renamed-notice', $title->getBaseText() ]
1564 $validUserPage = !$title->isSubpage();
1566 $blockLogBox = LogEventsList::getBlockLogWarningBox(
1568 $services->getNamespaceInfo(),
1569 $this->getContext(),
1570 $this->linkRenderer,
1574 if ( $blockLogBox !==
null ) {
1575 $outputPage->addHTML( $blockLogBox );
1580 $this->getHookRunner()->onShowMissingArticle( $this );
1582 # Show delete and move logs if there were any such events.
1583 # The logging query can DOS the site when bots/crawlers cause 404 floods,
1584 # so be careful showing this. 404 pages must be cheap as they are hard to cache.
1585 $dbCache = MediaWikiServices::getInstance()->getMainObjectStash();
1586 $key = $dbCache->makeKey(
'page-recent-delete', md5( $title->getPrefixedText() ) );
1587 $isRegistered = $contextUser->isRegistered();
1588 $sessionExists = $context->getRequest()->getSession()->isPersistent();
1590 if ( $isRegistered || $dbCache->get( $key ) || $sessionExists ) {
1591 $logTypes = [
'delete',
'move',
'protect',
'merge' ];
1593 $dbr = $this->dbProvider->getReplicaDatabase();
1595 $conds = [ $dbr->expr(
'log_action',
'!=',
'revision' ) ];
1597 $this->getHookRunner()->onArticle__MissingArticleConditions( $conds, $logTypes );
1598 LogEventsList::showLogExtract(
1606 'showIfEmpty' =>
false,
1607 'msgKey' => [ $isRegistered || $sessionExists
1608 ?
'moveddeleted-notice'
1609 :
'moveddeleted-notice-recent'
1615 if ( !$this->mPage->hasViewableContent() && $send404Code && !$validUserPage ) {
1618 $context->getRequest()->response()->statusHeader( 404 );
1622 $policy = $this->getRobotPolicy(
'view' );
1623 $outputPage->getMetadata()->setIndexPolicy( $policy[
'index'] );
1624 $outputPage->setFollowPolicy( $policy[
'follow'] );
1626 $hookResult = $this->getHookRunner()->onBeforeDisplayNoArticleText( $this );
1628 if ( !$hookResult ) {
1632 # Show error message
1633 $oldid = $this->getOldID();
1634 if ( !$oldid && $title->getNamespace() ===
NS_MEDIAWIKI && $title->hasSourceText() ) {
1635 $text = $this->
getTitle()->getDefaultMessageText() ??
'';
1636 $outputPage->addWikiTextAsContent( $text );
1639 $text = $this->getMissingRevisionMsg( $oldid )->plain();
1640 } elseif ( $context->getAuthority()->probablyCan(
'edit', $title ) ) {
1641 $message = $isRegistered ?
'noarticletext' :
'noarticletextanon';
1642 $text = $context->msg( $message )->plain();
1644 $text = $context->msg(
'noarticletext-nopermission' )->plain();
1647 $dir = $context->getLanguage()->getDir();
1648 $lang = $context->getLanguage()->getHtmlCode();
1649 $outputPage->addWikiTextAsInterface( Html::openElement(
'div', [
1650 'class' =>
"noarticletext mw-content-$dir",
1653 ] ) .
"\n$text\n</div>" );
1661 private function showViewError(
string $errortext ) {
1662 $outputPage = $this->getContext()->getOutput();
1663 $outputPage->setPageTitleMsg( $this->getContext()->msg(
'errorpagetitle' ) );
1664 $outputPage->disableClientCache();
1665 $outputPage->setRobotPolicy(
'noindex,nofollow' );
1666 $outputPage->clearHTML();
1667 $this->addMessageBoxStyles( $outputPage );
1668 $outputPage->addHTML( Html::errorBox( $outputPage->parseAsContent( $errortext ) ) );
1678 if ( !$this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
1682 $outputPage = $this->getContext()->getOutput();
1684 $titleText = $this->
getTitle()->getPrefixedDBkey();
1685 $this->addMessageBoxStyles( $outputPage );
1687 if ( !$this->mRevisionRecord->userCan(
1688 RevisionRecord::DELETED_TEXT,
1689 $this->getContext()->getAuthority()
1691 $outputPage->addHTML(
1693 $outputPage->msg(
'rev-deleted-text-permission', $titleText )->parse(),
1700 } elseif ( $this->getContext()->getRequest()->getInt(
'unhide' ) !== 1 ) {
1701 # Give explanation and add a link to view the revision...
1702 $oldid = intval( $this->getOldID() );
1703 $link = $this->
getTitle()->getFullURL(
"oldid={$oldid}&unhide=1" );
1704 $msg = $this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ?
1705 'rev-suppressed-text-unhide' :
'rev-deleted-text-unhide';
1706 $outputPage->addHTML(
1708 $outputPage->msg( $msg, $link )->parse(),
1716 $msg = $this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_RESTRICTED )
1717 ? [
'rev-suppressed-text-view', $titleText ]
1718 : [
'rev-deleted-text-view', $titleText ];
1719 $outputPage->addHTML(
1721 $outputPage->msg( $msg[0], $msg[1] )->parse(),
1730 private function addMessageBoxStyles(
OutputPage $outputPage ) {
1732 'mediawiki.codex.messagebox.styles',
1745 if ( !$this->getHookRunner()->onDisplayOldSubtitle( $this, $oldid ) ) {
1749 $context = $this->getContext();
1750 $unhide = $context->getRequest()->getInt(
'unhide' ) === 1;
1752 # Cascade unhide param in links for easy deletion browsing
1755 $extraParams[
'unhide'] = 1;
1758 if ( $this->mRevisionRecord && $this->mRevisionRecord->getId() === $oldid ) {
1759 $revisionRecord = $this->mRevisionRecord;
1761 $revisionRecord = $this->revisionStore->getRevisionById( $oldid );
1763 if ( !$revisionRecord ) {
1764 throw new LogicException(
'There should be a revision record at this point.' );
1767 $timestamp = $revisionRecord->getTimestamp();
1769 $current = ( $oldid == $this->mPage->getLatest() );
1770 $language = $context->getLanguage();
1771 $user = $context->getUser();
1773 $td = $language->userTimeAndDate( $timestamp, $user );
1774 $tddate = $language->userDate( $timestamp, $user );
1775 $tdtime = $language->userTime( $timestamp, $user );
1777 # Show user links if allowed to see them. If hidden, then show them only if requested...
1778 $userlinks = Linker::revUserTools( $revisionRecord, !$unhide );
1780 $infomsg = $current && !$context->msg(
'revision-info-current' )->isDisabled()
1781 ?
'revision-info-current'
1786 'mediawiki.action.styles',
1787 'mediawiki.interface.helpers.styles'
1790 $revisionUser = $revisionRecord->getUser();
1791 $revisionInfo =
"<div id=\"mw-{$infomsg}\">" .
1792 $context->msg( $infomsg, $td )
1793 ->rawParams( $userlinks )
1795 $revisionRecord->getId(),
1798 $revisionUser ? $revisionUser->getName() :
''
1800 ->rawParams( $this->commentFormatter->formatRevision(
1810 ? $context->msg(
'currentrevisionlink' )->escaped()
1811 : $this->linkRenderer->makeKnownLink(
1813 $context->msg(
'currentrevisionlink' )->text(),
1818 ? $context->msg(
'diff' )->escaped()
1819 : $this->linkRenderer->makeKnownLink(
1821 $context->msg(
'diff' )->text(),
1828 $prevExist = (bool)$this->revisionStore->getPreviousRevision( $revisionRecord );
1829 $prevlink = $prevExist
1830 ? $this->linkRenderer->makeKnownLink(
1832 $context->msg(
'previousrevision' )->text(),
1835 'direction' =>
'prev',
1839 : $context->msg(
'previousrevision' )->escaped();
1840 $prevdiff = $prevExist
1841 ? $this->linkRenderer->makeKnownLink(
1843 $context->msg(
'diff' )->text(),
1850 : $context->msg(
'diff' )->escaped();
1851 $nextlink = $current
1852 ? $context->msg(
'nextrevision' )->escaped()
1853 : $this->linkRenderer->makeKnownLink(
1855 $context->msg(
'nextrevision' )->text(),
1858 'direction' =>
'next',
1862 $nextdiff = $current
1863 ? $context->msg(
'diff' )->escaped()
1864 : $this->linkRenderer->makeKnownLink(
1866 $context->msg(
'diff' )->text(),
1874 $cdel = Linker::getRevDeleteLink(
1875 $context->getAuthority(),
1879 if ( $cdel !==
'' ) {
1884 $this->addMessageBoxStyles( $outputPage );
1888 "<div id=\"mw-revision-nav\">" . $cdel .
1889 $context->msg(
'revision-nav' )->rawParams(
1890 $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff
1891 )->escaped() .
"</div>",
1912 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
1925 $out = $this->getContext()->getOutput();
1926 $msg = $out->msg(
'namespace-' . $this->
getTitle()->getNamespace() .
'-helppage' );
1928 if ( !$msg->isDisabled() ) {
1929 $title = Title::newFromText( $msg->plain() );
1930 if ( $title instanceof
Title ) {
1931 $out->addHelpLink( $title->getLocalURL(),
true );
1934 $out->addHelpLink( $to, $overrideBaseUrl );
1942 $this->getContext()->getRequest()->response()->header(
'X-Robots-Tag: noindex' );
1943 $this->getContext()->getOutput()->setArticleBodyOnly(
true );
1945 $this->viewIsRenderAction =
true;
1974 static $called =
false;
1977 wfDebug(
"Article::tryFileCache(): called twice!?" );
1982 if ( $this->isFileCacheable() ) {
1984 if ( $cache->isCacheGood( $this->mPage->getTouched() ) ) {
1985 wfDebug(
"Article::tryFileCache(): about to load file" );
1986 $cache->loadFromFileCache( $this->getContext() );
1989 wfDebug(
"Article::tryFileCache(): starting buffer" );
1990 ob_start( [ &$cache,
'saveToFileCache' ] );
1993 wfDebug(
"Article::tryFileCache(): not cacheable" );
2007 if ( HTMLFileCache::useFileCache( $this->getContext(), $mode ) ) {
2008 $cacheable = $this->mPage->getId()
2009 && !$this->mRedirectedFrom && !$this->
getTitle()->isRedirect();
2012 $cacheable = $this->getHookRunner()->onIsFileCacheable( $this ) ??
false;
2031 if ( $user ===
null ) {
2032 $parserOptions = $this->getParserOptions();
2034 $parserOptions = $this->mPage->makeParserOptions( $user );
2035 $parserOptions->setRenderReason(
'page-view' );
2038 return $this->mPage->getParserOutput( $parserOptions, $oldid );
2046 $parserOptions = $this->mPage->makeParserOptions( $this->getContext() );
2047 $parserOptions->setRenderReason(
'page-view' );
2048 return $parserOptions;
2058 $this->mContext = $context;
2069 return $this->mContext;
2071 wfDebug( __METHOD__ .
" called and \$mContext is null. " .
2072 "Return RequestContext::getMain()" );
2073 return RequestContext::getMain();
2083 return $this->mPage->getActionOverrides();
2086 private function getMissingRevisionMsg(
int $oldid ):
Message {
2090 $context = $this->getContext();
2091 $revRecord = $this->archivedRevisionLookup->getArchivedRevisionRecord(
null, $oldid );
2094 $revRecord->userCan(
2095 RevisionRecord::DELETED_TEXT,
2096 $context->getAuthority()
2098 $context->getAuthority()->isAllowedAny(
'deletedtext',
'undelete' )
2100 return $context->msg(
2101 'missing-revision-permission',
2103 $revRecord->getTimestamp(),
2104 Title::newFromPageIdentity( $revRecord->getPage() )->getPrefixedDBkey()
2107 return $context->msg(
'missing-revision', $oldid );
2112class_alias( Article::class,
'Article' );
const SCHEMA_COMPAT_READ_OLD
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
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.
if(!defined('MW_SETUP_CALLBACK'))
Group all the pieces relevant to the context of a request into one instance.
The HTML user interface for page editing.
A class containing constants representing the names of configuration variables.
const UseFileCache
Name constant for the UseFileCache setting, for use with Config::get()
const EnableEditRecovery
Name constant for the EnableEditRecovery setting, for use with Config::get()
const EnableProtectionIndicators
Name constant for the EnableProtectionIndicators setting, for use with Config::get()
This is one of the Core classes and should be read at least once by any new developers.
addSubtitle( $str)
Add $str to the subtitle.
addModuleStyles( $modules)
Load the styles of one or more style-only ResourceLoader modules on this page.
Legacy class representing an editable page and handling UI for some page actions.
render()
Handle action=render.
static formatRobotPolicy( $policy)
Converts a String robot policy into an associative array, to allow merging of several policies using ...
static purgePatrolFooterCache( $articleID)
Purge the cache used to check if it is worth showing the patrol footer For example,...
static newFromWikiPage(WikiPage $page, IContextSource $context)
Create an Article object of the appropriate class for the given page.
showNamespaceHeader()
Show a header specific to the namespace currently being viewed, like [[MediaWiki:Talkpagetext]].
showViewFooter()
Show the footer section of an ordinary page view.
IConnectionProvider $dbProvider
int null $mOldId
The oldid of the article that was requested to be shown, 0 for the current revision.
showPatrolFooter()
If patrol is possible, output a patrol UI box.
setOldSubtitle( $oldid=0)
Generate the navigation links when browsing through an article revisions It shows the information as:...
Title null $mRedirectedFrom
Title from which we were redirected here, if any.
setContext( $context)
Sets the context this Article is executed in.
getParserOutput( $oldid=null, ?UserIdentity $user=null)
Lightweight method to get the parser output for a page, checking the parser cache and so on.
bool $viewIsRenderAction
Whether render() was called.
getRedirectedFrom()
Get the page this view was redirected from.
showProtectionIndicator()
Show a lock icon above the article body if the page is protected.
view()
This is the default action of the index.php entry point: just view the page of the given title.
getRevIdFetched()
Use this to fetch the rev ID used on page views.
string false $mRedirectUrl
URL to redirect to or false if none.
isCurrent()
Returns true if the currently-referenced revision is the current edit to this page (and it exists).
static newFromID( $id)
Constructor from a page id.
tryFileCache()
checkLastModified returns true if it has taken care of all output to the client that is necessary for...
showRedirectedFromHeader()
If this request is a redirect view, send "redirected from" subtitle to the output.
getPage()
Get the WikiPage object of this instance.
protect()
action=protect handler
ParserOutput null false $mParserOutput
The ParserOutput generated for viewing the page, initialized by view().
fetchRevisionRecord()
Fetches the revision to work on.
DatabaseBlockStore $blockStore
IContextSource null $mContext
The context this Article is executed in.
RestrictionStore $restrictionStore
LinkRenderer $linkRenderer
showDeletedRevisionHeader()
If the revision requested for view is deleted, check permissions.
getTitle()
Get the title object of the article.
showDiffPage()
Show a diff page according to current request variables.
getActionOverrides()
Call to WikiPage function for backwards compatibility.
WikiPage $mPage
The WikiPage object of this instance.
isFileCacheable( $mode=HTMLFileCache::MODE_NORMAL)
Check if the page can be cached.
setRedirectedFrom(Title $from)
Tell the page view functions that this view was redirected from another page on the wiki.
adjustDisplayTitle(ParserOutput $pOutput)
Adjust title for pages with displaytitle, -{T|}- or language conversion.
showMissingArticle()
Show the error text for a missing article.
getRobotPolicy( $action, ?ParserOutput $pOutput=null)
Get the robot policy to be used for the current view.
unprotect()
action=unprotect handler (alias)
getContext()
Gets the context this Article is executed in.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
__construct(Title $title, $oldId=null)
getOldIDFromRequest()
Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect.
static getRedirectHeaderHtml(Language $lang, Title $target, $forceKnown=false)
Return the HTML for the top of a redirect page.
getParserOptions()
Get parser options suitable for rendering the primary article wikitext.
static newFromTitle( $title, IContextSource $context)
Create an Article object of the appropriate class for the given page.
Special handling for category description pages.
Rendering of file description pages.
Handles the page protection UI and backend.
Service for creating WikiPage objects.
Base representation for an editable wiki page.
getTitle()
Get the title object of the article.
fatal( $message,... $parameters)
Add an error and set OK to false, indicating that the operation as a whole was fatal.
Interface for objects which can provide a MediaWiki context on request.
Interface for type hinting (accepts WikiPage, Article, ImagePage, CategoryPage)