210 $id = $title->getArticleID();
211 $config = $this->context->getConfig();
212 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
214 $pageCounts = $this->
pageCounts( $this->page );
216 $pageProperties = [];
218 if ( isset( $props[$id] ) ) {
219 $pageProperties = $props[$id];
224 $pageInfo[
'header-basic'] = [];
227 $displayTitle = $title->getPrefixedText();
228 if ( isset( $pageProperties[
'displaytitle'] ) ) {
229 $displayTitle = $pageProperties[
'displaytitle'];
232 $pageInfo[
'header-basic'][] = [
233 $this->
msg(
'pageinfo-display-title' ), $displayTitle
237 if ( $title->isRedirect() ) {
238 $pageInfo[
'header-basic'][] = [
239 $this->
msg(
'pageinfo-redirectsto' ),
240 $linkRenderer->makeLink( $this->page->getRedirectTarget() ) .
241 $this->
msg(
'word-separator' )->escaped() .
243 $this->page->getRedirectTarget(),
244 $this->msg(
'pageinfo-redirectsto-info' )->text(),
246 [
'action' =>
'info' ]
252 $sortKey = $title->getCategorySortkey();
253 if ( isset( $pageProperties[
'defaultsort'] ) ) {
254 $sortKey = $pageProperties[
'defaultsort'];
257 $sortKey = htmlspecialchars( $sortKey );
258 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-default-sort' ), $sortKey ];
261 $pageInfo[
'header-basic'][] = [
262 $this->
msg(
'pageinfo-length' ),
$lang->formatNum( $title->getLength() )
266 $pageInfo[
'header-basic'][] = [ $this->
msg(
'pageinfo-article-id' ), $id ];
269 $pageLang = $title->getPageLanguage()->getCode();
271 $pageLangHtml = $pageLang .
' - ' .
272 Language::fetchLanguageName( $pageLang,
$lang->getCode() );
274 if ( $config->get(
'PageLanguageUseDB' )
275 && $title->userCan(
'pagelang', $user )
277 $pageLangHtml .=
' ' . $this->
msg(
'parentheses' )->rawParams(
$linkRenderer->makeLink(
278 SpecialPage::getTitleValueFor(
'PageLanguage', $title->getPrefixedText() ),
279 $this->msg(
'pageinfo-language-change' )->text()
283 $pageInfo[
'header-basic'][] = [
284 $this->
msg(
'pageinfo-language' )->escaped(),
289 $modelHtml = htmlspecialchars( ContentHandler::getLocalizedName( $title->getContentModel() ) );
291 if ( $config->get(
'ContentHandlerUseDB' )
292 && $title->userCan(
'editcontentmodel', $user )
294 $modelHtml .=
' ' . $this->
msg(
'parentheses' )->rawParams(
$linkRenderer->makeLink(
295 SpecialPage::getTitleValueFor(
'ChangeContentModel', $title->getPrefixedText() ),
296 $this->msg(
'pageinfo-content-model-change' )->text()
300 $pageInfo[
'header-basic'][] = [
301 $this->
msg(
'pageinfo-content-model' ),
305 if ( $title->inNamespace( NS_USER ) ) {
307 if ( $pageUser && $pageUser->getId() && !$pageUser->isHidden() ) {
308 $pageInfo[
'header-basic'][] = [
309 $this->
msg(
'pageinfo-user-id' ),
317 if ( isset( $pageProperties[
'noindex'] ) ) {
318 $pOutput->setIndexPolicy(
'noindex' );
320 if ( isset( $pageProperties[
'index'] ) ) {
321 $pOutput->setIndexPolicy(
'index' );
325 $policy = $this->page->getRobotPolicy(
'view', $pOutput );
326 $pageInfo[
'header-basic'][] = [
328 $this->
msg(
'pageinfo-robot-policy' ),
329 $this->
msg(
"pageinfo-robot-${policy['index']}" )
332 $unwatchedPageThreshold = $config->get(
'UnwatchedPageThreshold' );
334 $user->isAllowed(
'unwatchedpages' ) ||
335 ( $unwatchedPageThreshold !==
false &&
336 $pageCounts[
'watchers'] >= $unwatchedPageThreshold )
339 $pageInfo[
'header-basic'][] = [
340 $this->
msg(
'pageinfo-watchers' ),
341 $lang->formatNum( $pageCounts[
'watchers'] )
344 $config->get(
'ShowUpdatedMarker' ) &&
345 isset( $pageCounts[
'visitingWatchers'] )
347 $minToDisclose = $config->get(
'UnwatchedPageSecret' );
348 if ( $pageCounts[
'visitingWatchers'] > $minToDisclose ||
349 $user->isAllowed(
'unwatchedpages' ) ) {
350 $pageInfo[
'header-basic'][] = [
351 $this->
msg(
'pageinfo-visiting-watchers' ),
352 $lang->formatNum( $pageCounts[
'visitingWatchers'] )
355 $pageInfo[
'header-basic'][] = [
356 $this->
msg(
'pageinfo-visiting-watchers' ),
357 $this->
msg(
'pageinfo-few-visiting-watchers' )
361 } elseif ( $unwatchedPageThreshold !==
false ) {
362 $pageInfo[
'header-basic'][] = [
363 $this->
msg(
'pageinfo-watchers' ),
364 $this->
msg(
'pageinfo-few-watchers' )->numParams( $unwatchedPageThreshold )
369 $whatLinksHere = SpecialPage::getTitleFor(
'Whatlinkshere', $title->getPrefixedText() );
370 $pageInfo[
'header-basic'][] = [
373 $this->
msg(
'pageinfo-redirects-name' )->
text(),
378 'hideimages' => $title->getNamespace() ==
NS_FILE
381 $this->
msg(
'pageinfo-redirects-value' )
382 ->numParams( count( $title->getRedirectsHere() ) )
386 if ( $this->page->isCountable() ) {
387 $pageInfo[
'header-basic'][] = [
388 $this->
msg(
'pageinfo-contentpage' ),
389 $this->
msg(
'pageinfo-contentpage-yes' )
394 if ( MWNamespace::hasSubpages( $title->getNamespace() ) ) {
395 $prefixIndex = SpecialPage::getTitleFor(
396 'Prefixindex', $title->getPrefixedText() .
'/' );
397 $pageInfo[
'header-basic'][] = [
400 $this->
msg(
'pageinfo-subpages-name' )->
text()
402 $this->
msg(
'pageinfo-subpages-value' )
404 $pageCounts[
'subpages'][
'total'],
405 $pageCounts[
'subpages'][
'redirects'],
406 $pageCounts[
'subpages'][
'nonredirects'] )
411 $category = Category::newFromTitle( $title );
415 $allCount = (int)$category->getPageCount();
416 $subcatCount = (int)$category->getSubcatCount();
417 $fileCount = (int)$category->getFileCount();
418 $pagesCount = $allCount - $subcatCount - $fileCount;
420 $pageInfo[
'category-info'] = [
422 $this->
msg(
'pageinfo-category-total' ),
423 $lang->formatNum( $allCount )
426 $this->
msg(
'pageinfo-category-pages' ),
427 $lang->formatNum( $pagesCount )
430 $this->
msg(
'pageinfo-category-subcats' ),
431 $lang->formatNum( $subcatCount )
434 $this->
msg(
'pageinfo-category-files' ),
435 $lang->formatNum( $fileCount )
441 if ( $title->inNamespace(
NS_FILE ) ) {
443 if ( $fileObj !==
false ) {
445 $output = Wikimedia\base_convert( $fileObj->getSha1(), 36, 16, 40 );
446 $pageInfo[
'header-basic'][] = [
447 $this->
msg(
'pageinfo-file-hash' ),
454 $pageInfo[
'header-restrictions'] = [];
457 if ( $title->isCascadeProtected() ) {
459 $sources = $title->getCascadeProtectionSources()[0];
461 foreach ( $sources as $sourceTitle ) {
462 $cascadingFrom .= Html::rawElement(
466 $cascadingFrom = Html::rawElement(
'ul', [], $cascadingFrom );
467 $pageInfo[
'header-restrictions'][] = [
468 $this->
msg(
'pageinfo-protect-cascading-from' ),
474 if ( $title->areRestrictionsCascading() ) {
475 $pageInfo[
'header-restrictions'][] = [
476 $this->
msg(
'pageinfo-protect-cascading' ),
477 $this->
msg(
'pageinfo-protect-cascading-yes' )
482 foreach ( $title->getRestrictionTypes() as $restrictionType ) {
483 $protectionLevel = implode(
', ', $title->getRestrictions( $restrictionType ) );
485 if ( $protectionLevel ==
'' ) {
487 $message = $this->
msg(
'protect-default' )->escaped();
491 $message = $this->
msg(
"protect-level-$protectionLevel" );
492 if ( $message->isDisabled() ) {
494 $message = $this->
msg(
"protect-fallback", $protectionLevel )->parse();
496 $message = $message->escaped();
499 $expiry = $title->getRestrictionExpiry( $restrictionType );
500 $formattedexpiry = $this->
msg(
'parentheses',
501 $lang->formatExpiry( $expiry ) )->escaped();
502 $message .= $this->
msg(
'word-separator' )->escaped() . $formattedexpiry;
506 $pageInfo[
'header-restrictions'][] = [
507 $this->
msg(
"restriction-$restrictionType" ), $message
511 if ( !$this->page->exists() ) {
516 $pageInfo[
'header-edits'] = [];
518 $firstRev = $this->page->getOldestRevision();
519 $lastRev = $this->page->getRevision();
523 $firstRevUser = $firstRev->getUserText( Revision::FOR_THIS_USER );
524 if ( $firstRevUser !==
'' ) {
525 $firstRevUserTitle = Title::makeTitle( NS_USER, $firstRevUser );
526 $batch->addObj( $firstRevUserTitle );
527 $batch->addObj( $firstRevUserTitle->getTalkPage() );
532 $lastRevUser = $lastRev->getUserText( Revision::FOR_THIS_USER );
533 if ( $lastRevUser !==
'' ) {
534 $lastRevUserTitle = Title::makeTitle( NS_USER, $lastRevUser );
535 $batch->addObj( $lastRevUserTitle );
536 $batch->addObj( $lastRevUserTitle->getTalkPage() );
544 $pageInfo[
'header-edits'][] = [
545 $this->
msg(
'pageinfo-firstuser' ),
550 $pageInfo[
'header-edits'][] = [
551 $this->
msg(
'pageinfo-firsttime' ),
554 $lang->userTimeAndDate( $firstRev->getTimestamp(), $user ),
556 [
'oldid' => $firstRev->getId() ]
563 $pageInfo[
'header-edits'][] = [
564 $this->
msg(
'pageinfo-lastuser' ),
569 $pageInfo[
'header-edits'][] = [
570 $this->
msg(
'pageinfo-lasttime' ),
573 $lang->userTimeAndDate( $this->page->getTimestamp(), $user ),
575 [
'oldid' => $this->page->getLatest() ]
581 $pageInfo[
'header-edits'][] = [
582 $this->
msg(
'pageinfo-edits' ),
$lang->formatNum( $pageCounts[
'edits'] )
586 if ( $pageCounts[
'authors'] > 0 ) {
587 $pageInfo[
'header-edits'][] = [
588 $this->
msg(
'pageinfo-authors' ),
$lang->formatNum( $pageCounts[
'authors'] )
593 $pageInfo[
'header-edits'][] = [
594 $this->
msg(
'pageinfo-recent-edits',
595 $lang->formatDuration( $config->get(
'RCMaxAge' ) ) ),
596 $lang->formatNum( $pageCounts[
'recent_edits'] )
600 $pageInfo[
'header-edits'][] = [
601 $this->
msg(
'pageinfo-recent-authors' ),
602 $lang->formatNum( $pageCounts[
'recent_authors'] )
617 $listItems[] = Html::element(
'li', [], $localizedWords[
$property][1] );
621 $localizedList = Html::rawElement(
'ul', [], implode(
'', $listItems ) );
622 $hiddenCategories = $this->page->getHiddenCategories();
625 count( $listItems ) > 0 ||
626 count( $hiddenCategories ) > 0 ||
627 $pageCounts[
'transclusion'][
'from'] > 0 ||
628 $pageCounts[
'transclusion'][
'to'] > 0
630 $options = [
'LIMIT' => $config->get(
'PageInfoTransclusionLimit' ) ];
631 $transcludedTemplates = $title->getTemplateLinksFrom(
$options );
632 if ( $config->get(
'MiserMode' ) ) {
633 $transcludedTargets = [];
635 $transcludedTargets = $title->getTemplateLinksTo(
$options );
639 $pageInfo[
'header-properties'] = [];
642 if ( count( $listItems ) > 0 ) {
643 $pageInfo[
'header-properties'][] = [
644 $this->
msg(
'pageinfo-magic-words' )->numParams( count( $listItems ) ),
650 if ( count( $hiddenCategories ) > 0 ) {
651 $pageInfo[
'header-properties'][] = [
652 $this->
msg(
'pageinfo-hidden-categories' )
653 ->numParams( count( $hiddenCategories ) ),
659 if ( $pageCounts[
'transclusion'][
'from'] > 0 ) {
660 if ( $pageCounts[
'transclusion'][
'from'] > count( $transcludedTemplates ) ) {
661 $more = $this->
msg(
'morenotlisted' )->escaped();
671 $pageInfo[
'header-properties'][] = [
672 $this->
msg(
'pageinfo-templates' )
673 ->numParams( $pageCounts[
'transclusion'][
'from'] ),
674 $templateListFormatter->format( $transcludedTemplates,
false, $more )
678 if ( !$config->get(
'MiserMode' ) && $pageCounts[
'transclusion'][
'to'] > 0 ) {
679 if ( $pageCounts[
'transclusion'][
'to'] > count( $transcludedTargets ) ) {
682 $this->
msg(
'moredotdotdot' )->
text(),
684 [
'hidelinks' => 1,
'hideredirs' => 1 ]
695 $pageInfo[
'header-properties'][] = [
696 $this->
msg(
'pageinfo-transclusions' )
697 ->numParams( $pageCounts[
'transclusion'][
'to'] ),
698 $templateListFormatter->format( $transcludedTargets,
false, $more )