25use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
47 use ProtectedHookAccessorTrait;
160 $this->mOldId = $oldId;
163 $services = MediaWikiServices::getInstance();
164 $this->linkRenderer = $services->getLinkRenderer();
165 $this->permManager = $services->getPermissionManager();
166 $this->revisionStore = $services->getRevisionStore();
183 $t = Title::newFromID( $id );
184 return $t ==
null ? null :
new static(
$t );
201 Hooks::runner()->onArticleFromTitle(
$title, $page, $context );
203 switch (
$title->getNamespace() ) {
214 $page->setContext( $context );
227 $article = self::newFromTitle( $page->
getTitle(), $context );
228 $article->mPage = $page;
238 return $this->mRedirectedFrom;
247 $this->mRedirectedFrom = $from;
256 return $this->mPage->getTitle();
273 $this->mContentLoaded =
false;
275 $this->mRedirectedFrom =
null; #
Title object if set
276 $this->mRevIdFetched = 0;
277 $this->mRedirectUrl =
false;
278 $this->mRevisionRecord =
null;
279 $this->mContentObject =
null;
280 $this->fetchResult =
null;
284 $this->mPage->clear();
305 if ( $this->mPage->getId() === 0 ) {
321 # If this is a MediaWiki:x message, then load the messages
322 # and return the message value for x.
324 $text = $this->
getTitle()->getDefaultMessageText();
325 if ( $text ===
false ) {
331 $message = $this->
getContext()->getUser()->isLoggedIn() ?
'noarticletext' :
'noarticletextanon';
361 if ( $this->mOldId ===
null ) {
365 return $this->mOldId;
374 $this->mRedirectUrl =
false;
377 $oldid = $request->getIntOrNull(
'oldid' );
379 if ( $oldid ===
null ) {
383 if ( $oldid !== 0 ) {
384 # Load the given revision and check whether the page is another one.
385 # In that case, update this instance to reflect the change.
386 if ( $oldid === $this->mPage->getLatest() ) {
387 $this->mRevisionRecord = $this->mPage->getRevisionRecord();
389 $this->mRevisionRecord = $this->revisionStore->getRevisionById( $oldid );
390 if ( $this->mRevisionRecord !==
null ) {
391 $revPageId = $this->mRevisionRecord->getPageId();
393 if ( $this->mPage->getId() != $revPageId ) {
394 $function = get_class( $this->mPage ) .
'::newFromID';
395 $this->mPage = $function( $revPageId );
401 $oldRev = $this->mRevisionRecord;
402 if ( $request->getVal(
'direction' ) ==
'next' ) {
405 $nextRev = $this->revisionStore->getNextRevision( $oldRev );
407 $nextid = $nextRev->getId();
412 $this->mRevisionRecord =
null;
414 $this->mRedirectUrl = $this->
getTitle()->getFullURL(
'redirect=no' );
416 } elseif ( $request->getVal(
'direction' ) ==
'prev' ) {
419 $prevRev = $this->revisionStore->getPreviousRevision( $oldRev );
421 $previd = $prevRev->getId();
426 $this->mRevisionRecord =
null;
430 $this->mRevIdFetched = $this->mRevisionRecord ? $this->mRevisionRecord->getId() : 0;
449 if ( !$this->mContentLoaded ) {
453 return $this->mContentObject;
468 if ( $this->fetchResult ) {
469 return $this->mRevisionRecord;
472 $this->mContentLoaded =
true;
473 $this->mContentObject =
null;
478 if ( !$this->mRevisionRecord ) {
480 $this->mRevisionRecord = $this->mPage->getRevisionRecord();
482 if ( !$this->mRevisionRecord ) {
483 wfDebug( __METHOD__ .
" failed to find page data for title " .
484 $this->
getTitle()->getPrefixedText() );
487 $this->fetchResult = Status::newFatal(
'noarticletext' );
492 $this->mRevisionRecord = $this->revisionStore->getRevisionById( $oldid );
494 if ( !$this->mRevisionRecord ) {
495 wfDebug( __METHOD__ .
" failed to load revision, rev_id $oldid" );
497 $this->fetchResult = Status::newFatal(
'missing-revision', $oldid );
504 $this->mRevIdFetched = $this->mRevisionRecord->getId();
505 $this->fetchResult = Status::newGood( $this->mRevisionRecord );
507 if ( !RevisionRecord::userCanBitfield(
508 $this->mRevisionRecord->getVisibility(),
509 RevisionRecord::DELETED_TEXT,
510 $this->getContext()->getUser()
512 wfDebug( __METHOD__ .
" failed to retrieve content of revision " .
513 $this->mRevisionRecord->getId() );
516 $this->fetchResult = Status::newFatal(
'rev-deleted-text-permission' );
522 $this->mContentObject = $this->mRevisionRecord->getContent(
524 RevisionRecord::FOR_THIS_USER,
528 return $this->mRevisionRecord;
538 if ( !$this->fetchResult || $this->fetchResult->isOK() ) {
561 $rev->setContent( SlotRecord::MAIN, $override );
563 $this->mRevisionRecord = $rev;
566 $this->mContentObject = $override;
575 # If no oldid, this is the current version.
580 return $this->mPage->exists() &&
581 $this->mRevisionRecord &&
582 $this->mRevisionRecord->isCurrent();
600 return $revRecord ?
new Revision( $revRecord ) :
null;
612 if ( $this->fetchResult && $this->fetchResult->isOK() ) {
613 return $this->fetchResult->value->getId();
615 return $this->mPage->getLatest();
626 # Get variables from query string
627 # As side effect this will load the revision and update the title
628 # in a revision ID is passed in the request, so this should remain
629 # the first call of this method even if $oldid is used way below.
633 # Another whitelist check in case getOldID() is altering the title
634 $permErrors = $this->permManager->getPermissionErrors(
639 if ( count( $permErrors ) ) {
640 wfDebug( __METHOD__ .
": denied on secondary read check" );
644 $outputPage = $this->
getContext()->getOutput();
645 # getOldID() may as well want us to redirect somewhere else
646 if ( $this->mRedirectUrl ) {
647 $outputPage->redirect( $this->mRedirectUrl );
648 wfDebug( __METHOD__ .
": redirecting due to oldid" );
653 # If we got diff in the query, we want to see a diff page instead of the article.
654 if ( $this->
getContext()->getRequest()->getCheck(
'diff' ) ) {
655 wfDebug( __METHOD__ .
": showing diff page" );
661 # Set page title (may be overridden by DISPLAYTITLE)
662 $outputPage->setPageTitle( $this->
getTitle()->getPrefixedText() );
664 $outputPage->setArticleFlag(
true );
665 # Allow frames by default
666 $outputPage->allowClickjacking();
668 $parserCache = MediaWikiServices::getInstance()->getParserCache();
672 # Render printable version, use printable version cache
673 if ( $outputPage->isPrintable() ) {
674 $parserOptions->setIsPrintable(
true );
675 $poOptions[
'enableSectionEditLinks'] =
false;
676 $outputPage->prependHTML(
678 $outputPage->msg(
'printableversion-deprecated-warning' )->escaped()
681 } elseif ( $this->viewIsRenderAction || !$this->
isCurrent() ||
682 !$this->permManager->quickUserCan(
'edit', $user, $this->getTitle() )
684 $poOptions[
'enableSectionEditLinks'] =
false;
687 # Try client and file cache
688 if ( $oldid === 0 && $this->mPage->checkTouched() ) {
689 # Try to stream the output from file cache
691 wfDebug( __METHOD__ .
": done file cache" );
692 # tell wgOut that output is taken care of
693 $outputPage->disable();
694 $this->mPage->doViewUpdates( $user, $oldid );
700 # Should the parser cache be used?
701 $useParserCache = $this->mPage->shouldCheckParserCache( $parserOptions, $oldid );
702 wfDebug(
'Article::view using parser cache: ' . ( $useParserCache ?
'yes' :
'no' ) );
703 if ( $user->getStubThreshold() ) {
704 MediaWikiServices::getInstance()->getStatsdDataFactory()->increment(
'pcache_miss_stub' );
710 # Iterate through the possible ways of constructing the output text.
711 # Keep going until $outputDone is set, or we run out of things to do.
714 $this->mParserOutput =
false;
716 while ( !$outputDone && ++$pass ) {
719 $this->getHookRunner()->onArticleViewHeader( $this, $outputDone, $useParserCache );
722 # Early abort if the page doesn't exist
723 if ( !$this->mPage->exists() ) {
724 wfDebug( __METHOD__ .
": showing missing article" );
726 $this->mPage->doViewUpdates( $user );
730 # Try the parser cache
731 if ( $useParserCache ) {
732 $this->mParserOutput = $parserCache->get( $this->
getPage(), $parserOptions );
734 if ( $this->mParserOutput !==
false ) {
736 wfDebug( __METHOD__ .
": showing parser cache contents for current rev permalink" );
739 wfDebug( __METHOD__ .
": showing parser cache contents" );
741 $outputPage->addParserOutput( $this->mParserOutput, $poOptions );
742 # Ensure that UI elements requiring revision ID have
743 # the correct version information.
744 $outputPage->setRevisionId( $this->mPage->getLatest() );
745 # Preload timestamp to avoid a DB hit
746 $cachedTimestamp = $this->mParserOutput->getTimestamp();
747 if ( $cachedTimestamp !==
null ) {
748 $outputPage->setRevisionTimestamp( $cachedTimestamp );
749 $this->mPage->setTimestamp( $cachedTimestamp );
756 # Are we looking at an old revision
758 if ( $oldid && $this->fetchResult->isOK() ) {
762 wfDebug( __METHOD__ .
": cannot view deleted revision" );
767 # Ensure that UI elements requiring revision ID have
768 # the correct version information.
770 # Preload timestamp to avoid a DB hit
771 $outputPage->setRevisionTimestamp( $this->mPage->getTimestamp() );
773 # Pages containing custom CSS or JavaScript get special treatment
774 if ( $this->
getTitle()->isSiteConfigPage() || $this->
getTitle()->isUserConfigPage() ) {
775 $dir = $this->
getContext()->getLanguage()->getDir();
778 $outputPage->wrapWikiMsg(
779 "<div id='mw-clearyourcache' lang='$lang' dir='$dir' class='mw-content-$dir'>\n$1\n</div>",
782 } elseif ( !$this->getHookRunner()->onArticleRevisionViewCustom(
794 # Run the parse, protected by a pool counter
795 wfDebug( __METHOD__ .
": doing uncached parse" );
810 $ok = $poolArticleView->execute();
811 $error = $poolArticleView->getError();
812 $this->mParserOutput = $poolArticleView->getParserOutput() ?:
null;
814 # Cache stale ParserOutput object with a short expiry
815 if ( $poolArticleView->getIsDirty() ) {
817 $outputPage->setLastModified( $this->mParserOutput->getCacheTime() );
818 $staleReason = $poolArticleView->getIsFastStale()
819 ?
'pool contention' :
'pool overload';
820 $outputPage->addHTML(
"<!-- parser cache is expired, " .
821 "sending anyway due to $staleReason-->\n" );
829 $outputPage->clearHTML();
830 $outputPage->enableClientCache(
false );
831 $outputPage->setRobotPolicy(
'noindex,nofollow' );
833 $errortext = $error->getWikiText(
834 false,
'view-pool-error', $this->
getContext()->getLanguage()
836 $outputPage->wrapWikiTextAsInterface(
'errorbox', $errortext );
838 # Connection or timeout error
842 if ( $this->mParserOutput ) {
843 $outputPage->addParserOutput( $this->mParserOutput, $poOptions );
847 $outputPage->addSubtitle(
"<span id=\"redirectsub\">" .
848 $this->
getContext()->msg(
'redirectpagesub' )->parse() .
"</span>" );
853 # Should be unreachable, but just in case...
865 : ( $this->mParserOutput ?: null );
867 # Adjust title for main page & pages with displaytitle
872 # For the main page, overwrite the <title> element with the con-
873 # tents of 'pagetitle-view-mainpage' instead of the default (if
875 # This message always exists because it is in the i18n files
876 if ( $this->
getTitle()->isMainPage() ) {
877 $msg =
wfMessage(
'pagetitle-view-mainpage' )->inContentLanguage();
878 if ( !$msg->isDisabled() ) {
879 $outputPage->setHTMLTitle( $msg->title( $this->getTitle() )->text() );
883 # Use adaptive TTLs for CDN so delayed/failed purges are noticed less often.
884 # This could use getTouched(), but that could be scary for major template edits.
885 $outputPage->adaptCdnTTL( $this->mPage->getTimestamp(), IExpiringStore::TTL_DAY );
887 # Check for any __NOINDEX__ tags on the page using $pOutput
889 $outputPage->setIndexPolicy( $policy[
'index'] );
890 $outputPage->setFollowPolicy( $policy[
'follow'] );
893 $this->mPage->doViewUpdates( $user, $oldid );
895 # Load the postEdit module if the user just saved this revision
896 # See also EditPage::setPostEditCookie
899 $postEdit = $request->getCookie( $cookieKey );
901 # Clear the cookie. This also prevents caching of the response.
902 $request->response()->clearCookie( $cookieKey );
903 $outputPage->addJsConfigVars(
'wgPostEdit', $postEdit );
904 $outputPage->addModules(
'mediawiki.action.view.postEdit' );
927 # Adjust the title if it was set by displaytitle, -{T|}- or language conversion
929 if ( strval( $titleText ) !==
'' ) {
930 $out->setPageTitle( $titleText );
931 $out->setDisplayTitle( $titleText );
942 $diff = $request->getVal(
'diff' );
943 $rcid = $request->getVal(
'rcid' );
944 $diffOnly = $request->getBool(
'diffonly', $user->getOption(
'diffonly' ) );
945 $purge = $request->getVal(
'action' ) ==
'purge';
946 $unhide = $request->getInt(
'unhide' ) == 1;
953 $msg = $this->
getContext()->msg(
'difference-missing-revision' )
957 $this->
getContext()->getOutput()->addHTML( $msg );
961 $contentHandler = MediaWikiServices::getInstance()
962 ->getContentHandlerFactory()
964 $rev->getSlot( SlotRecord::MAIN, RevisionRecord::RAW )->getModel()
966 $de = $contentHandler->createDifferenceEngine(
974 $de->setSlotDiffOptions( [
975 'diff-type' => $request->getVal(
'diff-type' )
979 $this->mRevIdFetched = $de->getNewid();
980 $de->showDiffPage( $diffOnly );
984 list( $old, $new ) = $de->mapDiffPrevNext( $oldid, $diff );
986 $this->mPage->doViewUpdates( $user, (
int)$new );
999 $ns = $this->
getTitle()->getNamespace();
1001 # Don't index user and user talk pages for blocked users (T13443)
1003 $specificTarget =
null;
1004 $vagueTarget =
null;
1005 $titleText = $this->
getTitle()->getText();
1006 if ( IPUtils::isValid( $titleText ) ) {
1007 $vagueTarget = $titleText;
1009 $specificTarget = $titleText;
1011 if ( DatabaseBlock::newFromTarget( $specificTarget, $vagueTarget ) instanceof
DatabaseBlock ) {
1013 'index' =>
'noindex',
1014 'follow' =>
'nofollow'
1019 if ( $this->mPage->getId() === 0 || $this->getOldID() ) {
1020 # Non-articles (special pages etc), and old revisions
1022 'index' =>
'noindex',
1023 'follow' =>
'nofollow'
1025 } elseif ( $this->
getContext()->getOutput()->isPrintable() ) {
1026 # Discourage indexing of printable versions, but encourage following
1028 'index' =>
'noindex',
1029 'follow' =>
'follow'
1031 } elseif ( $this->
getContext()->getRequest()->getInt(
'curid' ) ) {
1032 # For ?curid=x urls, disallow indexing
1034 'index' =>
'noindex',
1035 'follow' =>
'follow'
1039 # Otherwise, construct the policy based on the various config variables.
1043 # Honour customised robot policies for this namespace
1044 $policy = array_merge(
1049 if ( $this->
getTitle()->canUseNoindex() && is_object( $pOutput ) && $pOutput->getIndexPolicy() ) {
1050 # __INDEX__ and __NOINDEX__ magic words, if allowed. Incorporates
1051 # a final sanity check that we have really got the parser output.
1052 $policy = array_merge(
1054 [
'index' => $pOutput->getIndexPolicy() ]
1059 # (T16900) site config can override user-defined __INDEX__ or __NOINDEX__
1060 $policy = array_merge(
1077 if ( is_array( $policy ) ) {
1079 } elseif ( !$policy ) {
1083 $policy = explode(
',', $policy );
1084 $policy = array_map(
'trim', $policy );
1087 foreach ( $policy as $var ) {
1088 if ( in_array( $var, [
'index',
'noindex' ] ) ) {
1089 $arr[
'index'] = $var;
1090 } elseif ( in_array( $var, [
'follow',
'nofollow' ] ) ) {
1091 $arr[
'follow'] = $var;
1109 $outputPage = $context->getOutput();
1110 $request = $context->getRequest();
1111 $rdfrom = $request->getVal(
'rdfrom' );
1114 $query = $request->getValues();
1115 unset( $query[
'rdfrom'] );
1116 unset( $query[
'title'] );
1119 $query[
'redirect'] =
'no';
1121 $redirectTargetUrl = $this->
getTitle()->getLinkURL( $query );
1123 if ( isset( $this->mRedirectedFrom ) ) {
1126 if ( $this->getHookRunner()->onArticleViewRedirect( $this ) ) {
1127 $redir = $this->linkRenderer->makeKnownLink(
1128 $this->mRedirectedFrom,
1131 [
'redirect' =>
'no' ]
1134 $outputPage->addSubtitle(
"<span class=\"mw-redirectedfrom\">" .
1135 $context->msg(
'redirectedfrom' )->rawParams( $redir )->parse()
1140 $outputPage->addJsConfigVars( [
1141 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
1143 $outputPage->addModules(
'mediawiki.action.view.redirect' );
1146 $outputPage->setCanonicalUrl( $this->
getTitle()->getCanonicalURL() );
1149 $outputPage->setRedirectedFrom( $this->mRedirectedFrom );
1153 } elseif ( $rdfrom ) {
1158 $outputPage->addSubtitle(
"<span class=\"mw-redirectedfrom\">" .
1159 $context->msg(
'redirectedfrom' )->rawParams( $redir )->parse()
1163 $outputPage->addJsConfigVars( [
1164 'wgInternalRedirectTargetUrl' => $redirectTargetUrl,
1166 $outputPage->addModules(
'mediawiki.action.view.redirect' );
1180 if ( $this->
getTitle()->isTalkPage() && !
wfMessage(
'talkpageheader' )->isDisabled() ) {
1181 $this->
getContext()->getOutput()->wrapWikiMsg(
1182 "<div class=\"mw-talkpageheader\">\n$1\n</div>",
1183 [
'talkpageheader' ]
1192 # check if we're displaying a [[User talk:x.x.x.x]] anonymous talk page
1194 && IPUtils::isValid( $this->
getTitle()->getText() )
1196 $this->
getContext()->getOutput()->addWikiMsg(
'anontalkpagetext' );
1202 $this->getHookRunner()->onArticleViewFooter( $this, $patrolFooterShown );
1219 if ( !$this->getHookRunner()->onArticleShowPatrolFooter( $this ) ) {
1223 $outputPage = $this->
getContext()->getOutput();
1228 if ( !$this->permManager->quickUserCan(
'patrol', $user,
$title )
1236 if ( $this->mRevisionRecord
1237 && !RecentChange::isInRCLifespan( $this->mRevisionRecord->getTimestamp(), 21600 )
1245 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1246 $key =
$cache->makeKey(
'unpatrollable-page',
$title->getArticleID() );
1247 if (
$cache->get( $key ) ) {
1252 $oldestRevisionTimestamp =
$dbr->selectField(
1254 'MIN( rev_timestamp )',
1255 [
'rev_page' =>
$title->getArticleID() ],
1264 $recentPageCreation =
false;
1265 if ( $oldestRevisionTimestamp
1266 && RecentChange::isInRCLifespan( $oldestRevisionTimestamp, 21600 )
1269 $recentPageCreation =
true;
1270 $rc = RecentChange::newFromConds(
1273 'rc_timestamp' => $oldestRevisionTimestamp,
1274 'rc_namespace' =>
$title->getNamespace(),
1275 'rc_cur_id' =>
$title->getArticleID()
1281 $markPatrolledMsg =
wfMessage(
'markaspatrolledtext' );
1289 $recentFileUpload =
false;
1293 $newestUploadTimestamp =
$dbr->selectField(
1295 'MAX( img_timestamp )',
1296 [
'img_name' =>
$title->getDBkey() ],
1299 if ( $newestUploadTimestamp
1300 && RecentChange::isInRCLifespan( $newestUploadTimestamp, 21600 )
1303 $recentFileUpload =
true;
1304 $rc = RecentChange::newFromConds(
1307 'rc_log_type' =>
'upload',
1308 'rc_timestamp' => $newestUploadTimestamp,
1310 'rc_cur_id' =>
$title->getArticleID()
1316 $markPatrolledMsg =
wfMessage(
'markaspatrolledtext-file' );
1321 if ( !$recentPageCreation && !$recentFileUpload ) {
1326 $cache->set( $key,
'1' );
1338 if ( $rc->getAttribute(
'rc_patrolled' ) ) {
1343 $cache->set( $key,
'1' );
1348 if ( $rc->getPerformer()->equals( $user ) ) {
1354 $outputPage->preventClickjacking();
1355 if ( $this->permManager->userHasRight( $user,
'writeapi' ) ) {
1356 $outputPage->addModules(
'mediawiki.misc-authed-curate' );
1359 $link = $this->linkRenderer->makeKnownLink(
1361 $markPatrolledMsg->text(),
1364 'action' =>
'markpatrolled',
1365 'rcid' => $rc->getAttribute(
'rc_id' ),
1369 $outputPage->addHTML(
1370 "<div class='patrollink' data-mw='interface'>" .
1371 wfMessage(
'markaspatrolledlink' )->rawParams( $link )->escaped() .
1385 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1386 $cache->delete(
$cache->makeKey(
'unpatrollable-page', $articleID ) );
1396 $outputPage = $this->
getContext()->getOutput();
1398 $validUserPage =
false;
1402 $services = MediaWikiServices::getInstance();
1404 $contextUser = $this->
getContext()->getUser();
1406 # Show info in user (talk) namespace. Does the user exist? Is he blocked?
1410 $rootPart = explode(
'/',
$title->getText() )[0];
1411 $user = User::newFromName( $rootPart,
false );
1412 $ip = User::isIP( $rootPart );
1413 $block = DatabaseBlock::newFromTarget( $user, $user );
1415 if ( $user && $user->isLoggedIn() && $user->isHidden() &&
1416 !$services->getPermissionManager()
1417 ->userHasRight( $contextUser,
'hideuser' )
1423 if ( !( $user && $user->isLoggedIn() ) && !$ip ) { #
User does not exist
1424 $outputPage->wrapWikiMsg(
"<div class=\"mw-userpage-userdoesnotexist error\">\n\$1\n</div>",
1428 $block->getType() != DatabaseBlock::TYPE_AUTO &&
1429 ( $block->isSitewide() || $user->isBlockedFrom(
$title ) )
1433 LogEventsList::showLogExtract(
1436 $services->getNamespaceInfo()->getCanonicalName(
NS_USER ) .
':' .
1437 $block->getTarget(),
1441 'showIfEmpty' =>
false,
1443 'blocked-notice-logextract',
1444 $user->getName() # Support GENDER in notice
1448 $validUserPage = !
$title->isSubpage();
1450 $validUserPage = !
$title->isSubpage();
1454 $this->getHookRunner()->onShowMissingArticle( $this );
1456 # Show delete and move logs if there were any such events.
1457 # The logging query can DOS the site when bots/crawlers cause 404 floods,
1458 # so be careful showing this. 404 pages must be cheap as they are hard to cache.
1459 $dbCache = ObjectCache::getInstance(
'db-replicated' );
1460 $key = $dbCache->makeKey(
'page-recent-delete', md5(
$title->getPrefixedText() ) );
1461 $loggedIn = $contextUser->isLoggedIn();
1462 $sessionExists = $this->
getContext()->getRequest()->getSession()->isPersistent();
1464 if ( $loggedIn || $dbCache->get( $key ) || $sessionExists ) {
1465 $logTypes = [
'delete',
'move',
'protect' ];
1469 $conds = [
'log_action != ' .
$dbr->addQuotes(
'revision' ) ];
1471 $this->getHookRunner()->onArticle__MissingArticleConditions( $conds, $logTypes );
1472 LogEventsList::showLogExtract(
1480 'showIfEmpty' =>
false,
1481 'msgKey' => [ $loggedIn || $sessionExists
1482 ?
'moveddeleted-notice'
1483 :
'moveddeleted-notice-recent'
1489 if ( !$this->mPage->hasViewableContent() &&
$wgSend404Code && !$validUserPage ) {
1492 $this->
getContext()->getRequest()->response()->statusHeader( 404 );
1497 $outputPage->setIndexPolicy( $policy[
'index'] );
1498 $outputPage->setFollowPolicy( $policy[
'follow'] );
1500 $hookResult = $this->getHookRunner()->onBeforeDisplayNoArticleText( $this );
1502 if ( !$hookResult ) {
1506 # Show error message
1508 $pm = $this->permManager;
1511 $parserOptions = ParserOptions::newCanonical(
'canonical' );
1515 $text =
wfMessage(
'missing-revision', $oldid )->plain();
1516 } elseif ( $pm->quickUserCan(
'create', $contextUser,
$title ) &&
1517 $pm->quickUserCan(
'edit', $contextUser,
$title )
1519 $message = $loggedIn ?
'noarticletext' :
'noarticletextanon';
1522 $text =
wfMessage(
'noarticletext-nopermission' )->plain();
1525 $dir = $this->
getContext()->getLanguage()->getDir();
1527 $outputPage->addWikiTextAsInterface( Xml::openElement(
'div', [
1528 'class' =>
"noarticletext mw-content-$dir",
1531 ] ) .
"\n$text\n</div>" );
1542 if ( !$this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
1547 $outputPage = $this->
getContext()->getOutput();
1550 if ( !RevisionRecord::userCanBitfield(
1551 $this->mRevisionRecord->getVisibility(),
1552 RevisionRecord::DELETED_TEXT,
1555 $outputPage->wrapWikiMsg(
"<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1556 'rev-deleted-text-permission' );
1560 } elseif ( $this->
getContext()->getRequest()->getInt(
'unhide' ) != 1 ) {
1561 # Give explanation and add a link to view the revision...
1562 $oldid = intval( $this->
getOldID() );
1563 $link = $this->
getTitle()->getFullURL(
"oldid={$oldid}&unhide=1" );
1564 $msg = $this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ?
1565 'rev-suppressed-text-unhide' :
'rev-deleted-text-unhide';
1566 $outputPage->wrapWikiMsg(
"<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1572 $msg = $this->mRevisionRecord->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ?
1573 'rev-suppressed-text-view' :
'rev-deleted-text-view';
1574 $outputPage->wrapWikiMsg(
"<div class='mw-warning plainlinks'>\n$1\n</div>\n", $msg );
1589 if ( !$this->getHookRunner()->onDisplayOldSubtitle( $this, $oldid ) ) {
1594 $unhide = $context->getRequest()->getInt(
'unhide' ) == 1;
1596 # Cascade unhide param in links for easy deletion browsing
1599 $extraParams[
'unhide'] = 1;
1602 if ( $this->mRevisionRecord && $this->mRevisionRecord->getId() === $oldid ) {
1603 $revisionRecord = $this->mRevisionRecord;
1605 $revisionRecord = $this->revisionStore->getRevisionById( $oldid );
1608 $timestamp = $revisionRecord->getTimestamp();
1610 $current = ( $oldid == $this->mPage->getLatest() );
1611 $language = $context->getLanguage();
1612 $user = $context->getUser();
1614 $td = $language->userTimeAndDate( $timestamp, $user );
1615 $tddate = $language->userDate( $timestamp, $user );
1616 $tdtime = $language->userTime( $timestamp, $user );
1618 # Show user links if allowed to see them. If hidden, then show them only if requested...
1621 $infomsg = $current && !$context->msg(
'revision-info-current' )->isDisabled()
1622 ?
'revision-info-current'
1625 $outputPage = $context->getOutput();
1626 $revisionUser = $revisionRecord->getUser();
1627 $revisionInfo =
"<div id=\"mw-{$infomsg}\">" .
1628 $context->msg( $infomsg, $td )
1629 ->rawParams( $userlinks )
1631 $revisionRecord->getId(),
1634 $revisionUser ? $revisionUser->getName() :
''
1645 ? $context->msg(
'currentrevisionlink' )->escaped()
1646 : $this->linkRenderer->makeKnownLink(
1648 $context->msg(
'currentrevisionlink' )->text(),
1653 ? $context->msg(
'diff' )->escaped()
1654 : $this->linkRenderer->makeKnownLink(
1656 $context->msg(
'diff' )->text(),
1663 $prevExist = (bool)$this->revisionStore->getPreviousRevision( $revisionRecord );
1664 $prevlink = $prevExist
1665 ? $this->linkRenderer->makeKnownLink(
1667 $context->msg(
'previousrevision' )->text(),
1670 'direction' =>
'prev',
1674 : $context->msg(
'previousrevision' )->escaped();
1675 $prevdiff = $prevExist
1676 ? $this->linkRenderer->makeKnownLink(
1678 $context->msg(
'diff' )->text(),
1685 : $context->msg(
'diff' )->escaped();
1686 $nextlink = $current
1687 ? $context->msg(
'nextrevision' )->escaped()
1688 : $this->linkRenderer->makeKnownLink(
1690 $context->msg(
'nextrevision' )->text(),
1693 'direction' =>
'next',
1697 $nextdiff = $current
1698 ? $context->msg(
'diff' )->escaped()
1699 : $this->linkRenderer->makeKnownLink(
1701 $context->msg(
'diff' )->text(),
1714 if ( $cdel !==
'' ) {
1719 $outputPage->addSubtitle(
"<div class=\"mw-revision warningbox\">" . $revisionInfo .
1720 "<div id=\"mw-revision-nav\">" . $cdel .
1721 $context->msg(
'revision-nav' )->rawParams(
1722 $prevdiff, $prevlink, $lnk, $curdiff, $nextlink, $nextdiff
1723 )->escaped() .
"</div></div>" );
1739 public function viewRedirect( $target, $appendSubtitle =
true, $forceKnown =
false ) {
1742 if ( $appendSubtitle ) {
1743 $out->addSubtitle(
wfMessage(
'redirectpagesub' ) );
1745 $out->addModuleStyles(
'mediawiki.action.view.redirectPage' );
1746 return static::getRedirectHeaderHtml(
$lang, $target, $forceKnown );
1762 if ( !is_array( $target ) ) {
1763 $target = [ $target ];
1766 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
1768 $html =
'<ul class="redirectText">';
1770 foreach ( $target as
$title ) {
1771 if ( $forceKnown ) {
1777 $title->isRedirect() ? [
'redirect' =>
'no' ] : []
1785 $title->isRedirect() ? [
'redirect' =>
'no' ] : []
1788 $html .=
'<li>' . $link .
'</li>';
1792 $redirectToText =
wfMessage(
'redirectto' )->inLanguage(
$lang )->escaped();
1794 return '<div class="redirectMsg">' .
1795 '<p>' . $redirectToText .
'</p>' .
1810 'namespace-' . $this->
getTitle()->getNamespace() .
'-helppage'
1814 if ( !$msg->isDisabled() ) {
1815 $helpUrl = Skin::makeUrl( $msg->plain() );
1816 $out->addHelpLink( $helpUrl,
true );
1818 $out->addHelpLink( $to, $overrideBaseUrl );
1826 $this->
getContext()->getRequest()->response()->header(
'X-Robots-Tag: noindex' );
1827 $this->
getContext()->getOutput()->setArticleBodyOnly(
true );
1829 $this->viewIsRenderAction =
true;
1851 public function delete() {
1852 # This code desperately needs to be totally rewritten
1856 $user = $context->getUser();
1857 $request = $context->getRequest();
1860 $permissionErrors = $this->permManager->getPermissionErrors(
'delete', $user,
$title );
1861 if ( count( $permissionErrors ) ) {
1865 # Read-only check...
1870 # Better double-check that it hasn't been deleted yet!
1871 $this->mPage->loadPageData(
1872 $request->wasPosted() ? WikiPage::READ_LATEST : WikiPage::READ_NORMAL
1874 if ( !$this->mPage->exists() ) {
1875 $deleteLogPage =
new LogPage(
'delete' );
1876 $outputPage = $context->getOutput();
1877 $outputPage->setPageTitle( $context->msg(
'cannotdelete-title',
$title->getPrefixedText() ) );
1878 $outputPage->wrapWikiMsg(
"<div class=\"error mw-error-cannotdelete\">\n$1\n</div>",
1881 $outputPage->addHTML(
1882 Xml::element(
'h2',
null, $deleteLogPage->getName()->text() )
1884 LogEventsList::showLogExtract(
1893 $deleteReasonList = $request->getText(
'wpDeleteReasonList',
'other' );
1894 $deleteReason = $request->getText(
'wpReason' );
1896 if ( $deleteReasonList ==
'other' ) {
1897 $reason = $deleteReason;
1898 } elseif ( $deleteReason !=
'' ) {
1900 $colonseparator =
wfMessage(
'colon-separator' )->inContentLanguage()->text();
1901 $reason = $deleteReasonList . $colonseparator . $deleteReason;
1903 $reason = $deleteReasonList;
1906 if ( $request->wasPosted() && $user->matchEditToken( $request->getVal(
'wpEditToken' ),
1907 [
'delete', $this->getTitle()->getPrefixedText() ] )
1909 # Flag to hide all contents of the archived revisions
1911 $suppress = $request->getCheck(
'wpSuppress' ) &&
1912 $this->permManager->userHasRight( $user,
'suppressrevision' );
1914 $this->
doDelete( $reason, $suppress );
1922 $hasHistory =
false;
1926 ->getAutoDeleteReason( $hasHistory );
1927 }
catch ( Exception $e ) {
1928 # if a page is horribly broken, we still want to be able to
1929 # delete it. So be lenient about errors here.
1930 wfDebug(
"Error while building auto delete summary: $e" );
1936 if ( $hasHistory ) {
1945 $revisions = $edits = (int)
$dbr->selectField(
1948 [
'rev_page' =>
$title->getArticleID() ],
1953 $context->getOutput()->addHTML(
1954 '<strong class="mw-delete-warning-revisions">' .
1955 $context->msg(
'historywarning' )->numParams( $revisions )->parse() .
1956 $context->msg(
'word-separator' )->escaped() . $this->linkRenderer->makeKnownLink(
1958 $context->msg(
'history' )->text(),
1960 [
'action' =>
'history' ] ) .
1964 if (
$title->isBigDeletion() ) {
1966 $context->getOutput()->wrapWikiMsg(
"<div class='error'>\n$1\n</div>\n",
1968 'delete-warning-toobig',
1984 wfDebug(
"Article::confirmDelete" );
1988 $outputPage = $ctx->getOutput();
1989 $outputPage->setPageTitle(
wfMessage(
'delete-confirm',
$title->getPrefixedText() ) );
1990 $outputPage->addBacklinkSubtitle(
$title );
1991 $outputPage->setRobotPolicy(
'noindex,nofollow' );
1992 $outputPage->addModules(
'mediawiki.action.delete' );
1994 $backlinkCache =
$title->getBacklinkCache();
1995 if ( $backlinkCache->hasLinks(
'pagelinks' ) || $backlinkCache->hasLinks(
'templatelinks' ) ) {
1996 $outputPage->wrapWikiMsg(
"<div class='mw-warning plainlinks'>\n$1\n</div>\n",
1997 'deleting-backlinks-warning' );
2000 $subpageQueryLimit = 51;
2001 $subpages =
$title->getSubpages( $subpageQueryLimit );
2002 $subpageCount = count( $subpages );
2003 if ( $subpageCount > 0 ) {
2004 $outputPage->wrapWikiMsg(
"<div class='mw-warning plainlinks'>\n$1\n</div>\n",
2007 $outputPage->addWikiMsg(
'confirmdeletetext' );
2009 $this->getHookRunner()->onArticleConfirmDelete( $this, $outputPage, $reason );
2012 $checkWatch = $user->getBoolOption(
'watchdeletion' ) || $user->isWatched(
$title );
2014 $outputPage->enableOOUI();
2018 $suppressAllowed = $this->permManager->userHasRight( $user,
'suppressrevision' );
2019 $dropDownReason = $ctx->msg(
'deletereason-dropdown' )->inContentLanguage()->text();
2021 if ( $suppressAllowed ) {
2022 $dropDownReason .=
"\n" . $ctx->msg(
'deletereason-dropdown-suppress' )
2023 ->inContentLanguage()->text();
2026 $options = Xml::listDropDownOptions(
2028 [
'other' => $ctx->msg(
'deletereasonotherlist' )->inContentLanguage()->text() ]
2030 $options = Xml::listDropDownOptionsOoui( $options );
2032 $fields[] =
new OOUI\FieldLayout(
2033 new OOUI\DropdownInputWidget( [
2034 'name' =>
'wpDeleteReasonList',
2035 'inputId' =>
'wpDeleteReasonList',
2037 'infusable' =>
true,
2039 'options' => $options
2042 'label' => $ctx->msg(
'deletecomment' )->text(),
2050 $fields[] =
new OOUI\FieldLayout(
2051 new OOUI\TextInputWidget( [
2052 'name' =>
'wpReason',
2053 'inputId' =>
'wpReason',
2055 'maxLength' => CommentStore::COMMENT_CHARACTER_LIMIT,
2056 'infusable' =>
true,
2058 'autofocus' =>
true,
2061 'label' => $ctx->msg(
'deleteotherreason' )->text(),
2066 if ( $user->isLoggedIn() ) {
2067 $fields[] =
new OOUI\FieldLayout(
2068 new OOUI\CheckboxInputWidget( [
2069 'name' =>
'wpWatch',
2070 'inputId' =>
'wpWatch',
2072 'selected' => $checkWatch,
2075 'label' => $ctx->msg(
'watchthis' )->text(),
2076 'align' =>
'inline',
2077 'infusable' =>
true,
2081 if ( $suppressAllowed ) {
2082 $fields[] =
new OOUI\FieldLayout(
2083 new OOUI\CheckboxInputWidget( [
2084 'name' =>
'wpSuppress',
2085 'inputId' =>
'wpSuppress',
2089 'label' => $ctx->msg(
'revdelete-suppress' )->text(),
2090 'align' =>
'inline',
2091 'infusable' =>
true,
2096 $fields[] =
new OOUI\FieldLayout(
2097 new OOUI\ButtonInputWidget( [
2098 'name' =>
'wpConfirmB',
2099 'inputId' =>
'wpConfirmB',
2101 'value' => $ctx->msg(
'deletepage' )->text(),
2102 'label' => $ctx->msg(
'deletepage' )->text(),
2103 'flags' => [
'primary',
'destructive' ],
2111 $fieldset =
new OOUI\FieldsetLayout( [
2112 'label' => $ctx->msg(
'delete-legend' )->text(),
2113 'id' =>
'mw-delete-table',
2117 $form =
new OOUI\FormLayout( [
2119 'action' =>
$title->getLocalURL(
'action=delete' ),
2120 'id' =>
'deleteconfirm',
2122 $form->appendContent(
2124 new OOUI\HtmlSnippet(
2125 Html::hidden(
'wpEditToken', $user->getEditToken( [
'delete',
$title->getPrefixedText() ] ) )
2129 $outputPage->addHTML(
2130 new OOUI\PanelLayout( [
2131 'classes' => [
'deletepage-wrapper' ],
2132 'expanded' =>
false,
2139 if ( $this->permManager->userHasRight( $user,
'editinterface' ) ) {
2141 if ( $suppressAllowed ) {
2142 $link .= $this->linkRenderer->makeKnownLink(
2143 $ctx->msg(
'deletereason-dropdown-suppress' )->inContentLanguage()->getTitle(),
2144 $ctx->msg(
'delete-edit-reasonlist-suppress' )->text(),
2146 [
'action' =>
'edit' ]
2148 $link .= $ctx->msg(
'pipe-separator' )->escaped();
2150 $link .= $this->linkRenderer->makeKnownLink(
2151 $ctx->msg(
'deletereason-dropdown' )->inContentLanguage()->getTitle(),
2152 $ctx->msg(
'delete-edit-reasonlist' )->text(),
2154 [
'action' =>
'edit' ]
2156 $outputPage->addHTML(
'<p class="mw-delete-editreasons">' . $link .
'</p>' );
2159 $deleteLogPage =
new LogPage(
'delete' );
2160 $outputPage->addHTML( Xml::element(
'h2',
null, $deleteLogPage->getName()->text() ) );
2161 LogEventsList::showLogExtract( $outputPage,
'delete',
$title );
2172 public function doDelete( $reason, $suppress =
false, $immediate =
false ) {
2175 $outputPage = $context->getOutput();
2176 $user = $context->getUser();
2177 $status = $this->mPage->doDeleteArticleReal(
2178 $reason, $user, $suppress,
null, $error,
2179 null, [],
'delete', $immediate
2182 if ( $status->isOK() ) {
2183 $deleted = $this->
getTitle()->getPrefixedText();
2185 $outputPage->setPageTitle(
wfMessage(
'actioncomplete' ) );
2186 $outputPage->setRobotPolicy(
'noindex,nofollow' );
2188 if ( $status->isGood() ) {
2189 $loglink =
'[[Special:Log/delete|' .
wfMessage(
'deletionlog' )->text() .
']]';
2190 $outputPage->addWikiMsg(
'deletedtext',
wfEscapeWikiText( $deleted ), $loglink );
2191 $this->getHookRunner()->onArticleDeleteAfterSuccess( $this->
getTitle(), $outputPage );
2193 $outputPage->addWikiMsg(
'delete-scheduled',
wfEscapeWikiText( $deleted ) );
2196 $outputPage->returnToMain(
false );
2198 $outputPage->setPageTitle(
2200 $this->
getTitle()->getPrefixedText() )
2203 if ( $error ==
'' ) {
2204 $outputPage->wrapWikiTextAsInterface(
2205 'error mw-error-cannotdelete',
2206 $status->getWikiText(
false,
false, $context->getLanguage() )
2208 $deleteLogPage =
new LogPage(
'delete' );
2209 $outputPage->addHTML( Xml::element(
'h2',
null, $deleteLogPage->getName()->text() ) );
2211 LogEventsList::showLogExtract(
2217 $outputPage->addHTML( $error );
2232 static $called =
false;
2235 wfDebug(
"Article::tryFileCache(): called twice!?" );
2242 if (
$cache->isCacheGood( $this->mPage->getTouched() ) ) {
2243 wfDebug(
"Article::tryFileCache(): about to load file" );
2247 wfDebug(
"Article::tryFileCache(): starting buffer" );
2248 ob_start( [ &
$cache,
'saveToFileCache' ] );
2251 wfDebug(
"Article::tryFileCache(): not cacheable" );
2266 $cacheable = $this->mPage->getId()
2267 && !$this->mRedirectedFrom && !$this->
getTitle()->isRedirect();
2270 $cacheable = $this->getHookRunner()->onIsFileCacheable( $this );
2293 if ( $user ===
null ) {
2296 $parserOptions = $this->mPage->makeParserOptions( $user );
2299 return $this->mPage->getParserOutput( $parserOptions, $oldid );
2309 if ( $this->mParserOptions ) {
2310 throw new MWException(
"can't change parser options after they have already been set" );
2314 $this->mParserOptions = clone $options;
2322 if ( !$this->mParserOptions ) {
2323 $this->mParserOptions = $this->mPage->makeParserOptions( $this->
getContext() );
2326 return clone $this->mParserOptions;
2336 $this->mContext = $context;
2347 return $this->mContext;
2349 wfDebug( __METHOD__ .
" called and \$mContext is null. " .
2350 "Return RequestContext::getMain(); for sanity" );
2351 return RequestContext::getMain();
2365 wfDeprecatedMsg(
"Accessing Article::\$$fname is deprecated since MediaWiki 1.35",
2368 if ( $fname ===
'mRevision' ) {
2370 return $record ?
new Revision( $record ) :
null;
2373 if ( property_exists( $this->mPage, $fname ) ) {
2374 return $this->mPage->$fname;
2376 trigger_error(
'Inaccessible property via __get(): ' . $fname, E_USER_NOTICE );
2388 public function __set( $fname, $fvalue ) {
2389 wfDeprecatedMsg(
"Setting Article::\$$fname is deprecated since MediaWiki 1.35",
2392 if ( $fname ===
'mRevision' ) {
2393 $this->mRevisionRecord = $fvalue ?
2394 $fvalue->getRevisionRecord() :
2399 if ( property_exists( $this->mPage, $fname ) ) {
2400 $this->mPage->$fname = $fvalue;
2402 } elseif ( !in_array( $fname, [
'mContext',
'mPage' ] ) ) {
2403 $this->mPage->$fname = $fvalue;
2405 trigger_error(
'Inaccessible property via __set(): ' . $fname, E_USER_NOTICE );
2422 return $this->mPage->checkFlags( $flags );
2432 return $this->mPage->checkTouched();
2442 $this->mPage->clearPreparedEdit();
2460 $reason, $suppress =
false, $u1 =
null, $u2 =
null, &$error =
'',
User $user =
null,
2461 $tags = [], $immediate =
false
2464 return $this->mPage->doDeleteArticleReal(
2465 $reason, $suppress, $u1, $u2, $error, $user, $tags,
'delete', $immediate
2484 $this->mPage->doDeleteUpdates( $id,
$content, $revision, $user );
2498 $this->mPage->doEditUpdates( $revision, $user, $options );
2510 return $this->mPage->doPurge();
2521 $this->mPage->doViewUpdates( $user, $oldid );
2531 return $this->mPage->exists();
2541 return $this->mPage->followRedirect();
2550 return $this->mPage->getActionOverrides();
2561 return $this->mPage->getAutoDeleteReason( $hasHistory );
2571 return $this->mPage->getCategories();
2582 public function getComment( $audience = RevisionRecord::FOR_PUBLIC,
User $user =
null ) {
2584 return $this->mPage->getComment( $audience, $user );
2594 return $this->mPage->getContentHandler();
2604 return $this->mPage->getContentModel();
2614 return $this->mPage->getContributors();
2625 public function getCreator( $audience = RevisionRecord::FOR_PUBLIC,
User $user =
null ) {
2627 return $this->mPage->getCreator( $audience, $user );
2638 return $this->mPage->getDeletionUpdates(
$content );
2648 return $this->mPage->getHiddenCategories();
2658 return $this->mPage->getId();
2668 return $this->mPage->getLatest();
2678 return $this->mPage->getLinksTimestamp();
2688 return $this->mPage->getMinorEdit();
2697 return $this->mPage->getOldestRevision();
2707 return $this->mPage->getRedirectTarget();
2718 return $this->mPage->getRedirectURL( $rt );
2729 return $this->mPage->getRevision();
2739 return $this->mPage->getTimestamp();
2749 return $this->mPage->getTouched();
2762 return $this->mPage->getUndoContent( $undo, $undoafter );
2772 public function getUser( $audience = RevisionRecord::FOR_PUBLIC,
User $user =
null ) {
2774 return $this->mPage->getUser( $audience, $user );
2784 public function getUserText( $audience = RevisionRecord::FOR_PUBLIC,
User $user =
null ) {
2786 return $this->mPage->getUserText( $audience, $user );
2796 return $this->mPage->hasViewableContent();
2808 return $this->mPage->insertOn( $dbw, $pageId );
2823 array $expiry, $cascade, $reason, $user =
null
2826 return $this->mPage->insertProtectNullRevision( $revCommentMsg, $limit,
2827 $expiry, $cascade, $reason, $user
2838 return $this->mPage->insertRedirect();
2850 return $this->mPage->insertRedirectEntry( $rt, $oldLatest );
2861 return $this->mPage->isCountable( $editInfo );
2871 return $this->mPage->isRedirect();
2882 $this->mPage->loadFromRow( $data, $from );
2892 $this->mPage->loadPageData( $from );
2902 return $this->mPage->lockAndGetLatest();
2913 return $this->mPage->makeParserOptions( $context );
2926 return $this->mPage->pageDataFromId(
$dbr, $id, $options );
2939 return $this->mPage->pageDataFromTitle(
$dbr,
$title, $options );
2957 $serialFormat =
null, $useCache =
true
2960 return $this->mPage->prepareContentForEdit(
2962 $serialFormat, $useCache
2975 return $this->mPage->protectDescription( $limit, $expiry );
2987 return $this->mPage->protectDescriptionLog( $limit, $expiry );
3000 $sectionTitle =
'', $baseRevId =
null
3003 return $this->mPage->replaceSectionAtRev( $sectionId, $sectionContent,
3004 $sectionTitle, $baseRevId
3020 $sectionId,
Content $sectionContent, $sectionTitle =
'', $edittime =
null
3023 return $this->mPage->replaceSectionContent(
3024 $sectionId, $sectionContent, $sectionTitle, $edittime
3035 $this->mPage->setTimestamp( $ts );
3047 return $this->mPage->shouldCheckParserCache( $parserOptions, $oldId );
3057 return $this->mPage->supportsSections();
3067 $this->mPage->triggerOpportunisticLinksUpdate( $parserOutput );
3079 $this->mPage->updateCategoryCounts( $added, $deleted, $id );
3092 return $this->mPage->updateIfNewerOn( $dbw, $revision );
3105 return $this->mPage->updateRedirectOn( $dbw, $redirectTitle, $lastRevIsRedirect );
3118 $lastRevIsRedirect =
null
3121 return $this->mPage->updateRevisionOn( $dbw, $revision, $lastRevision,
3139 return $this->mPage->doUpdateRestrictions( $limit, $expiry, $cascade, $reason, $user );
3151 &$cascade = 0, $expiry = []
3154 return $this->mPage->doUpdateRestrictions(
3176 $reason, $suppress =
false, $u1 =
null, $u2 =
null, &$error =
'', $immediate =
false
3179 return $this->mPage->doDeleteArticle( $reason, $suppress, $u1, $u2, $error,
3206 return $this->mPage->doRollback( $fromP, $summary, $token, $bot, $resultDetails, $user );
3225 return $this->mPage->commitRollback( $fromP, $summary, $bot, $resultDetails, $guser );
3236 return $this->
getPage()->getAutoDeleteReason( $hasHistory );
$wgArticleRobotPolicies
Robot policies per article.
$wgCdnMaxageStale
Cache timeout when delivering a stale ParserCache response due to PoolCounter contention.
$wgDefaultRobotPolicy
Default robot policy.
$wgSend404Code
Some web hosts attempt to rewrite all responses with a 404 (not found) status code,...
$wgRedirectSources
If local interwikis are set up which allow redirects, set this regexp to restrict URLs which will be ...
$wgUseFilePatrol
Use file patrolling to check new files on Special:Newfiles.
$wgUseRCPatrol
Use RC Patrolling to check for vandalism (from recent changes and watchlists) New pages and new files...
$wgNamespaceRobotPolicies
Robot policies per namespaces.
$wgUseNPPatrol
Use new page patrolling to check new pages on Special:Newpages.
$wgDeleteRevisionsLimit
Optional to restrict deletion of pages with higher revision counts to users with the 'bigdelete' perm...
$wgUseFileCache
This will cache static pages for non-logged-in users to reduce database traffic on public sites.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfReadOnly()
Check whether the wiki is in read-only mode.
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.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that $function is deprecated.
Class for viewing MediaWiki article and history.
shouldCheckParserCache(ParserOptions $parserOptions, $oldId)
getRevisionFetched()
Get the fetched Revision object depending on request parameters or null on failure.
doDeleteUpdates( $id, Content $content=null, $revision=null, User $user=null)
updateRedirectOn( $dbw, $redirectTitle, $lastRevIsRedirect=null)
generateReason(&$hasHistory)
getSubstituteContent()
Returns Content object to use when the page does not exist.
checkFlags( $flags)
Call to WikiPage function for backwards compatibility.
static newFromWikiPage(WikiPage $page, IContextSource $context)
Create an Article object of the appropriate class for the given page.
doViewUpdates(User $user, $oldid=0)
getContext()
Gets the context this Article is executed in.
commitRollback( $fromP, $summary, $bot, &$resultDetails, User $guser=null)
getOldIDFromRequest()
Sets $this->mRedirectUrl to a correct URL if the query parameters are incorrect.
getParserOutput( $oldid=null, User $user=null)
#-
insertProtectNullRevision( $revCommentMsg, array $limit, array $expiry, $cascade, $reason, $user=null)
getRedirectedFrom()
Get the page this view was redirected from.
Title null $mRedirectedFrom
Title from which we were redirected here, if any.
insertOn( $dbw, $pageId=null)
updateRevisionOn( $dbw, $revision, $lastRevision=null, $lastRevIsRedirect=null)
bool $viewIsRenderAction
Whether render() was called.
fetchContentObject()
Get text content object Does NOT follow redirects.
pageDataFromTitle( $dbr, $title, $options=[])
RevisionStore $revisionStore
updateCategoryCounts(array $added, array $deleted, $id=0)
view()
This is the default action of the index.php entry point: just view the page of the given title.
loadPageData( $from='fromdb')
doDeleteArticleReal( $reason, $suppress=false, $u1=null, $u2=null, &$error='', User $user=null, $tags=[], $immediate=false)
Call to WikiPage function for backwards compatibility.
doUpdateRestrictions(array $limit, array $expiry, &$cascade, $reason, User $user)
protectDescriptionLog(array $limit, array $expiry)
getComment( $audience=RevisionRecord::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
clearPreparedEdit()
Call to WikiPage function for backwards compatibility.
__construct(Title $title, $oldId=null)
getRobotPolicy( $action, ParserOutput $pOutput=null)
Get the robot policy to be used for the current view.
static purgePatrolFooterCache( $articleID)
Purge the cache used to check if it is worth showing the patrol footer For example,...
prepareContentForEdit(Content $content, $revision=null, User $user=null, $serialFormat=null, $useCache=true)
Call to WikiPage function for backwards compatibility.
doDelete( $reason, $suppress=false, $immediate=false)
Perform a deletion and output success or failure messages.
replaceSectionAtRev( $sectionId, Content $sectionContent, $sectionTitle='', $baseRevId=null)
ParserOutput null false $mParserOutput
The ParserOutput generated for viewing the page, initialized by view().
getAutoDeleteReason(&$hasHistory)
protectDescription(array $limit, array $expiry)
LinkRenderer $linkRenderer
getTitle()
Get the title object of the article.
getActionOverrides()
Call to WikiPage function for backwards compatibility.
doEditUpdates(Revision $revision, User $user, array $options=[])
Call to WikiPage function for backwards compatibility.
adjustDisplayTitle(ParserOutput $pOutput)
Adjust title for pages with displaytitle, -{T|}- or language conversion.
updateIfNewerOn( $dbw, $revision)
Call to WikiPage function for backwards compatibility.
pageDataFromId( $dbr, $id, $options=[])
showDeletedRevisionHeader()
If the revision requested for view is deleted, check permissions.
isCountable( $editInfo=false)
getParserOptions()
Get parser options suitable for rendering the primary article wikitext.
IContextSource null $mContext
The context this Article is executed in.
static getRedirectHeaderHtml(Language $lang, $target, $forceKnown=false)
Return the HTML for the top of a redirect page.
getUserText( $audience=RevisionRecord::FOR_PUBLIC, User $user=null)
protect()
action=protect handler
isCurrent()
Returns true if the currently-referenced revision is the current edit to this page (and it exists).
updateRestrictions( $limit=[], $reason='', &$cascade=0, $expiry=[])
showMissingArticle()
Show the error text for a missing article.
getUndoContent(Revision $undo, Revision $undoafter=null)
Call to WikiPage function for backwards compatibility.
unprotect()
action=unprotect handler (alias)
int $mRevIdFetched
Revision ID of revision that was loaded.
applyContentOverride(Content $override)
Applies a content override by constructing a fake Revision object and assigning it to mRevisionRecord...
ParserOptions null $mParserOptions
ParserOptions object for $wgUser articles.
makeFetchErrorContent()
Returns a Content object representing any error in $this->fetchContent, or null if there is no such e...
confirmDelete( $reason)
Output deletion confirmation dialog.
getPage()
Get the WikiPage object of this instance.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
getRevision()
Call to WikiPage function for backwards compatibility.
string bool $mRedirectUrl
URL to redirect to or false if none.
static newFromID( $id)
Constructor from a page id.
int null $mOldId
The oldid of the article that was requested to be shown, 0 for the current revision.
static formatRobotPolicy( $policy)
Converts a String robot policy into an associative array, to allow merging of several policies using ...
fetchRevisionRecord()
Fetches the revision to work on.
viewRedirect( $target, $appendSubtitle=true, $forceKnown=false)
Return the HTML for the top of a redirect page.
insertRedirectEntry(Title $rt, $oldLatest=null)
triggerOpportunisticLinksUpdate(ParserOutput $parserOutput)
makeParserOptions( $context)
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:...
showViewFooter()
Show the footer section of an ordinary page view.
Status null $fetchResult
represents the outcome of fetchRevisionRecord().
WikiPage $mPage
The WikiPage object of this instance.
loadFromRow( $data, $from)
setRedirectedFrom(Title $from)
Tell the page view functions that this view was redirected from another page on the wiki.
isFileCacheable( $mode=HTMLFileCache::MODE_NORMAL)
Check if the page can be cached.
doDeleteArticle( $reason, $suppress=false, $u1=null, $u2=null, &$error='', $immediate=false)
getCreator( $audience=RevisionRecord::FOR_PUBLIC, User $user=null)
Call to WikiPage function for backwards compatibility.
tryFileCache()
checkLastModified returns true if it has taken care of all output to the client that is necessary for...
getRevIdFetched()
Use this to fetch the rev ID used on page views.
replaceSectionContent( $sectionId, Content $sectionContent, $sectionTitle='', $edittime=null)
Call to WikiPage function for backwards compatibility.
getUser( $audience=RevisionRecord::FOR_PUBLIC, User $user=null)
showNamespaceHeader()
Show a header specific to the namespace currently being viewed, like [[MediaWiki:Talkpagetext]].
getRevisionRedirectTarget(RevisionRecord $revision)
static newFromTitle( $title, IContextSource $context)
Create an Article object of the appropriate class for the given page.
getContentObject()
Returns a Content object representing the pages effective display content, not necessarily the revisi...
showDiffPage()
Show a diff page according to current request variables.
setParserOptions(ParserOptions $options)
Override the ParserOptions used to render the primary article wikitext.
getEmptyPageParserOutput(ParserOptions $options)
Returns ParserOutput to use when a page does not exist.
render()
Handle action=render.
showRedirectedFromHeader()
If this request is a redirect view, send "redirected from" subtitle to the output.
PermissionManager $permManager
setContext( $context)
Sets the context this Article is executed in.
bool $mContentLoaded
Is the target revision loaded? Set by fetchRevisionRecord().
getDeletionUpdates(Content $content=null)
doRollback( $fromP, $summary, $token, $bot, &$resultDetails, User $user=null)
Content null $mContentObject
Content of the main slot of $this->mRevisionRecord.
Special handling for category description pages, showing pages, subcategories and file that belong to...
const POST_EDIT_COOKIE_KEY_PREFIX
Prefix of key for cookie used to pass post-edit state.
Page view caching in the file system.
static useFileCache(IContextSource $context, $mode=self::MODE_NORMAL)
Check if pages can be cached for this request/user.
Class for viewing MediaWiki file description pages.
Internationalisation code See https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation for more...
static revComment( $rev, $local=false, $isPublic=false, $useParentheses=true)
Wrap and format the given revision's comment block, if the current user is allowed to view it.
static revUserTools( $rev, $isPublic=false, $useParentheses=true)
Generate a user tool link cluster if the current user is allowed to view it.
static getRevDeleteLink(User $user, $rev, LinkTarget $title)
Get a revision-deletion link, or disabled link, or nothing, depending on user permissions & the setti...
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=[], $title=null)
Make an external link.
Class to simplify the use of log pages.
Wrapper allowing us to handle a system message as a Content object.
Set options of the Parser.
Show an error when a user tries to do something they do not have the necessary permissions for.
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Represents a title within MediaWiki.
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
static doWatchOrUnwatch( $watch, Title $title, User $user, string $expiry=null)
Watch or unwatch a page.
Class representing a MediaWiki article and history.
getTitle()
Get the title object of the article.
Base interface for content objects.
Interface for objects which can provide a MediaWiki context on request.
Interface for type hinting (accepts WikiPage, Article, ImagePage, CategoryPage)
if(!isset( $args[0])) $lang