MediaWiki master
Skin.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Skin;
8
11use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
38use Wikimedia\IPUtils;
41
54abstract class Skin extends ContextSource {
55 use ProtectedHookAccessorTrait;
56
60 private $defaultLinkOptions;
61
65 protected $skinname = null;
66
70 protected $options = [];
72 protected $mRelevantTitle = null;
73
77 private $mRelevantUser = false;
78
80 protected const VERSION_MAJOR = 1;
81
83 private $languageLinks;
84
86 private $sidebar;
87
91 private $componentRegistry = null;
92
100 public static function getVersion() {
101 return self::VERSION_MAJOR;
102 }
103
109 final protected function getComponent( string $name ): SkinComponent {
110 return $this->componentRegistry->getComponent( $name );
111 }
112
134 public function getTemplateData() {
135 $title = $this->getTitle();
136 $out = $this->getOutput();
137 $user = $this->getUser();
138 $isMainPage = $title->isMainPage();
139 $blankedHeading = false;
140 // Heading can only be blanked on "views". It should
141 // still show on action=edit, diff pages and action=history
142 $isHeadingOverridable = $this->getContext()->getActionName() === 'view' &&
143 !$this->getRequest()->getRawVal( 'diff' );
144
145 if ( $isMainPage && $isHeadingOverridable ) {
146 // Special casing for the main page to allow more freedom to editors, to
147 // design their home page differently. This came up in T290480.
148 // The parameter for logged in users is optional and may
149 // or may not be used.
150 $titleMsg = $user->isAnon() ?
151 $this->msg( 'mainpage-title' ) :
152 $this->msg( 'mainpage-title-loggedin', $user->getName() );
153
154 // T298715: Use content language rather than user language so that
155 // the custom page heading is shown to all users, not just those that have
156 // their interface set to the site content language.
157 //
158 // T331095: Avoid Message::inContentLanguage and, just like Parser,
159 // pick the language variant based on the current URL and/or user
160 // preference if their variant relates to the content language.
161 $forceUIMsgAsContentMsg = $this->getConfig()
163 if ( !in_array( $titleMsg->getKey(), (array)$forceUIMsgAsContentMsg ) ) {
164 $services = MediaWikiServices::getInstance();
165 $contLangVariant = $services->getLanguageConverterFactory()
166 ->getLanguageConverter( $services->getContentLanguage() )
167 ->getPreferredVariant();
168 $titleMsg->inLanguage( $contLangVariant );
169 }
170 $titleMsg->setInterfaceMessageFlag( true );
171 $blankedHeading = $titleMsg->isBlank();
172 if ( !$titleMsg->isDisabled() ) {
173 $htmlTitle = $titleMsg->parse();
174 } else {
175 $htmlTitle = $out->getPageTitle();
176 }
177 } else {
178 $htmlTitle = $out->getPageTitle();
179 }
180
181 $data = [
182 // raw HTML
183 'html-title-heading' => Html::rawElement(
184 'h1',
185 [
186 'id' => 'firstHeading',
187 'class' => 'firstHeading mw-first-heading',
188 'style' => $blankedHeading ? 'display: none' : null
189 ] + $this->getUserLanguageAttributes(),
190 $htmlTitle
191 ),
192 'html-title' => $htmlTitle ?: null,
193 // Boolean values
194 'is-title-blank' => $blankedHeading, // @since 1.38
195 'is-anon' => $user->isAnon(),
196 'is-article' => $out->isArticle(),
197 'is-mainpage' => $isMainPage,
198 'is-specialpage' => $title->isSpecialPage(),
199 'canonical-url' => $this->getCanonicalUrl(),
200 ];
201
202 $components = $this->componentRegistry->getComponents();
203 foreach ( $components as $componentName => $component ) {
204 $data['data-' . $componentName] = $component->getTemplateData();
205 }
206 return $data;
207 }
208
218 public static function normalizeKey( string $key ) {
219 $config = MediaWikiServices::getInstance()->getMainConfig();
220 $defaultSkin = $config->get( MainConfigNames::DefaultSkin );
221 $fallbackSkin = $config->get( MainConfigNames::FallbackSkin );
222 $skinFactory = MediaWikiServices::getInstance()->getSkinFactory();
223 $skinNames = $skinFactory->getInstalledSkins();
224
225 // Make keys lowercase for case-insensitive matching.
226 $skinNames = array_change_key_case( $skinNames, CASE_LOWER );
227 $key = strtolower( $key );
228 $defaultSkin = strtolower( $defaultSkin );
229 $fallbackSkin = strtolower( $fallbackSkin );
230
231 if ( $key == '' || $key == 'default' ) {
232 // Don't return the default immediately;
233 // in a misconfiguration we need to fall back.
234 $key = $defaultSkin;
235 }
236
237 if ( isset( $skinNames[$key] ) ) {
238 return $key;
239 }
240
241 // Older versions of the software used a numeric setting
242 // in the user preferences.
243 $fallback = [
244 0 => $defaultSkin,
245 2 => 'cologneblue'
246 ];
247
248 if ( isset( $fallback[$key] ) ) {
249 // @phan-suppress-next-line PhanTypeMismatchDimFetch False positive
250 $key = $fallback[$key];
251 }
252
253 if ( isset( $skinNames[$key] ) ) {
254 return $key;
255 } elseif ( isset( $skinNames[$defaultSkin] ) ) {
256 return $defaultSkin;
257 } else {
258 return $fallbackSkin;
259 }
260 }
261
329 public function __construct( $options = null ) {
330 if ( is_string( $options ) ) {
331 $this->skinname = $options;
332 } elseif ( $options ) {
333 $name = $options['name'] ?? null;
334
335 if ( !$name ) {
336 throw new SkinException( 'Skin name must be specified' );
337 }
338
339 // Defaults are set in Skin::getOptions()
340 $this->options = $options;
341 $this->skinname = $name;
342 }
343 $this->defaultLinkOptions = $this->getOptions()['link'];
344 $this->componentRegistry = new SkinComponentRegistry(
346 );
347 }
348
352 public function getSkinName() {
353 return $this->skinname;
354 }
355
365 public function isResponsive() {
366 $isSkinResponsiveCapable = $this->getOptions()['responsive'];
367 $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
368
369 return $isSkinResponsiveCapable &&
370 $userOptionsLookup->getBoolOption( $this->getUser(), 'skin-responsive' );
371 }
372
377 public function initPage( OutputPage $out ) {
378 $skinMetaTags = $this->getConfig()->get( MainConfigNames::SkinMetaTags );
379 $siteName = $this->getConfig()->get( MainConfigNames::Sitename );
380 $this->preloadExistence();
381
382 if ( $this->isResponsive() ) {
383 $out->addMeta(
384 'viewport',
385 'width=device-width, initial-scale=1.0, ' .
386 'user-scalable=yes, minimum-scale=0.25, maximum-scale=5.0'
387 );
388 } else {
389 // Force the desktop experience on an iPad by resizing the mobile viewport to
390 // the value of @min-width-breakpoint-desktop (1120px).
391 // This is as @min-width-breakpoint-desktop-wide usually tends to optimize
392 // for larger screens with max-widths and margins.
393 // The initial-scale SHOULD NOT be set here as defining it will impact zoom
394 // on mobile devices.
395 $out->addMeta(
396 'viewport',
397 'width=1120'
398 );
399 }
400
401 $tags = [
402 'og:site_name' => $siteName,
403 'og:title' => $out->getHTMLTitle(),
404 'twitter:card' => 'summary_large_image',
405 'og:type' => 'website',
406 ];
407
408 // Support sharing on platforms such as Facebook and Twitter
409 foreach ( $tags as $key => $value ) {
410 if ( in_array( $key, $skinMetaTags ) ) {
411 $out->addMeta( $key, $value );
412 }
413 }
414 }
415
427 public function getDefaultModules() {
428 $out = $this->getOutput();
429
430 $options = $this->getOptions();
431 // Modules declared in the $modules literal are loaded
432 // for ALL users, on ALL pages, in ALL skins.
433 // Keep this list as small as possible!
434 $modules = [
435 // The 'styles' key sets render-blocking style modules
436 // Unlike other keys in $modules, this is an associative array
437 // where each key is its own group pointing to a list of modules
438 'styles' => [
439 'skin' => $options['styles'],
440 'core' => [],
441 'content' => [],
442 'syndicate' => [],
443 'user' => []
444 ],
445 'core' => [
446 'site',
447 'mediawiki.page.ready',
448 ],
449 // modules that enhance the content in some way
450 'content' => [],
451 // modules relating to search functionality
452 'search' => [],
453 // Skins can register their own scripts
454 'skin' => $options['scripts'],
455 // modules relating to functionality relating to watching an article
456 'watch' => [],
457 // modules which relate to the current users preferences
458 'user' => [],
459 // modules relating to RSS/Atom Feeds
460 'syndicate' => [],
461 ];
462
463 $bodyHtml = $out->getHTML();
464 // Preload jquery.tablesorter for mediawiki.page.ready
465 if ( str_contains( $bodyHtml, 'sortable' ) ) {
466 $modules['content'][] = 'jquery.tablesorter';
467 $modules['styles']['content'][] = 'jquery.tablesorter.styles';
468 }
469
470 // Preload jquery.makeCollapsible for mediawiki.page.ready
471 if ( str_contains( $bodyHtml, 'mw-collapsible' ) ) {
472 $modules['content'][] = 'jquery.makeCollapsible';
473 $modules['styles']['content'][] = 'jquery.makeCollapsible.styles';
474 }
475
476 // Load relevant styles on wiki pages that use mw-ui-button.
477 // Since 1.26, this no longer loads unconditionally. Special pages
478 // and extensions should load this via addModuleStyles() instead.
479 if ( str_contains( $bodyHtml, 'mw-ui-button' ) ) {
480 $modules['styles']['content'][] = 'mediawiki.ui.button';
481 }
482 // Since 1.41, styling for mw-message-box is only required for
483 // messages that appear in article content.
484 // This should only be removed when a suitable alternative exists
485 // e.g. https://phabricator.wikimedia.org/T363607 is resolved.
486 if ( str_contains( $bodyHtml, 'mw-message-box' ) ) {
487 $modules['styles']['content'][] = 'mediawiki.legacy.messageBox';
488 }
489 // Since 1.46, links to temporary accounts in page content are expected to be styled.
490 if ( str_contains( $bodyHtml, 'mw-tempuserlink' ) ) {
491 $modules['styles']['content'][] = 'mediawiki.interface.helpers.styles';
492 $modules['styles']['content'][] = 'mediawiki.interface.helpers.linker.styles';
493 }
494
495 $title = $this->getTitle();
496 $namespace = $title ? $title->getNamespace() : 0;
497 // If the page is using Codex message box markup load Codex styles.
498 // Since 1.41. Skins can unset this if they prefer to handle this via other
499 // means.
500 // For content, this should not be considered stable, and will likely
501 // be removed when https://phabricator.wikimedia.org/T363607 is resolved.
502 $containsUserGeneratedContent = str_contains( $bodyHtml, 'mw-parser-output' );
503 $containsCodexMessageBox = str_contains( $bodyHtml, 'cdx-message' );
504 if ( $containsCodexMessageBox && $containsUserGeneratedContent && $namespace !== NS_SPECIAL ) {
505 $modules['styles']['content'][] = 'mediawiki.codex.messagebox.styles';
506 }
507
508 if ( $out->isTOCEnabled() ) {
509 $modules['content'][] = 'mediawiki.toc';
510 }
511
512 $authority = $this->getAuthority();
513 $relevantTitle = $this->getRelevantTitle();
514 if ( $authority->isRegistered()
515 && $authority->isAllowedAll( 'viewmywatchlist', 'editmywatchlist' )
516 && $relevantTitle && $relevantTitle->canExist()
517 ) {
518 $modules['watch'][] = 'mediawiki.page.watch.ajax';
519 }
520
521 $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
522 $userIdentity = $authority->getUser();
523 if ( $userOptionsLookup->getBoolOption( $userIdentity, 'editsectiononrightclick' )
524 || ( $out->isArticle() && $userOptionsLookup->getOption( $userIdentity, 'editondblclick' ) )
525 ) {
526 $modules['user'][] = 'mediawiki.misc-authed-pref';
527 }
528
529 if ( $out->isSyndicated() ) {
530 $modules['styles']['syndicate'][] = 'mediawiki.feedlink';
531 }
532
533 if ( $authority->isTemp() ) {
534 $modules['user'][] = 'mediawiki.tempUserBanner';
535 $modules['styles']['user'][] = 'mediawiki.tempUserBanner.styles';
536 }
537
538 if ( $namespace === NS_FILE ) {
539 $modules['styles']['core'][] = 'filepage'; // local Filepage.css, T31277, T356505
540 }
541
542 return $modules;
543 }
544
548 private function preloadExistence() {
549 $titles = [];
550
551 // User/talk link
552 $user = $this->getUser();
553 if ( $user->isRegistered() ) {
554 $titles[] = $user->getUserPage();
555 $titles[] = $user->getTalkPage();
556 }
557
558 // Check, if the page can hold some kind of content, otherwise do nothing
559 $title = $this->getRelevantTitle();
560 if ( $title && $title->canExist() && $title->canHaveTalkPage() ) {
561 $namespaceInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
562 if ( $title->isTalkPage() ) {
563 $titles[] = $namespaceInfo->getSubjectPage( $title );
564 } else {
565 $titles[] = $namespaceInfo->getTalkPage( $title );
566 }
567 }
568
569 // Preload for self::getCategoryLinks
570 $allCats = $this->getOutput()->getCategoryLinks();
571 if ( isset( $allCats['normal'] ) && $allCats['normal'] !== [] ) {
572 $catLink = Title::newFromText( $this->msg( 'pagecategorieslink' )->inContentLanguage()->text() );
573 if ( $catLink ) {
574 // If this is a special page, the LinkBatch would skip it
575 $titles[] = $catLink;
576 }
577 }
578
579 $this->getHookRunner()->onSkinPreloadExistence( $titles, $this );
580
581 if ( $titles ) {
582 $linkBatchFactory = MediaWikiServices::getInstance()->getLinkBatchFactory();
583 $linkBatchFactory->newLinkBatch( $titles )
584 ->setCaller( __METHOD__ )
585 ->execute();
586 }
587 }
588
593 public function setRelevantTitle( $t ) {
594 $this->mRelevantTitle = $t;
595 }
596
608 public function getRelevantTitle() {
609 return $this->mRelevantTitle ?? $this->getTitle();
610 }
611
616 public function setRelevantUser( ?UserIdentity $u ) {
617 $this->mRelevantUser = $u;
618 }
619
629 public function getRelevantUser(): ?UserIdentity {
630 if ( $this->mRelevantUser === false ) {
631 $this->mRelevantUser = null; // false indicates we never attempted to load it.
632 $title = $this->getRelevantTitle();
633 if ( $title->hasSubjectNamespace( NS_USER ) ) {
634 $services = MediaWikiServices::getInstance();
635 $rootUser = $title->getRootText();
636 $userNameUtils = $services->getUserNameUtils();
637 if ( $userNameUtils->isIP( $rootUser ) ) {
638 $this->mRelevantUser = UserIdentityValue::newAnonymous( $rootUser );
639 } else {
640 $user = $services->getUserIdentityLookup()->getUserIdentityByName( $rootUser );
641 $this->mRelevantUser = $user && $user->isRegistered() ? $user : null;
642 }
643 }
644 }
645
646 // The relevant user should only be set if it exists. However, if it exists but is hidden,
647 // and the viewer cannot see hidden users, this exposes the fact that the user exists;
648 // pretend like the user does not exist in such cases, by setting it to null. T120883
649 if ( $this->mRelevantUser && $this->mRelevantUser->isRegistered() ) {
650 $userBlock = MediaWikiServices::getInstance()
651 ->getBlockManager()
652 ->getBlock( $this->mRelevantUser, null );
653 if ( $userBlock && $userBlock->getHideName() &&
654 !$this->getAuthority()->isAllowed( 'hideuser' )
655 ) {
656 $this->mRelevantUser = null;
657 }
658 }
659
660 return $this->mRelevantUser;
661 }
662
667 final public function outputPageFinal( OutputPage $out ) {
668 // generate body
669 ob_start();
670 $this->outputPage();
671 $html = ob_get_contents();
672 ob_end_clean();
673
674 // T259955: OutputPage::headElement must be called last
675 // as it calls OutputPage::getRlClient, which freezes the ResourceLoader
676 // modules queue for the current page load.
677 // Since Skins can add ResourceLoader modules via OutputPage::addModule
678 // and OutputPage::addModuleStyles changing this order can lead to
679 // bugs.
680 $head = $out->headElement( $this );
681 $tail = $out->tailElement( $this );
682
683 echo $head . $html . $tail;
684 }
685
689 abstract public function outputPage();
690
696 public function getPageClasses( $title ) {
697 $services = MediaWikiServices::getInstance();
698 $ns = $title->getNamespace();
699 $numeric = 'ns-' . $ns;
700
701 if ( $title->isSpecialPage() ) {
702 $type = 'ns-special';
703 // T25315: provide a class based on the canonical special page name without subpages
704 [ $canonicalName ] = $services->getSpecialPageFactory()->resolveAlias( $title->getDBkey() );
705 if ( $canonicalName ) {
706 $type .= ' ' . Sanitizer::escapeClass( "mw-special-$canonicalName" );
707 } else {
708 $type .= ' mw-invalidspecialpage';
709 }
710 } else {
711 if ( $title->isTalkPage() ) {
712 $type = 'ns-talk';
713 } else {
714 $type = 'ns-subject';
715 }
716 // T208315: add HTML class when the user can edit the page
717 if ( $this->getAuthority()->probablyCan( 'edit', $title ) ) {
718 $type .= ' mw-editable';
719 }
720 }
721
722 $titleFormatter = $services->getTitleFormatter();
723 $name = Sanitizer::escapeClass( 'page-' . $titleFormatter->getPrefixedText( $title ) );
724 $root = Sanitizer::escapeClass( 'rootpage-' . $titleFormatter->formatTitle( $ns, $title->getRootText() ) );
725 // Add a static class that is not subject to translation to allow extensions/skins/global code to target main
726 // pages reliably (T363281)
727 if ( $title->isMainPage() ) {
728 $name .= ' page-Main_Page';
729 }
730
731 return "$numeric $type $name $root";
732 }
733
738 public function getHtmlElementAttributes() {
739 $lang = $this->getLanguage();
740 return [
741 'lang' => $lang->getHtmlCode(),
742 'dir' => $lang->getDir(),
743 'class' => 'client-nojs',
744 ];
745 }
746
750 public function getCategoryLinks() {
751 $out = $this->getOutput();
752 $allCats = $out->getCategoryLinks();
753 $title = $this->getTitle();
754 $services = MediaWikiServices::getInstance();
755 $linkRenderer = $services->getLinkRenderer();
756
757 if ( $allCats === [] ) {
758 return '';
759 }
760
761 $embed = "<li>";
762 $pop = "</li>";
763
764 $s = '';
765 $colon = $this->msg( 'colon-separator' )->escaped();
766
767 if ( !empty( $allCats['normal'] ) ) {
768 $t = $embed . implode( $pop . $embed, $allCats['normal'] ) . $pop;
769
770 $msg = $this->msg( 'pagecategories' )->numParams( count( $allCats['normal'] ) );
771 $linkPage = $this->msg( 'pagecategorieslink' )->inContentLanguage()->text();
772 $pageCategoriesLinkTitle = Title::newFromText( $linkPage );
773 if ( $pageCategoriesLinkTitle ) {
774 $link = $linkRenderer->makeLink( $pageCategoriesLinkTitle, $msg->text() );
775 } else {
776 $link = $msg->escaped();
777 }
778 $s .= Html::rawElement(
779 'div',
780 [ 'id' => 'mw-normal-catlinks', 'class' => 'mw-normal-catlinks' ],
781 $link . $colon . Html::rawElement( 'ul', [], $t )
782 );
783 }
784
785 # Hidden categories
786 if ( isset( $allCats['hidden'] ) ) {
787 $userOptionsLookup = $services->getUserOptionsLookup();
788
789 if ( $userOptionsLookup->getBoolOption( $this->getUser(), 'showhiddencats' ) ) {
790 $class = ' mw-hidden-cats-user-shown';
791 } elseif ( $title->inNamespace( NS_CATEGORY ) ) {
792 $class = ' mw-hidden-cats-ns-shown';
793 } else {
794 $class = ' mw-hidden-cats-hidden';
795 }
796
797 $s .= Html::rawElement(
798 'div',
799 [ 'id' => 'mw-hidden-catlinks', 'class' => "mw-hidden-catlinks$class" ],
800 $this->msg( 'hidden-categories' )->numParams( count( $allCats['hidden'] ) )->escaped() .
801 $colon .
802 Html::rawElement(
803 'ul',
804 [],
805 $embed . implode( $pop . $embed, $allCats['hidden'] ) . $pop
806 )
807 );
808 }
809
810 return $s;
811 }
812
816 public function getCategories() {
817 $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
818 $showHiddenCats = $userOptionsLookup->getBoolOption( $this->getUser(), 'showhiddencats' );
819
820 $catlinks = $this->getCategoryLinks();
821 // Check what we're showing
822 $allCats = $this->getOutput()->getCategoryLinks();
823 $showHidden = $showHiddenCats || $this->getTitle()->inNamespace( NS_CATEGORY );
824
825 $classes = [ 'catlinks' ];
826 if ( empty( $allCats['normal'] ) && !( !empty( $allCats['hidden'] ) && $showHidden ) ) {
827 $classes[] = 'catlinks-allhidden';
828 }
829
830 return Html::rawElement(
831 'div',
832 [ 'id' => 'catlinks', 'class' => $classes,
833 'data-mw-interface' => '' ],
834 $catlinks
835 );
836 }
837
852 protected function afterContentHook() {
853 $data = '';
854
855 if ( $this->getHookRunner()->onSkinAfterContent( $data, $this ) ) {
856 // adding just some spaces shouldn't toggle the output
857 // of the whole <div/>, so we use trim() here
858 if ( trim( $data ) != '' ) {
859 // Doing this here instead of in the skins to
860 // ensure that the div has the same ID in all
861 // skins
862 $data = "<div id='mw-data-after-content'>\n" .
863 "\t$data\n" .
864 "</div>\n";
865 }
866 } else {
867 wfDebug( "Hook SkinAfterContent changed output processing." );
868 }
869
870 return $data;
871 }
872
878 private function getCanonicalUrl() {
879 $title = $this->getTitle();
880 $oldid = $this->getOutput()->getRevisionId();
881 if ( $oldid ) {
882 return $title->getCanonicalURL( 'oldid=' . $oldid );
883 } else {
884 // oldid not available for non existing pages
885 return $title->getCanonicalURL();
886 }
887 }
888
896 public function printSource() {
897 $urlUtils = MediaWikiServices::getInstance()->getUrlUtils();
898 $url = htmlspecialchars( $urlUtils->expandIRI( $this->getCanonicalUrl() ) ?? '' );
899
900 return $this->msg( 'retrievedfrom' )
901 ->rawParams( '<a dir="ltr" href="' . $url . '">' . $url . '</a>' )
902 ->parse();
903 }
904
908 public function getUndeleteLink() {
909 $action = $this->getRequest()->getRawVal( 'action' ) ?? 'view';
910 $title = $this->getTitle();
911 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
912
913 if ( ( !$title->exists() || $action == 'history' ) &&
914 $this->getAuthority()->probablyCan( 'deletedhistory', $title )
915 ) {
916 $n = $title->getDeletedEditsCount();
917
918 if ( $n ) {
919 if ( $this->getAuthority()->probablyCan( 'undelete', $title ) ) {
920 $msg = 'thisisdeleted';
921 } else {
922 $msg = 'viewdeleted';
923 }
924
925 $subtitle = $this->msg( $msg )->rawParams(
926 $linkRenderer->makeKnownLink(
927 SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedDBkey() ),
928 $this->msg( 'restorelink' )->numParams( $n )->text() )
929 )->escaped();
930
931 $links = [];
932 // Add link to page logs, unless we're on the history page (which
933 // already has one)
934 if ( $action !== 'history' ) {
935 $links[] = $linkRenderer->makeKnownLink(
936 SpecialPage::getTitleFor( 'Log' ),
937 $this->msg( 'viewpagelogs-lowercase' )->text(),
938 [],
939 [ 'page' => $title->getPrefixedText() ]
940 );
941 }
942
943 // Allow extensions to add more links
944 $this->getHookRunner()->onUndeletePageToolLinks(
945 $this->getContext(), $linkRenderer, $links );
946
947 if ( $links ) {
948 $subtitle .= ''
949 . $this->msg( 'word-separator' )->escaped()
950 . $this->msg( 'parentheses' )
951 ->rawParams( $this->getLanguage()->pipeList( $links ) )
952 ->escaped();
953 }
954
955 return Html::rawElement( 'div', [ 'class' => 'mw-undelete-subtitle' ], $subtitle );
956 }
957 }
958
959 return '';
960 }
961
965 private function subPageSubtitleInternal() {
966 $services = MediaWikiServices::getInstance();
967 $linkRenderer = $services->getLinkRenderer();
968 $out = $this->getOutput();
969 $title = $out->getTitle();
970 $subpages = '';
971
972 if ( !$this->getHookRunner()->onSkinSubPageSubtitle( $subpages, $this, $out ) ) {
973 return $subpages;
974 }
975
976 $hasSubpages = $services->getNamespaceInfo()->hasSubpages( $title->getNamespace() );
977 if ( !$out->isArticle() || !$hasSubpages ) {
978 return $subpages;
979 }
980
981 $ptext = $title->getPrefixedText();
982 if ( str_contains( $ptext, '/' ) ) {
983 $links = explode( '/', $ptext );
984 array_pop( $links );
985 $count = 0;
986 $growingLink = '';
987 $display = '';
988 $lang = $this->getLanguage();
989
990 foreach ( $links as $link ) {
991 $growingLink .= $link;
992 $display .= $link;
993 $linkObj = Title::newFromText( $growingLink );
994
995 if ( $linkObj && $linkObj->isKnown() ) {
996 $getlink = $linkRenderer->makeKnownLink( $linkObj, $display );
997
998 $count++;
999
1000 if ( $count > 1 ) {
1001 $subpages .= $this->msg( 'pipe-separator' )->escaped();
1002 } else {
1003 $subpages .= '&lt; ';
1004 }
1005
1006 $subpages .= Html::rawElement( 'bdi', [ 'dir' => $lang->getDir() ], $getlink );
1007 $display = '';
1008 } else {
1009 $display .= '/';
1010 }
1011 $growingLink .= '/';
1012 }
1013 }
1014
1015 return $subpages;
1016 }
1017
1025 private function getFooterTemplateDataItem( string $dataKey, string $name ) {
1026 $footerData = $this->getComponent( 'footer' )->getTemplateData();
1027 $items = $footerData[ $dataKey ]['array-items'] ?? [];
1028 foreach ( $items as $item ) {
1029 if ( $item['name'] === $name ) {
1030 return $item['html'];
1031 }
1032 }
1033 return '';
1034 }
1035
1036 final public function getCopyright(): string {
1037 return $this->getFooterTemplateDataItem( 'data-info', 'copyright' );
1038 }
1039
1044 public function logoText( $align = '' ) {
1045 if ( $align != '' ) {
1046 $a = " style='float: {$align};'";
1047 } else {
1048 $a = '';
1049 }
1050
1051 $mp = $this->msg( 'mainpage' )->escaped();
1052 $url = htmlspecialchars( Title::newMainPage()->getLocalURL() );
1053
1054 $logourl = RL\SkinModule::getAvailableLogos(
1055 $this->getConfig(),
1056 $this->getLanguage()->getCode()
1057 )[ '1x' ];
1058 return "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>";
1059 }
1060
1070 final public function getFooterIcons() {
1071 return SkinComponentFooter::getFooterIconsData(
1072 $this->getConfig()
1073 );
1074 }
1075
1087 final public function makeFooterIcon( $icon, $withImage = 'withImage' ) {
1088 return SkinComponentFooter::makeFooterIconHTML(
1089 $this->getConfig(), $icon, $withImage
1090 );
1091 }
1092
1100 public function editUrlOptions() {
1101 $options = [ 'action' => 'edit' ];
1102 $out = $this->getOutput();
1103
1104 if ( !$out->isRevisionCurrent() ) {
1105 $options['oldid'] = intval( $out->getRevisionId() );
1106 }
1107
1108 return $options;
1109 }
1110
1115 public function showEmailUser( $id ) {
1116 if ( $id instanceof UserIdentity ) {
1117 $targetUser = User::newFromIdentity( $id );
1118 } else {
1119 $targetUser = User::newFromId( $id );
1120 }
1121
1122 # The sending user must have a confirmed email address and the receiving
1123 # user must accept emails from the sender.
1124 $emailUser = MediaWikiServices::getInstance()->getEmailUserFactory()
1125 ->newEmailUser( $this->getUser() );
1126
1127 return $emailUser->canSend()->isOK()
1128 && $emailUser->validateTarget( $targetUser )->isOK();
1129 }
1130
1131 /* these are used extensively in SkinTemplate, but also some other places */
1132
1137 public static function makeMainPageUrl( $urlaction = '' ) {
1138 $title = Title::newMainPage();
1139
1140 return $title->getLinkURL( $urlaction );
1141 }
1142
1149 public static function makeInternalOrExternalUrl( $name ) {
1150 $protocols = MediaWikiServices::getInstance()->getUrlUtils()->validProtocols();
1151
1152 if ( preg_match( '/^(?i:' . $protocols . ')/', $name ) ) {
1153 return $name;
1154 } else {
1155 $title = $name instanceof Title ? $name : Title::newFromText( $name );
1156 return $title ? $title->getLinkURL() : '';
1157 }
1158 }
1159
1166 protected static function makeUrlDetails( $name, $urlaction = '' ) {
1167 $title = $name instanceof Title ? $name : Title::newFromText( $name );
1168 return [
1169 'href' => $title ? $title->getLocalURL( $urlaction ) : '',
1170 'exists' => $title && $title->isKnown(),
1171 ];
1172 }
1173
1180 protected static function makeKnownUrlDetails( $name, $urlaction = '' ) {
1181 $title = $name instanceof Title ? $name : Title::newFromText( $name );
1182 return [
1183 'href' => $title ? $title->getLocalURL( $urlaction ) : '',
1184 'exists' => (bool)$title,
1185 ];
1186 }
1187
1196 public function mapInterwikiToLanguage( $code ) {
1197 $map = $this->getConfig()->get( MainConfigNames::InterlanguageLinkCodeMap );
1198 return $map[ $code ] ?? $code;
1199 }
1200
1209 public function getLanguages() {
1210 if ( $this->getConfig()->get( MainConfigNames::HideInterlanguageLinks ) ) {
1211 return [];
1212 }
1213 if ( $this->languageLinks === null ) {
1214 $hookRunner = $this->getHookRunner();
1215
1216 $userLang = $this->getLanguage();
1217 $languageLinks = [];
1218 $langNameUtils = MediaWikiServices::getInstance()->getLanguageNameUtils();
1219
1220 foreach ( $this->getOutput()->getLanguageLinks() as $languageLinkText ) {
1221 [ $prefix, $title ] = explode( ':', $languageLinkText, 2 );
1222 $class = 'interlanguage-link interwiki-' . $prefix;
1223
1224 [ $title, $frag ] = array_pad( explode( '#', $title, 2 ), 2, '' );
1225 $languageLinkTitle = TitleValue::tryNew( NS_MAIN, $title, $frag, $prefix );
1226 if ( $languageLinkTitle === null ) {
1227 continue;
1228 }
1229 $ilInterwikiCode = $this->mapInterwikiToLanguage( $prefix );
1230
1231 $ilLangName = $langNameUtils->getLanguageName( $ilInterwikiCode );
1232
1233 if ( strval( $ilLangName ) === '' ) {
1234 $ilDisplayTextMsg = $this->msg( "interlanguage-link-$ilInterwikiCode" );
1235 if ( !$ilDisplayTextMsg->isDisabled() ) {
1236 // Use custom MW message for the display text
1237 $ilLangName = $ilDisplayTextMsg->text();
1238 } else {
1239 // Last resort: fallback to the language link target
1240 $ilLangName = $languageLinkText;
1241 }
1242 } else {
1243 // Use the language autonym as display text
1244 $ilLangName = $this->getLanguage()->ucfirst( $ilLangName );
1245 }
1246
1247 // CLDR extension or similar is required to localize the language name;
1248 // otherwise we'll end up with the autonym again.
1249 $ilLangLocalName =
1250 $langNameUtils->getLanguageName( $ilInterwikiCode, $userLang->getCode() );
1251
1252 $languageLinkTitleText = $languageLinkTitle->getText();
1253 if ( $ilLangLocalName === '' ) {
1254 $ilFriendlySiteName =
1255 $this->msg( "interlanguage-link-sitename-$ilInterwikiCode" );
1256 if ( !$ilFriendlySiteName->isDisabled() ) {
1257 if ( $languageLinkTitleText === '' ) {
1258 $ilTitle =
1259 $this->msg( 'interlanguage-link-title-nonlangonly',
1260 $ilFriendlySiteName->text() )->text();
1261 } else {
1262 $ilTitle =
1263 $this->msg( 'interlanguage-link-title-nonlang',
1264 $languageLinkTitleText, $ilFriendlySiteName->text() )->text();
1265 }
1266 } else {
1267 // we have nothing friendly to put in the title, so fall back to
1268 // displaying the interlanguage link itself in the title text
1269 // (similar to what is done in page content)
1270 $ilTitle = $languageLinkTitle->getInterwiki() . ":$languageLinkTitleText";
1271 }
1272 } elseif ( $languageLinkTitleText === '' ) {
1273 $ilTitle =
1274 $this->msg( 'interlanguage-link-title-langonly', $ilLangLocalName )->text();
1275 } else {
1276 $ilTitle =
1277 $this->msg( 'interlanguage-link-title', $languageLinkTitleText,
1278 $ilLangLocalName )->text();
1279 }
1280
1281 $ilInterwikiCodeBCP47 = LanguageCode::bcp47( $ilInterwikiCode );
1282 // A TitleValue is sufficient above this point, but we need
1283 // a full Title for ::getFullURL() and the hook invocation
1284 $languageLinkFullTitle = Title::newFromLinkTarget( $languageLinkTitle );
1285 $languageLink = [
1286 'href' => $languageLinkFullTitle->getFullURL(),
1287 'text' => $ilLangName,
1288 'title' => $ilTitle,
1289 'class' => $class,
1290 'link-class' => 'interlanguage-link-target',
1291 'lang' => $ilInterwikiCodeBCP47,
1292 'hreflang' => $ilInterwikiCodeBCP47,
1293 'data-title' => $languageLinkTitleText,
1294 'data-language-autonym' => $ilLangName,
1295 'data-language-local-name' => $ilLangLocalName,
1296 ];
1297 $hookRunner->onSkinTemplateGetLanguageLink(
1298 $languageLink, $languageLinkFullTitle, $this->getTitle(), $this->getOutput()
1299 );
1300 $languageLinks[] = $languageLink;
1301 }
1302 $this->languageLinks = $languageLinks;
1303 }
1304
1305 return $this->languageLinks;
1306 }
1307
1314 protected function buildNavUrls() {
1315 $services = MediaWikiServices::getInstance();
1316 $out = $this->getOutput();
1317 $title = $this->getTitle();
1318 $thispage = $title->getPrefixedDBkey();
1319 $uploadNavigationUrl = $this->getConfig()->get( MainConfigNames::UploadNavigationUrl );
1320
1321 $nav_urls = [];
1322 $nav_urls['mainpage'] = [ 'href' => self::makeMainPageUrl() ];
1323 if ( $uploadNavigationUrl ) {
1324 $nav_urls['upload'] = [ 'href' => $uploadNavigationUrl ];
1325 } elseif ( UploadBase::isEnabled() && UploadBase::isAllowed( $this->getAuthority() ) === true ) {
1326 $nav_urls['upload'] = [ 'href' => SkinComponentUtils::makeSpecialUrl( 'Upload' ) ];
1327 } else {
1328 $nav_urls['upload'] = false;
1329 }
1330
1331 $nav_urls['print'] = false;
1332 $nav_urls['permalink'] = false;
1333 $nav_urls['info'] = false;
1334 $nav_urls['whatlinkshere'] = false;
1335 $nav_urls['recentchangeslinked'] = false;
1336 $nav_urls['contributions'] = false;
1337 $nav_urls['log'] = false;
1338 $nav_urls['blockip'] = false;
1339 $nav_urls['changeblockip'] = false;
1340 $nav_urls['unblockip'] = false;
1341 $nav_urls['mute'] = false;
1342 $nav_urls['emailuser'] = false;
1343 $nav_urls['userrights'] = false;
1344
1345 // A print stylesheet is attached to all pages, but nobody ever
1346 // figures that out. :) Add a link...
1347 if ( !$out->isPrintable() && ( $out->isArticle() || $title->isSpecialPage() ) ) {
1348 $nav_urls['print'] = [
1349 'text' => $this->msg( 'printableversion' )->text(),
1350 'href' => 'javascript:print();'
1351 ];
1352 }
1353
1354 if ( $out->isArticle() ) {
1355 // Also add a "permalink" while we're at it
1356 $revid = $out->getRevisionId();
1357 if ( $revid ) {
1358 $nav_urls['permalink'] = [
1359 'icon' => 'link',
1360 'text' => $this->msg( 'permalink' )->text(),
1361 'href' => $title->getLocalURL( "oldid=$revid" )
1362 ];
1363 }
1364 }
1365
1366 if ( $out->isArticleRelated() ) {
1367 $nav_urls['whatlinkshere'] = [
1368 'href' => SpecialPage::getTitleFor( 'Whatlinkshere', $thispage )->getLocalURL()
1369 ];
1370
1371 $nav_urls['info'] = [
1372 'icon' => 'infoFilled',
1373 'text' => $this->msg( 'pageinfo-toolboxlink' )->text(),
1374 'href' => $title->getLocalURL( "action=info" )
1375 ];
1376
1377 if ( $title->exists() || $title->inNamespace( NS_CATEGORY ) ) {
1378 $nav_urls['recentchangeslinked'] = [
1379 'href' => SpecialPage::getTitleFor( 'Recentchangeslinked', $thispage )->getLocalURL()
1380 ];
1381 }
1382 }
1383
1384 $user = $this->getRelevantUser();
1385 $target = false;
1386 $targetIsIpRange = false;
1387 if ( $user ) {
1388 // This will either be an account or an IP
1389 $target = $user->getName();
1390 } else {
1391 // Support finding the IP range if its the target
1392 $pageTarget = $this->getPageTarget();
1393 if ( $pageTarget ) {
1394 $CIDRLimit = $this->getConfig()
1395 ->get( MainConfigNames::BlockCIDRLimit );
1396 [ $ip, $range ] = explode( '/', $pageTarget, 2 );
1397 if (
1398 ( IPUtils::isIPv4( $ip ) && $range >= $CIDRLimit['IPv4'] ) ||
1399 ( IPUtils::isIPv6( $ip ) && $range >= $CIDRLimit['IPv6'] )
1400 ) {
1401 $target = IPUtils::sanitizeRange( $pageTarget );
1402 $targetIsIpRange = true;
1403 }
1404 }
1405 }
1406 if ( !$target ) {
1407 return $nav_urls;
1408 }
1409
1410 $nav_urls['contributions'] = [
1411 'text' => $this->msg( 'tool-link-contributions', $target )->text(),
1412 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Contributions', $target ),
1413 'tooltip-params' => [ $target ],
1414 ];
1415 $nav_urls['log'] = [
1416 'icon' => 'listBullet',
1417 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Log', $target )
1418 ];
1419
1420 // Check if the user/ip/ip range is blocked
1421 if ( $this->getAuthority()->isAllowed( 'block' ) ) {
1422 $userBlock = null;
1423 if ( $targetIsIpRange ) {
1424 // getBlock doesn't support ip range lookups so check independently if the target is a range
1425 $userBlock = $services
1426 ->getBlockManager()
1427 ->getIpRangeBlock( $target );
1428 } elseif ( $user ) {
1429 // Check if the user or IP is already blocked
1430 $userBlock = $services
1431 ->getBlockManager()
1432 ->getBlock( $user, null );
1433 }
1434
1435 // If the block exists, only continue if it's not an autoblock. See T384147.
1436 if (
1437 $userBlock &&
1438 $userBlock->getType() !== Block::TYPE_AUTO
1439 ) {
1440 $useCodex = $this->getConfig()->get( MainConfigNames::UseCodexSpecialBlock );
1441 $nav_urls[ $useCodex ? 'block-manage-blocks' : 'changeblockip' ] = [
1442 'icon' => 'block',
1443 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Block', $target )
1444 ];
1445 if ( !$useCodex ) {
1446 $nav_urls['unblockip'] = [
1447 'icon' => 'unBlock',
1448 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Unblock', $target ),
1449 'text' => $this->msg(
1450 $targetIsIpRange ? 'unblockiprange' : 'unblockip'
1451 )->text(),
1452 ];
1453 }
1454 } else {
1455 $nav_urls['blockip'] = [
1456 'icon' => 'block',
1457 'text' => $this->msg(
1458 $targetIsIpRange ? 'blockiprange' : 'blockip'
1459 )->text(),
1460 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Block', $target ),
1461 ];
1462 }
1463 }
1464
1465 if ( $user ) {
1466 if ( $this->showEmailUser( $user ) ) {
1467 $nav_urls['emailuser'] = [
1468 'text' => $this->msg( 'tool-link-emailuser', $target )->text(),
1469 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Emailuser', $target ),
1470 'tooltip-params' => [ $target ],
1471 ];
1472 }
1473
1474 if ( $user->isRegistered() ) {
1475 if ( $this->getUser()->isNamed() ) {
1476 $nav_urls['mute'] = [
1477 'text' => $this->msg( 'mute-preferences' )->text(),
1478 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Mute', $target )
1479 ];
1480 }
1481
1482 // Don't show links to Special:UserRights for temporary accounts (as they cannot have groups)
1483 $userNameUtils = $services->getUserNameUtils();
1484 $userGroupsAssignmentService = $services->getUserGroupAssignmentService();
1485 if ( !$userNameUtils->isTemp( $user->getName() ) ) {
1486 $canChange = $userGroupsAssignmentService->userCanChangeRights(
1487 $this->getAuthority(),
1488 $user
1489 );
1490 $delimiter = $this->getConfig()->get(
1491 MainConfigNames::UserrightsInterwikiDelimiter );
1492 if ( str_contains( $target, $delimiter ) ) {
1493 // Username contains interwiki delimiter, link it via the
1494 // #{userid} syntax. (T260222)
1495 $linkArgs = [ false, [ 'user' => '#' . $user->getId() ] ];
1496 } else {
1497 $linkArgs = [ $target ];
1498 }
1499 $nav_urls['userrights'] = [
1500 'icon' => 'userGroup',
1501 'text' => $this->msg(
1502 $canChange ? 'tool-link-userrights' : 'tool-link-userrights-readonly',
1503 $target
1504 )->text(),
1505 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Userrights', ...$linkArgs )
1506 ];
1507 }
1508 }
1509 }
1510
1511 return $nav_urls;
1512 }
1513
1519 final protected function buildFeedUrls() {
1520 $feeds = [];
1521 $out = $this->getOutput();
1522 if ( $out->isSyndicated() ) {
1523 foreach ( $out->getSyndicationLinks() as $format => $link ) {
1524 $feeds[$format] = [
1525 // Messages: feed-atom, feed-rss
1526 'text' => $this->msg( "feed-$format" )->text(),
1527 'href' => $link
1528 ];
1529 }
1530 }
1531 return $feeds;
1532 }
1533
1559 public function buildSidebar() {
1560 if ( $this->sidebar === null ) {
1561 $services = MediaWikiServices::getInstance();
1562 $callback = function ( $old = null, &$ttl = null ) {
1563 $bar = [];
1564 $this->addToSidebar( $bar, 'sidebar' );
1565
1566 // This hook may vary its behaviour by skin.
1567 $this->getHookRunner()->onSkinBuildSidebar( $this, $bar );
1568 $msgCache = MediaWikiServices::getInstance()->getMessageCache();
1569 if ( $msgCache->isDisabled() ) {
1570 // Don't cache the fallback if DB query failed. T133069
1571 $ttl = WANObjectCache::TTL_UNCACHEABLE;
1572 }
1573
1574 return $bar;
1575 };
1576
1577 $msgCache = $services->getMessageCache();
1578 $wanCache = $services->getMainWANObjectCache();
1579 $config = $this->getConfig();
1580 $languageCode = $this->getLanguage()->getCode();
1581
1582 $sidebar = $config->get( MainConfigNames::EnableSidebarCache )
1583 ? $wanCache->getWithSetCallback(
1584 $wanCache->makeKey( 'sidebar', $languageCode, $this->getSkinName() ?? '' ),
1585 $config->get( MainConfigNames::SidebarCacheExpiry ),
1586 $callback,
1587 [
1588 'checkKeys' => [
1589 // Unless there is both no exact $code override nor an i18n definition
1590 // in the software, the only MediaWiki page to check is for $code.
1591 $msgCache->getCheckKey( $languageCode )
1592 ],
1593 'lockTSE' => 30
1594 ]
1595 )
1596 : $callback();
1597
1598 $sidebar['TOOLBOX'] = array_merge(
1599 $this->makeToolbox(
1600 $this->buildNavUrls(),
1601 $this->buildFeedUrls()
1602 ), $sidebar['TOOLBOX'] ?? []
1603 );
1604
1605 $sidebar['LANGUAGES'] = $this->getLanguages();
1606 // Apply post-processing to the cached value
1607 $this->getHookRunner()->onSidebarBeforeOutput( $this, $sidebar );
1608
1609 $this->sidebar = $sidebar;
1610 }
1611
1612 return $this->sidebar;
1613 }
1614
1624 public function addToSidebar( &$bar, $message ) {
1625 $this->addToSidebarPlain( $bar, $this->msg( $message )->inContentLanguage()->plain() );
1626 }
1627
1634 private function createSidebarItem( $target, $text ) {
1635 $config = $this->getConfig();
1636 $messageTitle = $config->get( MainConfigNames::EnableSidebarCache )
1637 ? Title::newMainPage() : $this->getTitle();
1638 $services = MediaWikiServices::getInstance();
1639 $urlUtils = $services->getUrlUtils();
1640
1641 $extraAttribs = [];
1642
1643 $msgLink = $this->msg( $target )->page( $messageTitle )->inContentLanguage();
1644 if ( $msgLink->exists() ) {
1645 $link = $msgLink->text();
1646 // Extra check in case a message does fancy stuff with {{#if:… and such
1647 if ( $link === '-' ) {
1648 return null;
1649 }
1650 } else {
1651 $link = $target;
1652 }
1653 $msgText = $this->msg( $text )->page( $messageTitle );
1654 if ( $msgText->exists() ) {
1655 $parsedText = $msgText->text();
1656 } else {
1657 $parsedText = $text;
1658 }
1659
1660 if ( preg_match( '/^(?i:' . $urlUtils->validProtocols() . ')/', $link ) ) {
1661 $href = $link;
1662
1663 // Parser::getExternalLinkAttribs won't work here because of the Namespace things
1664 if ( $config->get( MainConfigNames::NoFollowLinks ) &&
1665 !$urlUtils->matchesDomainList(
1666 (string)$href,
1667 (array)$config->get( MainConfigNames::NoFollowDomainExceptions )
1668 )
1669 ) {
1670 $extraAttribs['rel'] = 'nofollow';
1671 }
1672
1673 if ( $config->get( MainConfigNames::ExternalLinkTarget ) ) {
1674 $extraAttribs['target'] =
1675 $config->get( MainConfigNames::ExternalLinkTarget );
1676 }
1677 } else {
1678 $title = Title::newFromText( $link );
1679 $href = $title ? $title->fixSpecialName()->getLinkURL() : '';
1680 }
1681
1682 $id = strtr( $text, ' ', '-' );
1683 return $extraAttribs + [
1684 'text' => $parsedText,
1685 'href' => $href,
1686 'icon' => $this->getSidebarIcon( $id ),
1687 'id' => Sanitizer::escapeIdForAttribute( 'n-' . $id ),
1688 'active' => false,
1689 ];
1690 }
1691
1699 public function addToSidebarPlain( &$bar, $text ) {
1700 $lines = explode( "\n", $text );
1701
1702 $heading = '';
1703 $config = $this->getConfig();
1704 $messageTitle = $config->get( MainConfigNames::EnableSidebarCache )
1705 ? Title::newMainPage() : $this->getTitle();
1706 $services = MediaWikiServices::getInstance();
1707 $messageParser = $services->getMessageParser();
1708 $urlUtils = $services->getUrlUtils();
1709
1710 foreach ( $lines as $line ) {
1711 if ( !str_starts_with( $line, '*' ) ) {
1712 continue;
1713 }
1714 $line = rtrim( $line, "\r" ); // for Windows compat
1715
1716 if ( !str_starts_with( $line, '**' ) ) {
1717 $heading = trim( $line, '* ' );
1718 if ( !array_key_exists( $heading, $bar ) ) {
1719 $bar[$heading] = [];
1720 }
1721 } else {
1722 $line = trim( $line, '* ' );
1723
1724 if ( str_contains( $line, '|' ) ) {
1725 $line = $messageParser->transform( $line, false, null, $messageTitle );
1726 $line = array_map( 'trim', explode( '|', $line, 2 ) );
1727 if ( count( $line ) !== 2 ) {
1728 // Second check, could be hit by people doing
1729 // funky stuff with parserfuncs... (T35321)
1730 continue;
1731 }
1732
1733 $item = $this->createSidebarItem( $line[0], $line[1] );
1734 if ( $item !== null ) {
1735 $bar[$heading][] = $item;
1736 }
1737 }
1738 }
1739 }
1740
1741 return $bar;
1742 }
1743
1748 private function getSidebarIcon( string $id ) {
1749 switch ( $id ) {
1750 case 'mainpage-description':
1751 return 'home';
1752 case 'randompage':
1753 return 'die';
1754 case 'recentchanges':
1755 return 'recentChanges';
1756 // These menu items are commonly added in MediaWiki:Sidebar. We should
1757 // reconsider the location of this logic in future.
1758 case 'help':
1759 case 'help-mediawiki':
1760 return 'help';
1761 case 'specialpages':
1762 return 'specialPages';
1763 default:
1764 return null;
1765 }
1766 }
1767
1784 private function hideNewTalkMessagesForCurrentSession() {
1785 // Only show new talk page notification if there is a session,
1786 // (the client edited a page from this browser, or is logged-in).
1787 return !$this->getRequest()->getSession()->isPersistent();
1788 }
1789
1795 public function getNewtalks() {
1796 if ( $this->hideNewTalkMessagesForCurrentSession() ) {
1797 return '';
1798 }
1799
1800 $newMessagesAlert = '';
1801 $user = $this->getUser();
1802 $services = MediaWikiServices::getInstance();
1803 $linkRenderer = $services->getLinkRenderer();
1804 $userHasNewMessages = $services->getTalkPageNotificationManager()
1805 ->userHasNewMessages( $user );
1806 $timestamp = $services->getTalkPageNotificationManager()
1807 ->getLatestSeenMessageTimestamp( $user );
1808 $newtalks = !$userHasNewMessages ? [] : [
1809 [
1810 // TODO: Deprecate adding wiki and link to array and redesign GetNewMessagesAlert hook
1811 'wiki' => WikiMap::getCurrentWikiId(),
1812 'link' => $user->getTalkPage()->getLocalURL(),
1813 'rev' => $timestamp ? $services->getRevisionLookup()
1814 ->getRevisionByTimestamp( $user->getTalkPage(), $timestamp ) : null
1815 ]
1816 ];
1817 $out = $this->getOutput();
1818
1819 // Allow extensions to disable or modify the new messages alert
1820 if ( !$this->getHookRunner()->onGetNewMessagesAlert(
1821 $newMessagesAlert, $newtalks, $user, $out )
1822 ) {
1823 return '';
1824 }
1825 if ( $newMessagesAlert ) {
1826 return $newMessagesAlert;
1827 }
1828
1829 if ( $newtalks !== [] ) {
1830 $uTalkTitle = $user->getTalkPage();
1831 $lastSeenRev = $newtalks[0]['rev'];
1832 $numAuthors = 0;
1833 if ( $lastSeenRev !== null ) {
1834 $plural = true; // Default if we have a last seen revision: if unknown, use plural
1835 $revStore = $services->getRevisionStore();
1836 $latestRev = $revStore->getRevisionByTitle(
1837 $uTalkTitle,
1838 0,
1839 IDBAccessObject::READ_NORMAL
1840 );
1841 if ( $latestRev !== null ) {
1842 // Singular if only 1 unseen revision, plural if several unseen revisions.
1843 $plural = $latestRev->getParentId() !== $lastSeenRev->getId();
1844 $numAuthors = $revStore->countAuthorsBetween(
1845 $uTalkTitle->getArticleID(),
1846 $lastSeenRev,
1847 $latestRev,
1848 null,
1849 10,
1850 RevisionStore::INCLUDE_NEW
1851 );
1852 }
1853 } else {
1854 // Singular if no revision -> diff link will show latest change only in any case
1855 $plural = false;
1856 }
1857 $plural = $plural ? 999 : 1;
1858 // 999 signifies "more than one revision". We don't know how many, and even if we did,
1859 // the number of revisions or authors is not necessarily the same as the number of
1860 // "messages".
1861 $newMessagesLink = $linkRenderer->makeKnownLink(
1862 $uTalkTitle,
1863 $this->msg( 'new-messages-link-plural', $plural )->text(),
1864 [],
1865 $uTalkTitle->isRedirect() ? [ 'redirect' => 'no' ] : []
1866 );
1867
1868 $newMessagesDiffLink = $linkRenderer->makeKnownLink(
1869 $uTalkTitle,
1870 $this->msg( 'new-messages-diff-link-plural', $plural )->text(),
1871 [],
1872 $lastSeenRev !== null
1873 ? [ 'oldid' => $lastSeenRev->getId(), 'diff' => 'cur' ]
1874 : [ 'diff' => 'cur' ]
1875 );
1876
1877 if ( $numAuthors >= 1 && $numAuthors <= 10 ) {
1878 $newMessagesAlert = $this->msg(
1879 'new-messages-from-users'
1880 )->rawParams(
1881 $newMessagesLink,
1882 $newMessagesDiffLink
1883 )->numParams(
1884 $numAuthors,
1885 $plural
1886 );
1887 } else {
1888 // $numAuthors === 11 signifies "11 or more" ("more than 10")
1889 $newMessagesAlert = $this->msg(
1890 $numAuthors > 10 ? 'new-messages-from-many-users' : 'new-messages'
1891 )->rawParams(
1892 $newMessagesLink,
1893 $newMessagesDiffLink
1894 )->numParams( $plural );
1895 }
1896 $newMessagesAlert = $newMessagesAlert->parse();
1897 }
1898
1899 return $newMessagesAlert;
1900 }
1901
1908 protected function getEmailConfirmationNotice(): string {
1909 $services = MediaWikiServices::getInstance();
1910 $component = new SkinComponentEmailConfirmationBanner(
1911 $services->getEmailConfirmationBannerHandler(),
1912 $this->getContext()
1913 );
1914 return $component->getTemplateData()['html'];
1915 }
1916
1924 private function getCachedNotice( $name ) {
1925 $config = $this->getConfig();
1926
1927 if ( $name === 'default' ) {
1928 // special case
1929 $notice = $config->get( MainConfigNames::SiteNotice );
1930 if ( !$notice ) {
1931 return false;
1932 }
1933 } else {
1934 $msg = $this->msg( $name )->inContentLanguage();
1935 if ( $msg->isBlank() ) {
1936 return '';
1937 } elseif ( $msg->isDisabled() ) {
1938 return false;
1939 }
1940 $notice = $msg->plain();
1941 }
1942
1943 $services = MediaWikiServices::getInstance();
1944 $cache = $services->getMainWANObjectCache();
1945 $parsed = $cache->getWithSetCallback(
1946 // Use the extra hash appender to let eg SSL variants separately cache
1947 // Key is verified with md5 hash of unparsed wikitext
1948 $cache->makeKey(
1949 $name, $config->get( MainConfigNames::RenderHashAppend ), md5( $notice ) ),
1950 // TTL in seconds
1951 600,
1952 function () use ( $notice ) {
1953 return $this->getOutput()->parseAsInterface( $notice );
1954 }
1955 );
1956
1957 $contLang = $services->getContentLanguage();
1958 return Html::rawElement(
1959 'div',
1960 [
1961 'class' => $name,
1962 'lang' => $contLang->getHtmlCode(),
1963 'dir' => $contLang->getDir()
1964 ],
1965 $parsed
1966 );
1967 }
1968
1972 public function getSiteNotice() {
1973 $siteNotice = '';
1974
1975 if ( $this->getHookRunner()->onSiteNoticeBefore( $siteNotice, $this ) ) {
1976 if ( $this->getUser()->isRegistered() ) {
1977 $siteNotice = $this->getCachedNotice( 'sitenotice' );
1978 } else {
1979 $anonNotice = $this->getCachedNotice( 'anonnotice' );
1980 if ( $anonNotice === false ) {
1981 $siteNotice = $this->getCachedNotice( 'sitenotice' );
1982 } else {
1983 $siteNotice = $anonNotice;
1984 }
1985 }
1986 if ( $siteNotice === false ) {
1987 $siteNotice = $this->getCachedNotice( 'default' ) ?: '';
1988 }
1989 if ( $this->canUseWikiPage() ) {
1990 $ns = $this->getWikiPage()->getNamespace();
1991 $nsNotice = $this->getCachedNotice( "namespacenotice-$ns" );
1992 if ( $nsNotice ) {
1993 $siteNotice .= $nsNotice;
1994 }
1995 }
1996 if ( $siteNotice !== '' ) {
1997 $siteNotice = Html::rawElement( 'div', [ 'id' => 'localNotice', 'data-nosnippet' => '' ], $siteNotice );
1998 }
1999 }
2000
2001 $this->getHookRunner()->onSiteNoticeAfter( $siteNotice, $this );
2002 $siteNotice = $this->getEmailConfirmationNotice() . $siteNotice;
2003 if ( $this->getOptions()[ 'wrapSiteNotice' ] ) {
2004 $siteNotice = Html::rawElement( 'div', [ 'id' => 'siteNotice' ], $siteNotice );
2005 }
2006 return $siteNotice;
2007 }
2008
2021 public function doEditSectionLink( Title $nt, $section, $sectionTitle, Language $lang ) {
2022 // HTML generated here should probably have userlangattributes
2023 // added to it for LTR text on RTL pages
2024
2025 $attribs = [];
2026 $attribs['title'] = $this->msg( 'editsectionhint' )->plaintextParams( $sectionTitle )
2027 ->inLanguage( $lang )->text();
2028
2029 $links = [
2030 'editsection' => [
2031 'icon' => 'edit',
2032 'text' => $this->msg( 'editsection' )->inLanguage( $lang )->text(),
2033 'targetTitle' => $nt,
2034 'attribs' => $attribs,
2035 'query' => [ 'action' => 'edit', 'section' => $section ]
2036 ]
2037 ];
2038
2039 $this->getHookRunner()->onSkinEditSectionLinks( $this, $nt, $section, $sectionTitle, $links, $lang );
2040
2041 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
2042 $newLinks = [];
2043 $options = $this->defaultLinkOptions + [
2044 'class-as-property' => true,
2045 ];
2046 $ctx = $this->getContext();
2047 foreach ( $links as $key => $linkDetails ) {
2048 $targetTitle = $linkDetails['targetTitle'];
2049 $attrs = $linkDetails['attribs'];
2050 $query = $linkDetails['query'];
2051 unset( $linkDetails['targetTitle'] );
2052 unset( $linkDetails['query'] );
2053 unset( $linkDetails['attribs'] );
2054 unset( $linkDetails['options' ] );
2055 $component = new SkinComponentLink(
2056 $key, $linkDetails + [
2057 'href' => Title::newFromLinkTarget( $targetTitle )->getLinkURL( $query, false ),
2058 ] + $attrs, $ctx, $options
2059 );
2060 $newLinks[] = $component->getTemplateData();
2061 }
2062 return $this->doEditSectionLinksHTML( $newLinks, $lang );
2063 }
2064
2072 protected function doEditSectionLinksHTML( array $links, Language $lang ) {
2073 $result = Html::openElement( 'span', [ 'class' => 'mw-editsection' ] );
2074 $result .= Html::rawElement( 'span', [ 'class' => 'mw-editsection-bracket' ], '[' );
2075
2076 $linksHtml = array_column( $links, 'html' );
2077
2078 if ( count( $linksHtml ) === 1 ) {
2079 $result .= $linksHtml[0];
2080 } else {
2081 $result .= implode(
2082 Html::element( 'span',
2083 [ 'class' => 'mw-editsection-divider' ],
2084 $this->msg( 'pipe-separator' )->inLanguage( $lang )->text()
2085 ),
2086 $linksHtml
2087 );
2088 }
2089
2090 $result .= Html::rawElement( 'span', [ 'class' => 'mw-editsection-bracket' ], ']' );
2091 $result .= Html::closeElement( 'span' );
2092 return $result;
2093 }
2094
2104 public function makeToolbox( $navUrls, $feedUrls ) {
2105 $toolbox = [];
2106 if ( $navUrls['whatlinkshere'] ?? null ) {
2107 $toolbox['whatlinkshere'] = $navUrls['whatlinkshere'];
2108 $toolbox['whatlinkshere']['id'] = 't-whatlinkshere';
2109 $toolbox['whatlinkshere']['icon'] = 'articleRedirect';
2110 }
2111 if ( $navUrls['recentchangeslinked'] ?? null ) {
2112 $toolbox['recentchangeslinked'] = $navUrls['recentchangeslinked'];
2113 $toolbox['recentchangeslinked']['msg'] = 'recentchangeslinked-toolbox';
2114 $toolbox['recentchangeslinked']['id'] = 't-recentchangeslinked';
2115 $toolbox['recentchangeslinked']['rel'] = 'nofollow';
2116 }
2117 if ( $feedUrls ) {
2118 $toolbox['feeds']['id'] = 'feedlinks';
2119 $toolbox['feeds']['links'] = [];
2120 foreach ( $feedUrls as $key => $feed ) {
2121 $toolbox['feeds']['links'][$key] = $feed;
2122 $toolbox['feeds']['links'][$key]['id'] = "feed-$key";
2123 $toolbox['feeds']['links'][$key]['rel'] = 'alternate';
2124 $toolbox['feeds']['links'][$key]['type'] = "application/{$key}+xml";
2125 $toolbox['feeds']['links'][$key]['class'] = 'feedlink';
2126 }
2127 }
2128 foreach ( [ 'contributions', 'log', 'blockip', 'changeblockip', 'unblockip',
2129 'block-manage-blocks', 'emailuser', 'mute', 'userrights', 'upload' ] as $special
2130 ) {
2131 if ( $navUrls[$special] ?? null ) {
2132 $toolbox[$special] = $navUrls[$special];
2133 $toolbox[$special]['id'] = "t-$special";
2134 }
2135 }
2136 if ( $navUrls['print'] ?? null ) {
2137 $toolbox['print'] = $navUrls['print'];
2138 $toolbox['print']['id'] = 't-print';
2139 $toolbox['print']['rel'] = 'alternate';
2140 $toolbox['print']['msg'] = 'printableversion';
2141 }
2142 if ( $navUrls['permalink'] ?? null ) {
2143 $toolbox['permalink'] = $navUrls['permalink'];
2144 $toolbox['permalink']['id'] = 't-permalink';
2145 }
2146 if ( $navUrls['info'] ?? null ) {
2147 $toolbox['info'] = $navUrls['info'];
2148 $toolbox['info']['id'] = 't-info';
2149 }
2150
2151 return $toolbox;
2152 }
2153
2160 protected function getIndicatorsData( array $indicators ): array {
2161 $indicatorData = [];
2162 foreach ( $indicators as $id => $content ) {
2163 $indicatorData[] = [
2164 'id' => Sanitizer::escapeIdForAttribute( "mw-indicator-$id" ),
2165 'class' => 'mw-indicator',
2166 'html' => $content,
2167 ];
2168 }
2169 return $indicatorData;
2170 }
2171
2186 final public function getPersonalToolsForMakeListItem( $urls, $applyClassesToListItems = false ) {
2187 $personal_tools = [];
2188 foreach ( $urls as $key => $plink ) {
2189 # The class on a personal_urls item is meant to go on the <a> instead
2190 # of the <li> so we have to use a single item "links" array instead
2191 # of using most of the personal_url's keys directly.
2192 $ptool = [
2193 'links' => [
2194 [ 'single-id' => "pt-$key" ],
2195 ],
2196 'id' => "pt-$key",
2197 'icon' => $plink[ 'icon' ] ?? null,
2198 ];
2199 if ( $applyClassesToListItems && isset( $plink['class'] ) ) {
2200 $ptool['class'] = $plink['class'];
2201 }
2202 if ( isset( $plink['active'] ) ) {
2203 $ptool['active'] = $plink['active'];
2204 }
2205 // Set class for the link to link-class, when defined.
2206 // This allows newer notifications content navigation to retain their classes
2207 // when merged back into the personal tools.
2208 // Doing this here allows the loop below to overwrite the class if defined directly.
2209 if ( isset( $plink['link-class'] ) ) {
2210 $ptool['links'][0]['class'] = $plink['link-class'];
2211 }
2212 $props = [
2213 'href',
2214 'text',
2215 'dir',
2216 'data',
2217 'exists',
2218 // @todo: Remove data-mw once migration from data-mw to data-mw-interface is complete.
2219 // this should probably go through the deprecation process for 3rd party support.
2220 'data-mw',
2221 'data-mw-interface',
2222 'link-html',
2223 ];
2224 if ( !$applyClassesToListItems ) {
2225 $props[] = 'class';
2226 }
2227 foreach ( $props as $k ) {
2228 if ( isset( $plink[$k] ) ) {
2229 $ptool['links'][0][$k] = $plink[$k];
2230 }
2231 }
2232 $personal_tools[$key] = $ptool;
2233 }
2234 return $personal_tools;
2235 }
2236
2298 final public function makeLink( $key, $item, $linkOptions = [] ) {
2299 $options = $linkOptions + $this->defaultLinkOptions;
2300 $component = new SkinComponentLink(
2301 $key, $item, $this->getContext(), $options
2302 );
2303 return $component->getTemplateData()[ 'html' ];
2304 }
2305
2341 final public function makeListItem( $key, $item, $options = [] ) {
2342 $component = new SkinComponentListItem(
2343 $key, $item, $this->getContext(), $options, $this->defaultLinkOptions
2344 );
2345 return $component->getTemplateData()[ 'html-item' ];
2346 }
2347
2358 public function getAfterPortlet( string $name ): string {
2359 $html = '';
2360
2361 if ( $name === 'user-page' && $this->getUser()->isTemp() ) {
2362 $html .= Html::rawElement( 'div', [ 'class' => 'mw-temp-user-banner-tooltip' ],
2363 Html::rawElement( 'button', [
2364 'id' => 'mw-temp-user-banner-tooltip-button',
2365 'class' => 'mw-temp-user-banner-tooltip-summary cdx-button '
2366 . 'cdx-button--icon-only cdx-button--weight-quiet',
2367 'aria-label' => $this->msg( 'temp-user-banner-tooltip-label' )->text(),
2368 'data-event-name' => 'temp-user-banner.info',
2369 ],
2370 Html::element( 'span', [ 'class' => 'mw-temp-user-banner-tooltip-icon' ] )
2371 )
2372 );
2373 }
2374
2375 $this->getHookRunner()->onSkinAfterPortlet( $this, $name, $html );
2376
2377 return $html;
2378 }
2379
2386 final public function prepareSubtitle( bool $withContainer = true ) {
2387 $out = $this->getOutput();
2388 $subpagestr = $this->subPageSubtitleInternal();
2389 if ( $subpagestr !== '' ) {
2390 $subpagestr = Html::rawElement( 'div', [ 'class' => 'subpages' ], $subpagestr );
2391 }
2392 $html = $subpagestr . $out->getSubtitle();
2393 return $withContainer ? Html::rawElement( 'div', [
2394 'id' => 'mw-content-subtitle',
2395 ] + $this->getUserLanguageAttributes(), $html ) : $html;
2396 }
2397
2405 protected function getJsConfigVars(): array {
2406 return [];
2407 }
2408
2414 final protected function getUserLanguageAttributes() {
2415 $userLang = $this->getLanguage();
2416 $userLangCode = $userLang->getHtmlCode();
2417 $userLangDir = $userLang->getDir();
2418 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
2419 if (
2420 $userLangCode !== $contLang->getHtmlCode() ||
2421 $userLangDir !== $contLang->getDir()
2422 ) {
2423 return [
2424 'lang' => $userLangCode,
2425 'dir' => $userLangDir,
2426 ];
2427 }
2428 return [];
2429 }
2430
2436 final protected function prepareUserLanguageAttributes() {
2437 return Html::expandAttributes(
2438 $this->getUserLanguageAttributes()
2439 );
2440 }
2441
2447 final protected function prepareUndeleteLink() {
2448 $undelete = $this->getUndeleteLink();
2449 return $undelete === '' ? null : '<div class="subpages">' . $undelete . '</div>';
2450 }
2451
2460 protected function wrapHTML( $title, $html ) {
2461 // This wraps the "real" body content (i.e. parser output or special page).
2462 // On page views, elements like categories and contentSub are outside of this.
2463 return Html::rawElement( 'div', [
2464 'id' => 'mw-content-text',
2465 'class' => [
2466 'mw-body-content',
2467 ],
2468 ], $html );
2469 }
2470
2479 final public function getOptions(): array {
2480 return $this->options + [
2481 'styles' => [],
2482 'scripts' => [],
2483 'toc' => true,
2484 'format' => 'html',
2485 'bodyClasses' => [],
2486 'clientPrefEnabled' => false,
2487 'responsive' => false,
2488 'link' => [],
2489 'tempUserBanner' => false,
2490 'wrapSiteNotice' => false,
2491 'menus' => [
2492 // Legacy keys that are enabled by default for backwards compatibility
2493 'namespaces',
2494 'views',
2495 'actions',
2496 'variants',
2497 'personal',
2498 // Opt-in menus
2499 // * 'associated-pages'
2500 // * 'notifications'
2501 // * 'user-interface-preferences',
2502 // * 'user-page',
2503 // * 'user-menu',
2504 ]
2505 ];
2506 }
2507
2516 public function supportsMenu( string $menu ): bool {
2517 $options = $this->getOptions();
2518 return in_array( $menu, $options['menus'] );
2519 }
2520
2535 public static function getPortletLinkOptions( RL\Context $context ): array {
2536 $skinName = $context->getSkin();
2537 $skinFactory = MediaWikiServices::getInstance()->getSkinFactory();
2538 $options = $skinFactory->getSkinOptions( $skinName );
2539 $portletLinkOptions = $options['link'] ?? [];
2540 // Normalize link options to always have this key
2541 $portletLinkOptions += [ 'text-wrapper' => [] ];
2542 // Normalize text-wrapper to always be an array of arrays
2543 if ( isset( $portletLinkOptions['text-wrapper']['tag'] ) ) {
2544 $portletLinkOptions['text-wrapper'] = [ $portletLinkOptions['text-wrapper'] ];
2545 }
2546 return $portletLinkOptions;
2547 }
2548
2556 final protected function getPortletData( string $name, array $items ): array {
2557 $portletComponent = new SkinComponentMenu(
2558 $name,
2559 $items,
2560 $this->getContext(),
2561 '',
2562 $this->defaultLinkOptions,
2563 $this->getAfterPortlet( $name )
2564 );
2565 return $portletComponent->getTemplateData();
2566 }
2567
2579 public function getPageTarget() {
2580 $target = '';
2581 // Check if the target user is a valid user or IP
2582 $relUser = $this->getRelevantUser();
2583 if ( $relUser ) {
2584 $target = $relUser->getName();
2585 }
2586
2587 // Otherwise, check if the target is an IP range which should also be supported
2588 if ( !$target ) {
2589 // Check for the target parameter first
2590 $pageTarget = trim( $this->getRequest()->getText( 'target' ) );
2591
2592 // If it doesn't exist, check for the subpage next
2593 if ( !$pageTarget ) {
2594 $pageTarget = $this->getTitle()->getFullSubpageText();
2595 }
2596
2597 // If it exists, only set the target if it's an IP range
2598 // as that's the only case not covered by Skin->getRelevantUser()
2599 if (
2600 $pageTarget &&
2601 IPUtils::isValidRange( $pageTarget )
2602 ) {
2603 $target = $pageTarget;
2604 }
2605 }
2606
2607 return $target;
2608 }
2609}
2610
2612class_alias( Skin::class, 'Skin' );
const NS_USER
Definition Defines.php:53
const NS_FILE
Definition Defines.php:57
const NS_MAIN
Definition Defines.php:51
const NS_SPECIAL
Definition Defines.php:40
const NS_CATEGORY
Definition Defines.php:65
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
$fallback
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:69
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
This class is a collection of static functions that serve two purposes:
Definition Html.php:44
Methods for dealing with language codes.
Base class for language-specific code.
Definition Language.php:65
A class containing constants representing the names of configuration variables.
const DefaultSkin
Name constant for the DefaultSkin setting, for use with Config::get()
const Sitename
Name constant for the Sitename setting, for use with Config::get()
const FallbackSkin
Name constant for the FallbackSkin setting, for use with Config::get()
const SkinMetaTags
Name constant for the SkinMetaTags setting, for use with Config::get()
const ForceUIMsgAsContentMsg
Name constant for the ForceUIMsgAsContentMsg setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
This is one of the Core classes and should be read at least once by any new developers.
tailElement( $skin)
The final bits that go to the bottom of a page HTML document including the closing tags.
getHTMLTitle()
Return the "HTML title", i.e.
headElement(Skin $sk, $includeStyle=true)
addMeta( $name, $val)
Add a new "<meta>" tag To add an http-equiv meta tag, precede the name with "http:".
HTML sanitizer for MediaWiki.
Definition Sanitizer.php:32
Service for looking up page revisions.
getTemplateData()
This returns all the data that is needed to the component.Returned array must be serialized....
Exceptions for skin-related failures.
The base class for all skins.
Definition Skin.php:54
buildNavUrls()
Build array of common navigation links.
Definition Skin.php:1314
getRelevantTitle()
Return the "relevant" title.
Definition Skin.php:608
array $options
Skin options passed into constructor.
Definition Skin.php:70
buildFeedUrls()
Build data structure representing syndication links.
Definition Skin.php:1519
string null $skinname
Definition Skin.php:65
getDefaultModules()
Defines the ResourceLoader modules that should be added to the skin It is recommended that skins wish...
Definition Skin.php:427
static getVersion()
Get the current major version of Skin.
Definition Skin.php:100
logoText( $align='')
Definition Skin.php:1044
getPageClasses( $title)
TODO: document.
Definition Skin.php:696
supportsMenu(string $menu)
Does the skin support the named menu? e.g.
Definition Skin.php:2516
getJsConfigVars()
Returns array of config variables that should be added only to this skin for use in JavaScript.
Definition Skin.php:2405
getComponent(string $name)
Definition Skin.php:109
doEditSectionLink(Title $nt, $section, $sectionTitle, Language $lang)
Create a section edit link.
Definition Skin.php:2021
static makeKnownUrlDetails( $name, $urlaction='')
Make URL details where the article exists (or at least it's convenient to think so)
Definition Skin.php:1180
mapInterwikiToLanguage( $code)
Allows correcting the language of interlanguage links which, mostly due to legacy reasons,...
Definition Skin.php:1196
getAfterPortlet(string $name)
Allows extensions to hook into known portlets and add stuff to them.
Definition Skin.php:2358
static makeInternalOrExternalUrl( $name)
If url string starts with http, consider as external URL, else internal.
Definition Skin.php:1149
prepareUndeleteLink()
Prepare undelete link for output in page.
Definition Skin.php:2447
outputPageFinal(OutputPage $out)
Outputs the HTML for the page.
Definition Skin.php:667
afterContentHook()
This runs a hook to allow extensions placing their stuff after content and article metadata (e....
Definition Skin.php:852
outputPage()
Outputs the HTML generated by other functions.
makeToolbox( $navUrls, $feedUrls)
Create an array of common toolbox items from the data in the quicktemplate stored by SkinTemplate.
Definition Skin.php:2104
static makeMainPageUrl( $urlaction='')
Definition Skin.php:1137
setRelevantTitle( $t)
Definition Skin.php:593
prepareUserLanguageAttributes()
Prepare user language attribute links.
Definition Skin.php:2436
addToSidebar(&$bar, $message)
Add content from a sidebar system message Currently only used for MediaWiki:Sidebar (but may be used ...
Definition Skin.php:1624
static getPortletLinkOptions(RL\Context $context)
Returns skin options for portlet links, used by addPortletLink.
Definition Skin.php:2535
editUrlOptions()
Return URL options for the 'edit page' link.
Definition Skin.php:1100
buildSidebar()
Build an array that represents the sidebar(s), the navigation bar among them.
Definition Skin.php:1559
makeFooterIcon( $icon, $withImage='withImage')
Renders a $wgFooterIcons icon according to the method's arguments.
Definition Skin.php:1087
getOptions()
Get current skin's options.
Definition Skin.php:2479
initPage(OutputPage $out)
Definition Skin.php:377
getPersonalToolsForMakeListItem( $urls, $applyClassesToListItems=false)
Create an array of personal tools items from the data in the quicktemplate stored by SkinTemplate.
Definition Skin.php:2186
static normalizeKey(string $key)
Normalize a skin preference value to a form that can be loaded.
Definition Skin.php:218
wrapHTML( $title, $html)
Wrap the body text with language information and identifiable element.
Definition Skin.php:2460
getUserLanguageAttributes()
Get user language attribute links array.
Definition Skin.php:2414
Title null $mRelevantTitle
Definition Skin.php:72
static makeUrlDetails( $name, $urlaction='')
these return an array with the 'href' and boolean 'exists'
Definition Skin.php:1166
getPortletData(string $name, array $items)
Definition Skin.php:2556
printSource()
Text with the permalink to the source page, usually shown on the footer of a printed page.
Definition Skin.php:896
const VERSION_MAJOR
The current major version of the skin specification.
Definition Skin.php:80
prepareSubtitle(bool $withContainer=true)
Prepare the subtitle of the page for output in the skin if one has been set.
Definition Skin.php:2386
doEditSectionLinksHTML(array $links, Language $lang)
Definition Skin.php:2072
getEmailConfirmationNotice()
Return HTML for an email confirmation notice banner if the current user has a registered but unconfir...
Definition Skin.php:1908
getHtmlElementAttributes()
Return values for <html> element.
Definition Skin.php:738
makeListItem( $key, $item, $options=[])
Generates a list item for a navigation, portlet, portal, sidebar... list.
Definition Skin.php:2341
getIndicatorsData(array $indicators)
Return an array of indicator data.
Definition Skin.php:2160
isResponsive()
Indicates if this skin is responsive.
Definition Skin.php:365
setRelevantUser(?UserIdentity $u)
Definition Skin.php:616
__construct( $options=null)
Definition Skin.php:329
getFooterIcons()
Get template representation of the footer.
Definition Skin.php:1070
getLanguages()
Generates array of language links for the current page.
Definition Skin.php:1209
getNewtalks()
Gets new talk page messages for the current user and returns an appropriate alert message (or an empt...
Definition Skin.php:1795
makeLink( $key, $item, $linkOptions=[])
Makes a link, usually used by makeListItem to generate a link for an item in a list used in navigatio...
Definition Skin.php:2298
getRelevantUser()
Return the "relevant" user.
Definition Skin.php:629
addToSidebarPlain(&$bar, $text)
Add content from plain text.
Definition Skin.php:1699
Parent class for all special pages.
Represents the target of a wiki link.
Represents a title within MediaWiki.
Definition Title.php:69
UploadBase and subclasses are the backend of MediaWiki's file uploads.
getBoolOption(UserIdentity $user, string $oname, int $queryFlags=IDBAccessObject::READ_NORMAL)
Get the user's current setting for a given option, as a boolean value.
getOption(UserIdentity $user, string $oname, $defaultOverride=null, bool $ignoreHidden=false, int $queryFlags=IDBAccessObject::READ_NORMAL)
Get the user's current setting for a given option.
Value object representing a user's identity.
User class for the MediaWiki software.
Definition User.php:130
Tools for dealing with other locally-hosted wikis.
Definition WikiMap.php:19
Multi-datacenter aware caching interface.
return[ 'config-schema-inverse'=>['default'=>['ConfigRegistry'=>['main'=> 'MediaWiki\\Config\\GlobalVarConfig::newInstance',], 'Sitename'=> 'MediaWiki', 'Server'=> false, 'CanonicalServer'=> false, 'ServerName'=> false, 'AssumeProxiesUseDefaultProtocolPorts'=> true, 'HttpsPort'=> 443, 'ForceHTTPS'=> false, 'ScriptPath'=> '/wiki', 'UsePathInfo'=> null, 'Script'=> false, 'LoadScript'=> false, 'RestPath'=> false, 'StylePath'=> false, 'LocalStylePath'=> false, 'ExtensionAssetsPath'=> false, 'ExtensionDirectory'=> null, 'StyleDirectory'=> null, 'ArticlePath'=> false, 'UploadPath'=> false, 'ImgAuthPath'=> false, 'ThumbPath'=> false, 'UploadDirectory'=> false, 'FileCacheDirectory'=> false, 'Logo'=> false, 'Logos'=> false, 'Favicon'=> '/favicon.ico', 'AppleTouchIcon'=> false, 'ReferrerPolicy'=> false, 'TmpDirectory'=> false, 'UploadBaseUrl'=> '', 'UploadStashScalerBaseUrl'=> false, 'ActionPaths'=>[], 'MainPageIsDomainRoot'=> false, 'EnableUploads'=> false, 'UploadStashMaxAge'=> 21600, 'EnableAsyncUploads'=> false, 'EnableAsyncUploadsByURL'=> false, 'UploadMaintenance'=> false, 'IllegalFileChars'=> ':\\/\\\\', 'DeletedDirectory'=> false, 'ImgAuthDetails'=> false, 'ImgAuthUrlPathMap'=>[], 'LocalFileRepo'=>['class'=> 'MediaWiki\\FileRepo\\LocalRepo', 'name'=> 'local', 'directory'=> null, 'scriptDirUrl'=> null, 'favicon'=> null, 'url'=> null, 'hashLevels'=> null, 'thumbScriptUrl'=> null, 'transformVia404'=> null, 'deletedDir'=> null, 'deletedHashLevels'=> null, 'updateCompatibleMetadata'=> null, 'reserializeMetadata'=> null,], 'ForeignFileRepos'=>[], 'UseInstantCommons'=> false, 'UseSharedUploads'=> false, 'SharedUploadDirectory'=> null, 'SharedUploadPath'=> null, 'HashedSharedUploadDirectory'=> true, 'RepositoryBaseUrl'=> 'https:'FetchCommonsDescriptions'=> false, 'SharedUploadDBname'=> false, 'SharedUploadDBprefix'=> '', 'CacheSharedUploads'=> true, 'ForeignUploadTargets'=>['local',], 'UploadDialog'=>['fields'=>['description'=> true, 'date'=> false, 'categories'=> false,], 'licensemessages'=>['local'=> 'generic-local', 'foreign'=> 'generic-foreign',], 'comment'=>['local'=> '', 'foreign'=> '',], 'format'=>['filepage'=> ' $DESCRIPTION', 'description'=> ' $TEXT', 'ownwork'=> '', 'license'=> '', 'uncategorized'=> '',],], 'FileBackends'=>[], 'LockManagers'=>[], 'ShowEXIF'=> null, 'UpdateCompatibleMetadata'=> false, 'AllowCopyUploads'=> false, 'CopyUploadsDomains'=>[], 'CopyUploadsFromSpecialUpload'=> false, 'CopyUploadProxy'=> false, 'CopyUploadTimeout'=> false, 'CopyUploadAllowOnWikiDomainConfig'=> false, 'MaxUploadSize'=> 104857600, 'MinUploadChunkSize'=> 1024, 'UploadNavigationUrl'=> false, 'UploadMissingFileUrl'=> false, 'ThumbnailScriptPath'=> false, 'SharedThumbnailScriptPath'=> false, 'HashedUploadDirectory'=> true, 'CSPUploadEntryPoint'=> true, 'FileExtensions'=>['png', 'gif', 'jpg', 'jpeg', 'webp',], 'ProhibitedFileExtensions'=>['html', 'htm', 'js', 'jsb', 'mhtml', 'mht', 'xhtml', 'xht', 'php', 'phtml', 'php3', 'php4', 'php5', 'phps', 'phar', 'shtml', 'jhtml', 'pl', 'py', 'cgi', 'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl', 'xml',], 'MimeTypeExclusions'=>['text/html', 'application/javascript', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', 'application/x-php', 'text/x-php', 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', 'text/scriptlet', 'application/x-msdownload', 'application/x-msmetafile', 'application/java', 'application/xml', 'text/xml',], 'CheckFileExtensions'=> true, 'StrictFileExtensions'=> true, 'DisableUploadScriptChecks'=> false, 'UploadSizeWarning'=> false, 'TrustedMediaFormats'=>['BITMAP', 'AUDIO', 'VIDEO', 'image/svg+xml', 'application/pdf',], 'MediaHandlers'=>[], 'NativeImageLazyLoading'=> false, 'ParserTestMediaHandlers'=>['image/jpeg'=> 'MockBitmapHandler', 'image/png'=> 'MockBitmapHandler', 'image/gif'=> 'MockBitmapHandler', 'image/tiff'=> 'MockBitmapHandler', 'image/webp'=> 'MockBitmapHandler', 'image/x-ms-bmp'=> 'MockBitmapHandler', 'image/x-bmp'=> 'MockBitmapHandler', 'image/x-xcf'=> 'MockBitmapHandler', 'image/svg+xml'=> 'MockSvgHandler', 'image/vnd.djvu'=> 'MockDjVuHandler',], 'UseImageResize'=> true, 'UseImageMagick'=> false, 'ImageMagickConvertCommand'=> '/usr/bin/convert', 'MaxInterlacingAreas'=>[], 'SharpenParameter'=> '0x0.4', 'SharpenReductionThreshold'=> 0.85, 'ImageMagickTempDir'=> false, 'CustomConvertCommand'=> false, 'JpegTran'=> '/usr/bin/jpegtran', 'JpegPixelFormat'=> 'yuv420', 'JpegQuality'=> 80, 'Exiv2Command'=> '/usr/bin/exiv2', 'Exiftool'=> '/usr/bin/exiftool', 'SVGConverters'=>['ImageMagick'=> ' $path/convert -background "#ffffff00" -thumbnail $widthx$height\\! $input PNG:$output', 'inkscape'=> ' $path/inkscape -w $width -o $output $input', 'batik'=> 'java -Djava.awt.headless=true -jar $path/batik-rasterizer.jar -w $width -d $output $input', 'rsvg'=> ' $path/rsvg-convert -w $width -h $height -o $output $input', 'ImagickExt'=>['SvgHandler::rasterizeImagickExt',],], 'SVGConverter'=> 'ImageMagick', 'SVGConverterPath'=> '', 'SVGMaxSize'=> 5120, 'SVGMetadataCutoff'=> 5242880, 'SVGNativeRendering'=> true, 'SVGNativeRenderingSizeLimit'=> 51200, 'MediaInTargetLanguage'=> true, 'MaxImageArea'=> 12500000, 'MaxAnimatedGifArea'=> 12500000, 'TiffThumbnailType'=>[], 'ThumbnailEpoch'=> '20030516000000', 'AttemptFailureEpoch'=> 1, 'IgnoreImageErrors'=> false, 'GenerateThumbnailOnParse'=> true, 'ShowArchiveThumbnails'=> true, 'EnableAutoRotation'=> null, 'Antivirus'=> null, 'AntivirusSetup'=>['clamav'=>['command'=> 'clamscan --no-summary ', 'codemap'=>[0=> 0, 1=> 1, 52=> -1, ' *'=> false,], 'messagepattern'=> '/.*?:(.*)/sim',],], 'AntivirusRequired'=> true, 'VerifyMimeType'=> true, 'MimeTypeFile'=> 'internal', 'MimeInfoFile'=> 'internal', 'MimeDetectorCommand'=> null, 'TrivialMimeDetection'=> false, 'XMLMimeTypes'=>['http:'svg'=> 'image/svg+xml', 'http:'http:'html'=> 'text/html',], 'ImageLimits'=>[[320, 240,], [640, 480,], [800, 600,], [1024, 768,], [1280, 1024,], [2560, 2048,],], 'ThumbLimits'=>[120, 150, 180, 200, 220, 250, 300, 400,], 'ThumbnailNamespaces'=>[6,], 'ThumbnailSteps'=> null, 'ThumbnailStepsRatio'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> false, 'TrackMediaRequestProvenance'=> false, 'DjvuUseBoxedCommand'=> false, 'DjvuDump'=> null, 'DjvuRenderer'=> null, 'DjvuTxt'=> null, 'DjvuPostProcessor'=> 'pnmtojpeg', 'DjvuOutputExtension'=> 'jpg', 'EmergencyContact'=> false, 'PasswordSender'=> false, 'NoReplyAddress'=> false, 'EnableEmail'=> true, 'EnableUserEmail'=> true, 'UserEmailUseReplyTo'=> true, 'PasswordReminderResendTime'=> 24, 'NewPasswordExpiry'=> 604800, 'UserEmailConfirmationTokenExpiry'=> 604800, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, 'EmailConfirmationBanner'=> false, 'EnotifWatchlist'=> false, 'EnotifUserTalk'=> false, 'EnotifRevealEditorAddress'=> false, 'EnotifMinorEdits'=> true, 'EnotifUseRealName'=> false, 'UsersNotifiedOnAllChanges'=>[], 'DBname'=> 'my_wiki', 'DBmwschema'=> null, 'DBprefix'=> '', 'DBserver'=> 'localhost', 'DBport'=> 5432, 'DBuser'=> 'wikiuser', 'DBpassword'=> '', 'DBtype'=> 'mysql', 'DBssl'=> false, 'DBcompress'=> false, 'DBStrictWarnings'=> false, 'DBadminuser'=> null, 'DBadminpassword'=> null, 'SearchType'=> null, 'SearchTypeAlternatives'=> null, 'DBTableOptions'=> 'ENGINE=InnoDB, DEFAULT CHARSET=binary', 'SQLMode'=> '', 'SQLiteDataDir'=> '', 'SharedDB'=> null, 'SharedPrefix'=> false, 'SharedTables'=>['user', 'user_properties', 'user_autocreate_serial',], 'SharedSchema'=> false, 'DBservers'=> false, 'LBFactoryConf'=>['class'=> 'Wikimedia\\Rdbms\\LBFactorySimple',], 'DataCenterUpdateStickTTL'=> 10, 'DBerrorLog'=> false, 'DBerrorLogTZ'=> false, 'LocalDatabases'=>[], 'DatabaseReplicaLagWarning'=> 10, 'DatabaseReplicaLagCritical'=> 30, 'MaxExecutionTimeForExpensiveQueries'=> 0, 'VirtualDomainsMapping'=>[], 'FileSchemaMigrationStage'=> 3, 'ExternalLinksDomainGaps'=>[], 'ContentHandlers'=>['wikitext'=>['class'=> 'MediaWiki\\Content\\WikitextContentHandler', 'services'=>['TitleFactory', 'ParserFactory', 'GlobalIdGenerator', 'LanguageNameUtils', 'LinkRenderer', 'MagicWordFactory', 'ParsoidParserFactory',],], 'javascript'=>['class'=> 'MediaWiki\\Content\\JavaScriptContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> 'MediaWiki\\ObjectCache\\SqlBagOStuff', 'loggroup'=> 'SQLBagOStuff',], 'memcached-php'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPhpBagOStuff', 'loggroup'=> 'memcached',], 'memcached-pecl'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPeclBagOStuff', 'loggroup'=> 'memcached',], 'hash'=>['class'=> 'Wikimedia\\ObjectCache\\HashBagOStuff', 'reportDupes'=> false,], 'apc'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,], 'apcu'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,],], 'WANObjectCache'=>[], 'MicroStashType'=> -1, 'MainStash'=> 1, 'ParsoidCacheConfig'=>['StashType'=> null, 'StashDuration'=> 86400, 'WarmParsoidParserCache'=> false,], 'ParsoidSelectiveUpdateSampleRate'=> 0, 'ParserCacheFilterConfig'=>['pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'JwtSessionCookieIssuer'=> null, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> 'MediaWiki\\Language\\LocalisationCache', 'store'=> 'detect', 'storeClass'=> false, 'storeDirectory'=> false, 'storeServer'=>[], 'forceRecache'=> false, 'manualRecache'=> false,], 'CachePages'=> true, 'CacheEpoch'=> '20030516000000', 'GitInfoCacheDirectory'=> false, 'UseFileCache'=> false, 'FileCacheDepth'=> 2, 'RenderHashAppend'=> '', 'EnableSidebarCache'=> false, 'SidebarCacheExpiry'=> 86400, 'UseGzip'=> false, 'InvalidateCacheOnLocalSettingsChange'=> true, 'ExtensionInfoMTime'=> false, 'EnableRemoteBagOStuffTests'=> false, 'UseCdn'=> false, 'VaryOnXFP'=> false, 'InternalServer'=> false, 'CdnMaxAge'=> 18000, 'CdnMaxageLagged'=> 30, 'CdnMaxageStale'=> 10, 'CdnReboundPurgeDelay'=> 0, 'CdnMaxageSubstitute'=> 60, 'ForcedRawSMaxage'=> 300, 'CdnServers'=>[], 'CdnServersNoPurge'=>[], 'HTCPRouting'=>[], 'HTCPMulticastTTL'=> 1, 'UsePrivateIPs'=> false, 'CdnMatchParameterOrder'=> true, 'LanguageCode'=> 'en', 'GrammarForms'=>[], 'InterwikiMagic'=> true, 'HideInterlanguageLinks'=> false, 'ExtraInterlanguageLinkPrefixes'=>[], 'InterlanguageLinkCodeMap'=>[], 'ExtraLanguageNames'=>[], 'ExtraLanguageCodes'=>['bh'=> 'bho', 'no'=> 'nb', 'simple'=> 'en',], 'DummyLanguageCodes'=>[], 'AllUnicodeFixes'=> false, 'LegacyEncoding'=> false, 'AmericanDates'=> false, 'TranslateNumerals'=> true, 'UseDatabaseMessages'=> true, 'MaxMsgCacheEntrySize'=> 10000, 'DisableLangConversion'=> false, 'DisableTitleConversion'=> false, 'DefaultLanguageVariant'=> false, 'UsePigLatinVariant'=> false, 'DisabledVariants'=>[], 'VariantArticlePath'=> false, 'UseXssLanguage'=> false, 'LoginLanguageSelector'=> false, 'ForceUIMsgAsContentMsg'=>[], 'RawHtmlMessages'=>[], 'Localtimezone'=> null, 'LocalTZoffset'=> null, 'OverrideUcfirstCharacters'=>[], 'MimeType'=> 'text/html', 'Html5Version'=> null, 'EditSubmitButtonLabelPublish'=> false, 'XhtmlNamespaces'=>[], 'SiteNotice'=> '', 'BrowserFormatDetection'=> 'telephone=no', 'SkinMetaTags'=>[], 'DefaultSkin'=> 'vector-2022', 'FallbackSkin'=> 'fallback', 'SkipSkins'=>[], 'DisableOutputCompression'=> false, 'FragmentMode'=>['html5', 'legacy',], 'ExternalInterwikiFragmentMode'=> 'legacy', 'FooterIcons'=>['copyright'=>['copyright'=>[],], 'poweredby'=>['mediawiki'=>['src'=> null, 'url'=> 'https:'alt'=> 'Powered by MediaWiki', 'lang'=> 'en',],],], 'UseCombinedLoginLink'=> false, 'Edititis'=> false, 'Send404Code'=> true, 'ShowRollbackEditCount'=> 10, 'EnableCanonicalServerLink'=> false, 'InterwikiLogoOverride'=>[], 'ResourceModules'=>[], 'ResourceModuleSkinStyles'=>[], 'ResourceLoaderSources'=>[], 'ResourceBasePath'=> null, 'ResourceLoaderMaxage'=>[], 'ResourceLoaderDebug'=> false, 'ResourceLoaderMaxQueryLength'=> false, 'ResourceLoaderValidateJS'=> true, 'ResourceLoaderEnableJSProfiler'=> false, 'ResourceLoaderStorageEnabled'=> true, 'ResourceLoaderStorageVersion'=> 1, 'ResourceLoaderEnableSourceMapLinks'=> true, 'AllowSiteCSSOnRestrictedPages'=> false, 'VueDevelopmentMode'=> false, 'CodexDevelopmentDir'=> null, 'MetaNamespace'=> false, 'MetaNamespaceTalk'=> false, 'CanonicalNamespaceNames'=>[-2=> 'Media', -1=> 'Special', 0=> '', 1=> 'Talk', 2=> 'User', 3=> 'User_talk', 4=> 'Project', 5=> 'Project_talk', 6=> 'File', 7=> 'File_talk', 8=> 'MediaWiki', 9=> 'MediaWiki_talk', 10=> 'Template', 11=> 'Template_talk', 12=> 'Help', 13=> 'Help_talk', 14=> 'Category', 15=> 'Category_talk',], 'ExtraNamespaces'=>[], 'ExtraGenderNamespaces'=>[], 'NamespaceAliases'=>[], 'LegalTitleChars'=> ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', 'CapitalLinks' => true, 'CapitalLinkOverrides' => [ ], 'NamespacesWithSubpages' => [ 1 => true, 2 => true, 3 => true, 4 => true, 5 => true, 7 => true, 8 => true, 9 => true, 10 => true, 11 => true, 12 => true, 13 => true, 15 => true, ], 'ContentNamespaces' => [ 0, ], 'ShortPagesNamespaceExclusions' => [ ], 'ExtraSignatureNamespaces' => [ ], 'InvalidRedirectTargets' => [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect', 'Mylog', ], 'DisableHardRedirects' => false, 'FixDoubleRedirects' => false, 'LocalInterwikis' => [ ], 'InterwikiExpiry' => 10800, 'InterwikiCache' => false, 'InterwikiScopes' => 3, 'InterwikiFallbackSite' => 'wiki', 'RedirectSources' => false, 'SiteTypes' => [ 'mediawiki' => 'MediaWiki\\Site\\MediaWikiSite', ], 'MaxTocLevel' => 999, 'MaxPPNodeCount' => 1000000, 'MaxTemplateDepth' => 100, 'MaxPPExpandDepth' => 100, 'UrlProtocols' => [ 'bitcoin:', 'ftp: 'ftps: 'geo:', 'git: 'gopher: 'http: 'https: 'irc: 'ircs: 'magnet:', 'mailto:', 'matrix:', 'mms: 'news:', 'nntp: 'redis: 'sftp: 'sip:', 'sips:', 'sms:', 'ssh: 'svn: 'tel:', 'telnet: 'urn:', 'wikipedia: 'worldwind: 'xmpp:', ' ], 'CleanSignatures' => true, 'AllowExternalImages' => false, 'AllowExternalImagesFrom' => '', 'EnableImageWhitelist' => false, 'TidyConfig' => [ ], 'ParsoidSettings' => [ 'useSelser' => true, ], 'ParsoidExperimentalParserFunctionOutput' => false, 'UseLegacyMediaStyles' => false, 'RawHtml' => false, 'ExternalLinkTarget' => false, 'NoFollowLinks' => true, 'NoFollowNsExceptions' => [ ], 'NoFollowDomainExceptions' => [ 'mediawiki.org', ], 'RegisterInternalExternals' => false, 'ExternalLinksIgnoreDomains' => [ ], 'AllowDisplayTitle' => true, 'RestrictDisplayTitle' => true, 'ExpensiveParserFunctionLimit' => 100, 'PreprocessorCacheThreshold' => 1000, 'EnableScaryTranscluding' => false, 'TranscludeCacheExpiry' => 3600, 'EnableMagicLinks' => [ 'ISBN' => false, 'PMID' => false, 'RFC' => false, ], 'ParserEnableUserLanguage' => false, 'ArticleCountMethod' => 'link', 'ActiveUserDays' => 30, 'LearnerEdits' => 10, 'LearnerMemberSince' => 4, 'ExperiencedUserEdits' => 500, 'ExperiencedUserMemberSince' => 30, 'ManualRevertSearchRadius' => 15, 'RevertedTagMaxDepth' => 15, 'CentralIdLookupProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\CentralId\\LocalIdLookup', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', 'HideUserUtils', ], ], ], 'CentralIdLookupProvider' => 'local', 'UserRegistrationProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\Registration\\LocalUserRegistrationProvider', 'services' => [ 'ConnectionProvider', ], ], ], 'PasswordPolicy' => [ 'policies' => [ 'bureaucrat' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'sysop' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'interface-admin' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'bot' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'default' => [ 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true, ], 'PasswordCannotBeSubstringInUsername' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'PasswordCannotMatchDefaults' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'MaximalPasswordLength' => [ 'value' => 4096, 'suggestChangeOnLogin' => true, ], 'PasswordNotInCommonList' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], ], ], 'checks' => [ 'MinimalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimalPasswordLength', ], 'MinimumPasswordLengthToLogin' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimumPasswordLengthToLogin', ], 'PasswordCannotBeSubstringInUsername' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotBeSubstringInUsername', ], 'PasswordCannotMatchDefaults' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotMatchDefaults', ], 'MaximalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMaximalPasswordLength', ], 'PasswordNotInCommonList' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordNotInCommonList', ], ], ], 'AuthManagerConfig' => null, 'AuthManagerAutoConfig' => [ 'preauth' => [ 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider', 'sort' => 0, ], ], 'primaryauth' => [ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', 'UserOptionsLookup', ], 'args' => [ [ 'authoritative' => false, ], ], 'sort' => 0, ], 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'args' => [ [ 'authoritative' => true, ], ], 'sort' => 100, ], ], 'secondaryauth' => [ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider', 'sort' => 100, ], 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'sort' => 200, ], ], ], 'RememberMe' => 'choose', 'ReauthenticateTime' => [ 'default' => 3600, ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'default' => true, ], 'ChangeCredentialsBlacklist' => [ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest', ], 'RemoveCredentialsBlacklist' => [ 'MediaWiki\\Auth\\PasswordAuthenticationRequest', ], 'InvalidPasswordReset' => true, 'PasswordDefault' => 'pbkdf2', 'PasswordConfig' => [ 'A' => [ 'class' => 'MediaWiki\\Password\\MWOldPassword', ], 'B' => [ 'class' => 'MediaWiki\\Password\\MWSaltedPassword', ], 'pbkdf2-legacyA' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'A', 'pbkdf2', ], ], 'pbkdf2-legacyB' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'B', 'pbkdf2', ], ], 'bcrypt' => [ 'class' => 'MediaWiki\\Password\\BcryptPassword', 'cost' => 9, ], 'pbkdf2' => [ 'class' => 'MediaWiki\\Password\\Pbkdf2PasswordUsingOpenSSL', 'algo' => 'sha512', 'cost' => '30000', 'length' => '64', ], 'argon2' => [ 'class' => 'MediaWiki\\Password\\Argon2Password', 'algo' => 'auto', ], ], 'PasswordResetRoutes' => [ 'username' => true, 'email' => true, ], 'MaxSigChars' => 255, 'SignatureValidation' => 'warning', 'SignatureAllowedLintErrors' => [ 'obsolete-tag', ], 'MaxNameChars' => 255, 'ReservedUsernames' => [ 'MediaWiki default', 'Conversion script', 'Maintenance script', 'Template namespace initialisation script', 'ScriptImporter', 'Delete page script', 'Move page script', 'Command line script', 'Unknown user', 'msg:double-redirect-fixer', 'msg:usermessage-editor', 'msg:proxyblocker', 'msg:sorbs', 'msg:spambot_username', 'msg:autochange-username', ], 'DefaultUserOptions' => [ 'ccmeonemails' => 0, 'date' => 'default', 'diffonly' => 0, 'diff-type' => 'table', 'disablemail' => 0, 'editfont' => 'monospace', 'editondblclick' => 0, 'editrecovery' => 0, 'editsectiononrightclick' => 0, 'email-allow-new-users' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'enotifusertalkpages' => 1, 'enotifwatchlistpages' => 1, 'extendwatchlist' => 1, 'fancysig' => 0, 'forceeditsummary' => 0, 'forcesafemode' => 0, 'gender' => 'unknown', 'hidecategorization' => 1, 'hideminor' => 0, 'hidepatrolled' => 0, 'imagesize' => 2, 'minordefault' => 0, 'newpageshidepatrolled' => 0, 'nickname' => '', 'norollbackdiff' => 0, 'prefershttps' => 1, 'previewonfirst' => 0, 'previewontop' => 1, 'pst-cssjs' => 1, 'rcdays' => 7, 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'requireemail' => 0, 'search-match-redirect' => true, 'search-special-page' => 'Search', 'search-thumbnail-extra-namespaces' => true, 'searchlimit' => 20, 'showhiddencats' => 0, 'shownumberswatching' => 1, 'showrollbackconfirmation' => 0, 'skin' => false, 'skin-responsive' => 1, 'thumbsize' => 5, 'underline' => 2, 'useeditwarning' => 1, 'uselivepreview' => 0, 'usenewrc' => 1, 'watchcreations' => 1, 'watchcreations-expiry' => 'infinite', 'watchdefault' => 1, 'watchdefault-expiry' => 'infinite', 'watchdeletion' => 0, 'watchlistdays' => 7, 'watchlisthideanons' => 0, 'watchlisthidebots' => 0, 'watchlisthidecategorization' => 1, 'watchlisthideliu' => 0, 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, 'watchlistreloadautomatically' => 0, 'watchlistunwatchlinks' => 0, 'watchmoves' => 0, 'watchrollback' => 0, 'watchuploads' => 1, 'watchrollback-expiry' => 'infinite', 'watchstar-expiry' => 'infinite', 'wlenhancedfilters-disable' => 0, 'wllimit' => 250, ], 'ConditionalUserOptions' => [ ], 'HiddenPrefs' => [ ], 'UserJsPrefLimit' => 100, 'InvalidUsernameCharacters' => '@:>=', 'UserrightsInterwikiDelimiter' => '@', 'SecureLogin' => false, 'AuthenticationTokenVersion' => null, 'SessionProviders' => [ 'MediaWiki\\Session\\CookieSessionProvider' => [ 'class' => 'MediaWiki\\Session\\CookieSessionProvider', 'args' => [ [ 'priority' => 30, ], ], 'services' => [ 'JwtCodec', 'UrlUtils', ], ], 'MediaWiki\\Session\\BotPasswordSessionProvider' => [ 'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => [ [ 'priority' => 75, ], ], 'services' => [ 'GrantsInfo', ], ], ], 'AutoCreateTempUser' => [ 'known' => false, 'enabled' => false, 'actions' => [ 'edit', ], 'genPattern' => '~$1', 'matchPattern' => null, 'reservedPattern' => '~$1', 'serialProvider' => [ 'type' => 'local', 'useYear' => true, ], 'serialMapping' => [ 'type' => 'readable-numeric', ], 'expireAfterDays' => 90, 'notifyBeforeExpirationDays' => 10, ], 'AutoblockExemptions' => [ ], 'AutoblockExpiry' => 86400, 'BlockAllowsUTEdit' => true, 'BlockCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 19, ], 'BlockDisablesLogin' => false, 'EnableMultiBlocks' => false, 'WhitelistRead' => false, 'WhitelistReadRegexp' => false, 'EmailConfirmToEdit' => false, 'HideIdentifiableRedirects' => true, 'GroupPermissions' => [ '*' => [ 'createaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'viewmyprivateinfo' => true, 'editmyprivateinfo' => true, 'editmyoptions' => true, ], 'user' => [ 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'movefile' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'minoredit' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, 'editmyuserjsredirect' => true, 'sendemail' => true, 'applychangetags' => true, 'changetags' => true, 'viewmywatchlist' => true, 'editmywatchlist' => true, 'createwithcontentmodel' => true, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], 'UserRequirementsPrivateConditions' => [ ], 'RestrictionTypes' => [ 'create', 'edit', 'move', 'upload', ], 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop', ], 'CascadingRestrictionLevels' => [ 'sysop', ], 'SemiprotectedRestrictionLevels' => [ 'autoconfirmed', ], 'NamespaceProtection' => [ ], 'NonincludableNamespaces' => [ ], 'AutoConfirmAge' => 0, 'AutoConfirmCount' => 0, 'Autopromote' => [ 'autoconfirmed' => [ '&', [ 1, null, ], [ 2, null, ], ], ], 'AutopromoteOnce' => [ 'onEdit' => [ ], ], 'AutopromoteOnceLogInRC' => true, 'AutopromoteOnceRCExcludedGroups' => [ ], 'AddGroups' => [ ], 'RemoveGroups' => [ ], 'AvailableRights' => [ ], 'ImplicitRights' => [ ], 'DeleteRevisionsLimit' => 0, 'DeleteRevisionsBatchSize' => 1000, 'HideUserContribLimit' => 1000, 'AccountCreationThrottle' => [ [ 'count' => 0, 'seconds' => 86400, ], ], 'TempAccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 600, ], [ 'count' => 6, 'seconds' => 86400, ], ], 'TempAccountNameAcquisitionThrottle' => [ [ 'count' => 60, 'seconds' => 86400, ], ], 'SpamRegex' => [ ], 'SummarySpamRegex' => [ ], 'EnableDnsBlacklist' => false, 'DnsBlacklistUrls' => [ ], 'ProxyList' => [ ], 'ProxyWhitelist' => [ ], 'SoftBlockRanges' => [ ], 'ApplyIpBlocksToXff' => false, 'RateLimits' => [ 'edit' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], 'user' => [ 90, 60, ], ], 'move' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], 'upload' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'rollback' => [ 'user' => [ 10, 60, ], 'newbie' => [ 5, 120, ], ], 'mailpassword' => [ 'ip' => [ 5, 3600, ], ], 'sendemail' => [ 'ip' => [ 5, 86400, ], 'newbie' => [ 5, 86400, ], 'user' => [ 20, 86400, ], ], 'changeemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'confirmemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'purge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'linkpurge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'renderfile' => [ 'ip' => [ 700, 30, ], 'user' => [ 700, 30, ], ], 'renderfile-nonstandard' => [ 'ip' => [ 70, 30, ], 'user' => [ 70, 30, ], ], 'stashedit' => [ 'ip' => [ 30, 60, ], 'newbie' => [ 30, 60, ], ], 'stashbasehtml' => [ 'ip' => [ 5, 60, ], 'newbie' => [ 5, 60, ], ], 'changetags' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'editcontentmodel' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], ], 'RateLimitsExcludedIPs' => [ ], 'PutIPinRC' => true, 'QueryPageDefaultLimit' => 50, 'ExternalQuerySources' => [ ], 'PasswordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300, ], [ 'count' => 150, 'seconds' => 172800, ], ], 'GrantPermissions' => [ 'basic' => [ 'autocreateaccount' => true, 'autoconfirmed' => true, 'autopatrol' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'nominornewtalk' => true, 'patrolmarks' => true, 'read' => true, 'unwatchedpages' => true, ], 'highvolume' => [ 'bot' => true, 'apihighlimits' => true, 'noratelimit' => true, 'markbotedits' => true, ], 'import' => [ 'import' => true, 'importupload' => true, ], 'editpage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, 'editusercss' => true, 'edituserjs' => true, 'editsitecss' => true, 'editsitejs' => true, ], 'createeditmovepage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'createpage' => true, 'createtalk' => true, 'delete-redirect' => true, 'move' => true, 'move-rootuserpages' => true, 'move-subpages' => true, 'move-categorypages' => true, 'suppressredirect' => true, ], 'uploadfile' => [ 'upload' => true, 'reupload-own' => true, ], 'uploadeditmovefile' => [ 'upload' => true, 'reupload-own' => true, 'reupload' => true, 'reupload-shared' => true, 'upload_by_url' => true, 'movefile' => true, 'suppressredirect' => true, ], 'patrol' => [ 'patrol' => true, ], 'rollback' => [ 'rollback' => true, ], 'blockusers' => [ 'block' => true, 'blockemail' => true, ], 'viewdeleted' => [ 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, ], 'viewrestrictedlogs' => [ 'suppressionlog' => true, ], 'delete' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, 'delete' => true, 'bigdelete' => true, 'deletelogentry' => true, 'deleterevision' => true, 'undelete' => true, ], 'oversight' => [ 'suppressrevision' => true, 'viewsuppressed' => true, ], 'protect' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], ], 'GrantPermissionGroups' => [ 'basic' => 'hidden', 'editpage' => 'page-interaction', 'createeditmovepage' => 'page-interaction', 'editprotected' => 'page-interaction', 'patrol' => 'page-interaction', 'uploadfile' => 'file-interaction', 'uploadeditmovefile' => 'file-interaction', 'sendemail' => 'email', 'viewmywatchlist' => 'watchlist-interaction', 'editviewmywatchlist' => 'watchlist-interaction', 'editmycssjs' => 'customization', 'editmyoptions' => 'customization', 'editinterface' => 'administration', 'editsiteconfig' => 'administration', 'rollback' => 'administration', 'blockusers' => 'administration', 'delete' => 'administration', 'viewdeleted' => 'administration', 'viewrestrictedlogs' => 'administration', 'protect' => 'administration', 'oversight' => 'administration', 'createaccount' => 'administration', 'mergehistory' => 'administration', 'import' => 'administration', 'highvolume' => 'high-volume', 'privateinfo' => 'private-information', ], 'GrantRiskGroups' => [ 'basic' => 'low', 'editpage' => 'low', 'createeditmovepage' => 'low', 'editprotected' => 'vandalism', 'patrol' => 'low', 'uploadfile' => 'low', 'uploadeditmovefile' => 'low', 'sendemail' => 'security', 'viewmywatchlist' => 'low', 'editviewmywatchlist' => 'low', 'editmycssjs' => 'security', 'editmyoptions' => 'security', 'editinterface' => 'vandalism', 'editsiteconfig' => 'security', 'rollback' => 'low', 'blockusers' => 'vandalism', 'delete' => 'vandalism', 'viewdeleted' => 'vandalism', 'viewrestrictedlogs' => 'security', 'protect' => 'vandalism', 'oversight' => 'security', 'createaccount' => 'low', 'mergehistory' => 'vandalism', 'import' => 'security', 'highvolume' => 'low', 'privateinfo' => 'low', ], 'EnableBotPasswords' => true, 'BotPasswordsCluster' => false, 'BotPasswordsDatabase' => false, 'BotPasswordsLimit' => 100, 'SecretKey' => false, 'JwtPrivateKey' => false, 'JwtPublicKey' => false, 'AllowUserJs' => false, 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, 'CSPFalsePositiveUrls' => [ 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'chrome-extension' => true, ], 'AllowCrossOrigin' => false, 'RestAllowCrossOriginCookieAuth' => false, 'SessionSecret' => false, 'CookieExpiration' => 2592000, 'ExtendedLoginCookieExpiration' => 15552000, 'SessionCookieJwtExpiration' => 14400, 'CookieDomain' => '', 'CookiePath' => '/', 'CookieSecure' => 'detect', 'CookiePrefix' => false, 'CookieHttpOnly' => true, 'CookieSameSite' => null, 'CacheVaryCookies' => [ ], 'SessionName' => false, 'CookieSetOnAutoblock' => true, 'CookieSetOnIpBlock' => true, 'DebugLogFile' => '', 'DebugLogPrefix' => '', 'DebugRedirects' => false, 'DebugRawPage' => false, 'DebugComments' => false, 'DebugDumpSql' => false, 'TrxProfilerLimits' => [ 'GET' => [ 'masterConns' => 0, 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'POST-nonwrite' => [ 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'PostSend-GET' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 10000, 'maxAffected' => 1000, 'masterConns' => 0, 'writes' => 0, ], 'PostSend-POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'JobRunner' => [ 'readQueryTime' => 30, 'writeQueryTime' => 5, 'readQueryRows' => 100000, 'maxAffected' => 500, ], 'Maintenance' => [ 'writeQueryTime' => 5, 'maxAffected' => 1000, ], ], 'DebugLogGroups' => [ ], 'MWLoggerDefaultSpi' => [ 'class' => 'MediaWiki\\Logger\\LegacySpi', ], 'ShowDebug' => false, 'SpecialVersionShowHooks' => false, 'ShowExceptionDetails' => false, 'LogExceptionBacktrace' => true, 'PropagateErrors' => true, 'ShowHostnames' => false, 'OverrideHostname' => false, 'DevelopmentWarnings' => false, 'DeprecationReleaseLimit' => false, 'Profiler' => [ ], 'StatsdServer' => false, 'StatsdMetricPrefix' => 'MediaWiki', 'StatsTarget' => null, 'StatsFormat' => null, 'StatsPrefix' => 'mediawiki', 'OpenTelemetryConfig' => null, 'PageInfoTransclusionLimit' => 50, 'EnableJavaScriptTest' => false, 'CachePrefix' => false, 'DebugToolbar' => false, 'ApiClientErrorSampleRate' => 1.0, 'DisableTextSearch' => false, 'AdvancedSearchHighlighting' => false, 'SearchHighlightBoundaries' => '[\\p{Z}\\p{P}\\p{C}]', 'OpenSearchTemplates' => [ 'application/x-suggestions+json' => false, 'application/x-suggestions+xml' => false, ], 'OpenSearchDefaultLimit' => 10, 'OpenSearchDescriptionLength' => 100, 'SearchSuggestCacheExpiry' => 1200, 'DisableSearchUpdate' => false, 'NamespacesToBeSearchedDefault' => [ true, ], 'DisableInternalSearch' => false, 'SearchForwardUrl' => null, 'SitemapNamespaces' => false, 'SitemapNamespacesPriorities' => false, 'SitemapApiConfig' => [ ], 'SpecialSearchFormOptions' => [ ], 'SearchMatchRedirectPreference' => false, 'SearchRunSuggestedQuery' => true, 'Diff3' => '/usr/bin/diff3', 'Diff' => '/usr/bin/diff', 'PreviewOnOpenNamespaces' => [ 14 => true, ], 'UniversalEditButton' => true, 'UseAutomaticEditSummaries' => true, 'CommandLineDarkBg' => false, 'ReadOnly' => null, 'ReadOnlyWatchedItemStore' => false, 'ReadOnlyFile' => false, 'UpgradeKey' => false, 'GitBin' => '/usr/bin/git', 'GitRepositoryViewers' => [ 'https: 'ssh: ], 'InstallerInitialPages' => [ [ 'titlemsg' => 'mainpage', 'text' => '{{subst:int:mainpagetext}}{{subst:int:mainpagedocfooter}}', ], ], 'RCMaxAge' => 7776000, 'WatchersMaxAge' => 15552000, 'UnwatchedPageSecret' => 1, 'RCFilterByAge' => false, 'RCLinkLimits' => [ 50, 100, 250, 500, ], 'RCLinkDays' => [ 1, 3, 7, 14, 30, ], 'RCFeeds' => [ ], 'RCWatchCategoryMembership' => false, 'UseRCPatrol' => true, 'StructuredChangeFiltersLiveUpdatePollingRate' => 3, 'UseNPPatrol' => true, 'UseFilePatrol' => true, 'Feed' => true, 'FeedLimit' => 50, 'FeedCacheTimeout' => 60, 'FeedDiffCutoff' => 32768, 'OverrideSiteFeed' => [ ], 'FeedClasses' => [ 'rss' => 'MediaWiki\\Feed\\RSSFeed', 'atom' => 'MediaWiki\\Feed\\AtomFeed', ], 'AdvertisedFeedTypes' => [ 'atom', ], 'RCShowWatchingUsers' => false, 'RCShowChangedSize' => true, 'RCChangedSizeThreshold' => 500, 'ShowUpdatedMarker' => true, 'DisableAnonTalk' => false, 'UseTagFilter' => true, 'SoftwareTags' => [ 'mw-contentmodelchange' => true, 'mw-new-redirect' => true, 'mw-removed-redirect' => true, 'mw-changed-redirect-target' => true, 'mw-blank' => true, 'mw-replace' => true, 'mw-recreated' => true, 'mw-rollback' => true, 'mw-undo' => true, 'mw-manual-revert' => true, 'mw-reverted' => true, 'mw-server-side-upload' => true, 'mw-ipblock-appeal' => true, ], 'UnwatchedPageThreshold' => false, 'RecentChangesFlags' => [ 'newpage' => [ 'letter' => 'newpageletter', 'title' => 'recentchanges-label-newpage', 'legend' => 'recentchanges-legend-newpage', 'grouping' => 'any', ], 'minor' => [ 'letter' => 'minoreditletter', 'title' => 'recentchanges-label-minor', 'legend' => 'recentchanges-legend-minor', 'class' => 'minoredit', 'grouping' => 'all', ], 'bot' => [ 'letter' => 'boteditletter', 'title' => 'recentchanges-label-bot', 'legend' => 'recentchanges-legend-bot', 'class' => 'botedit', 'grouping' => 'all', ], 'unpatrolled' => [ 'letter' => 'unpatrolledletter', 'title' => 'recentchanges-label-unpatrolled', 'legend' => 'recentchanges-legend-unpatrolled', 'grouping' => 'any', ], ], 'WatchlistExpiry' => false, 'EnableWatchlistLabels' => false, 'WatchlistLabelsMaxPerUser' => 100, 'WatchlistPurgeRate' => 0.1, 'WatchlistExpiryMaxDuration' => '1 year', 'EnableChangesListQueryPartitioning' => false, 'RightsPage' => null, 'RightsUrl' => null, 'RightsText' => null, 'RightsIcon' => null, 'UseCopyrightUpload' => false, 'MaxCredits' => 0, 'ShowCreditsIfMax' => true, 'ImportSources' => [ ], 'ImportTargetNamespace' => null, 'ExportAllowHistory' => true, 'ExportMaxHistory' => 0, 'ExportAllowListContributors' => false, 'ExportMaxLinkDepth' => 0, 'ExportFromNamespaces' => false, 'ExportAllowAll' => false, 'ExportPagelistLimit' => 5000, 'XmlDumpSchemaVersion' => '0.11', 'WikiFarmSettingsDirectory' => null, 'WikiFarmSettingsExtension' => 'yaml', 'ExtensionFunctions' => [ ], 'ExtensionMessagesFiles' => [ ], 'MessagesDirs' => [ ], 'TranslationAliasesDirs' => [ ], 'ExtensionEntryPointListFiles' => [ ], 'EnableParserLimitReporting' => true, 'ValidSkinNames' => [ ], 'SpecialPages' => [ ], 'ExtensionCredits' => [ ], 'Hooks' => [ ], 'ServiceWiringFiles' => [ ], 'JobClasses' => [ 'deletePage' => 'MediaWiki\\Page\\DeletePageJob', 'refreshLinks' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'deleteLinks' => 'MediaWiki\\Page\\DeleteLinksJob', 'htmlCacheUpdate' => 'MediaWiki\\JobQueue\\Jobs\\HTMLCacheUpdateJob', 'sendMail' => [ 'class' => 'MediaWiki\\Mail\\EmaillingJob', 'services' => [ 'Emailer', ], ], 'enotifNotify' => [ 'class' => 'MediaWiki\\RecentChanges\\RecentChangeNotifyJob', 'services' => [ 'RecentChangeLookup', ], ], 'fixDoubleRedirect' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\DoubleRedirectJob', 'services' => [ 'RevisionLookup', 'MagicWordFactory', 'WikiPageFactory', ], 'needsPage' => true, ], 'AssembleUploadChunks' => 'MediaWiki\\JobQueue\\Jobs\\AssembleUploadChunksJob', 'PublishStashedFile' => 'MediaWiki\\JobQueue\\Jobs\\PublishStashedFileJob', 'ThumbnailRender' => 'MediaWiki\\JobQueue\\Jobs\\ThumbnailRenderJob', 'UploadFromUrl' => 'MediaWiki\\JobQueue\\Jobs\\UploadFromUrlJob', 'recentChangesUpdate' => 'MediaWiki\\RecentChanges\\RecentChangesUpdateJob', 'refreshLinksPrioritized' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'refreshLinksDynamic' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'activityUpdateJob' => 'MediaWiki\\Watchlist\\ActivityUpdateJob', 'categoryMembershipChange' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryMembershipChangeJob', 'services' => [ 'RecentChangeFactory', ], ], 'CategoryCountUpdateJob' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryCountUpdateJob', 'services' => [ 'ConnectionProvider', 'NamespaceInfo', ], ], 'clearUserWatchlist' => 'MediaWiki\\Watchlist\\ClearUserWatchlistJob', 'watchlistExpiry' => 'MediaWiki\\Watchlist\\WatchlistExpiryJob', 'cdnPurge' => 'MediaWiki\\JobQueue\\Jobs\\CdnPurgeJob', 'userGroupExpiry' => 'MediaWiki\\User\\UserGroupExpiryJob', 'clearWatchlistNotifications' => 'MediaWiki\\Watchlist\\ClearWatchlistNotificationsJob', 'userOptionsUpdate' => 'MediaWiki\\User\\Options\\UserOptionsUpdateJob', 'revertedTagUpdate' => 'MediaWiki\\JobQueue\\Jobs\\RevertedTagUpdateJob', 'null' => 'MediaWiki\\JobQueue\\Jobs\\NullJob', 'userEditCountInit' => 'MediaWiki\\User\\UserEditCountInitJob', 'parsoidCachePrewarm' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\ParsoidCachePrewarmJob', 'services' => [ 'ParserOutputAccess', 'PageStore', 'RevisionLookup', 'ParsoidSiteConfig', ], 'needsPage' => false, ], 'renameUserTable' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], 'renameUserDerived' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserDerivedJob', 'services' => [ 'RenameUserFactory', 'UserFactory', ], ], 'renameUser' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], ], 'JobTypesExcludedFromDefaultQueue' => [ 'AssembleUploadChunks', 'PublishStashedFile', 'UploadFromUrl', ], 'JobBackoffThrottling' => [ ], 'JobTypeConf' => [ 'default' => [ 'class' => 'MediaWiki\\JobQueue\\JobQueueDB', 'order' => 'random', 'claimTTL' => 3600, ], ], 'JobQueueIncludeInMaxLagFactor' => false, 'SpecialPageCacheUpdates' => [ 'Statistics' => [ 'MediaWiki\\Deferred\\SiteStatsUpdate', 'cacheUpdate', ], ], 'PagePropLinkInvalidations' => [ 'hiddencat' => 'categorylinks', ], 'CategoryMagicGallery' => true, 'CategoryPagingLimit' => 200, 'CategoryCollation' => 'uppercase', 'TempCategoryCollations' => [ ], 'SortedCategories' => false, 'TrackingCategories' => [ ], 'LogTypes' => [ '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'import', 'interwiki', 'patrol', 'merge', 'suppress', 'tag', 'managetags', 'contentmodel', 'renameuser', ], 'LogRestrictions' => [ 'suppress' => 'suppressionlog', ], 'FilterLogTypes' => [ 'patrol' => true, 'tag' => true, 'newusers' => false, ], 'LogNames' => [ '' => 'all-logs-page', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage', 'import' => 'importlogpage', 'patrol' => 'patrol-log-page', 'merge' => 'mergelog', 'suppress' => 'suppressionlog', ], 'LogHeaders' => [ '' => 'alllogstext', 'block' => 'blocklogtext', 'delete' => 'dellogpagetext', 'import' => 'importlogpagetext', 'merge' => 'mergelogpagetext', 'move' => 'movelogpagetext', 'patrol' => 'patrol-log-header', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'suppress' => 'suppressionlogtext', 'upload' => 'uploadlogpagetext', ], 'LogActions' => [ ], 'LogActionsHandlers' => [ 'block/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/unblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'contentmodel/change' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'contentmodel/new' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'delete/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir2' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/restore' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'import/interwiki' => 'MediaWiki\\Logging\\ImportLogFormatter', 'import/upload' => 'MediaWiki\\Logging\\ImportLogFormatter', 'interwiki/iw_add' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_delete' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_edit' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'managetags/activate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/create' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/deactivate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/delete' => 'MediaWiki\\Logging\\LogFormatter', 'merge/merge' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'merge/merge-into' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move_redir' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'patrol/patrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'patrol/autopatrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'protect/modify' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/move_prot' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/protect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/unprotect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'renameuser/renameuser' => [ 'class' => 'MediaWiki\\Logging\\RenameuserLogFormatter', 'services' => [ 'TitleParser', ], ], 'rights/autopromote' => 'MediaWiki\\Logging\\RightsLogFormatter', 'rights/rights' => 'MediaWiki\\Logging\\RightsLogFormatter', 'suppress/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'tag/update' => 'MediaWiki\\Logging\\TagLogFormatter', 'upload/overwrite' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/revert' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/upload' => 'MediaWiki\\Logging\\UploadLogFormatter', ], 'ActionFilteredLogs' => [ 'block' => [ 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], 'unblock' => [ 'unblock', ], ], 'contentmodel' => [ 'change' => [ 'change', ], 'new' => [ 'new', ], ], 'delete' => [ 'delete' => [ 'delete', ], 'delete_redir' => [ 'delete_redir', 'delete_redir2', ], 'restore' => [ 'restore', ], 'event' => [ 'event', ], 'revision' => [ 'revision', ], ], 'import' => [ 'interwiki' => [ 'interwiki', ], 'upload' => [ 'upload', ], ], 'managetags' => [ 'create' => [ 'create', ], 'delete' => [ 'delete', ], 'activate' => [ 'activate', ], 'deactivate' => [ 'deactivate', ], ], 'move' => [ 'move' => [ 'move', ], 'move_redir' => [ 'move_redir', ], ], 'newusers' => [ 'create' => [ 'create', 'newusers', ], 'create2' => [ 'create2', ], 'autocreate' => [ 'autocreate', ], 'byemail' => [ 'byemail', ], ], 'protect' => [ 'protect' => [ 'protect', ], 'modify' => [ 'modify', ], 'unprotect' => [ 'unprotect', ], 'move_prot' => [ 'move_prot', ], ], 'rights' => [ 'rights' => [ 'rights', ], 'autopromote' => [ 'autopromote', ], ], 'suppress' => [ 'event' => [ 'event', ], 'revision' => [ 'revision', ], 'delete' => [ 'delete', ], 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], ], 'upload' => [ 'upload' => [ 'upload', ], 'overwrite' => [ 'overwrite', ], 'revert' => [ 'revert', ], ], ], 'NewUserLog' => true, 'PageCreationLog' => true, 'AllowSpecialInclusion' => true, 'DisableQueryPageUpdate' => false, 'CountCategorizedImagesAsUsed' => false, 'MaxRedirectLinksRetrieved' => 500, 'RangeContributionsCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 32, ], 'Actions' => [ ], 'DefaultRobotPolicy' => 'index,follow', 'NamespaceRobotPolicies' => [ ], 'ArticleRobotPolicies' => [ ], 'ExemptFromUserRobotsControl' => null, 'DebugAPI' => false, 'APIModules' => [ ], 'APIFormatModules' => [ ], 'APIMetaModules' => [ ], 'APIPropModules' => [ ], 'APIListModules' => [ ], 'APIMaxDBRows' => 5000, 'APIMaxResultSize' => 8388608, 'APIMaxUncachedDiffs' => 1, 'APIMaxLagThreshold' => 7, 'APICacheHelpTimeout' => 3600, 'APIUselessQueryPages' => [ 'MIMEsearch', 'LinkSearch', ], 'AjaxLicensePreview' => true, 'CrossSiteAJAXdomains' => [ ], 'CrossSiteAJAXdomainExceptions' => [ ], 'AllowedCorsHeaders' => [ 'Accept', 'Accept-Language', 'Content-Language', 'Content-Type', 'Accept-Encoding', 'DNT', 'Origin', 'User-Agent', 'Api-User-Agent', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestSandboxSpecs' => [ ], 'MaxShellMemory' => 307200, 'MaxShellFileSize' => 102400, 'MaxShellTime' => 180, 'MaxShellWallClockTime' => 180, 'ShellCgroup' => false, 'PhpCli' => '/usr/bin/php', 'ShellRestrictionMethod' => 'autodetect', 'ShellboxUrls' => [ 'default' => null, ], 'ShellboxSecretKey' => null, 'ShellboxShell' => '/bin/sh', 'HTTPTimeout' => 25, 'HTTPConnectTimeout' => 5.0, 'HTTPMaxTimeout' => 0, 'HTTPMaxConnectTimeout' => 0, 'HTTPImportTimeout' => 25, 'AsyncHTTPTimeout' => 25, 'HTTPProxy' => '', 'LocalVirtualHosts' => [ ], 'LocalHTTPProxy' => false, 'AllowExternalReqID' => false, 'GenerateReqIDFormat' => 'rand24', 'JobRunRate' => 1, 'RunJobsAsync' => false, 'UpdateRowsPerJob' => 300, 'UpdateRowsPerQuery' => 100, 'RedirectOnLogin' => null, 'VirtualRestConfig' => [ 'paths' => [ ], 'modules' => [ ], 'global' => [ 'timeout' => 360, 'forwardCookies' => false, 'HTTPProxy' => null, ], ], 'EventRelayerConfig' => [ 'default' => [ 'class' => 'Wikimedia\\EventRelayer\\EventRelayerNull', ], ], 'Pingback' => false, 'OriginTrials' => [ ], 'ReportToExpiry' => 86400, 'ReportToEndpoints' => [ ], 'FeaturePolicyReportOnly' => [ ], 'SkinsPreferred' => [ 'vector-2022', 'vector', ], 'SpecialContributeSkinsEnabled' => [ ], 'SpecialContributeNewPageTarget' => null, 'EnableEditRecovery' => false, 'EditRecoveryExpiry' => 2592000, 'UseCodexSpecialBlock' => false, 'ShowLogoutConfirmation' => false, 'EnableProtectionIndicators' => true, 'OutputPipelineStages' => [ ], 'FeatureShutdown' => [ ], 'CloneArticleParserOutput' => true, 'UseLeximorph' => false, 'UsePostprocCacheLegacy' => false, 'UsePostprocCacheParsoid' => true, 'ParserOptionsLogUnsafeSampleRate' => 0, ], 'type' => [ 'ConfigRegistry' => 'object', 'AssumeProxiesUseDefaultProtocolPorts' => 'boolean', 'ForceHTTPS' => 'boolean', 'ExtensionDirectory' => [ 'string', 'null', ], 'StyleDirectory' => [ 'string', 'null', ], 'UploadDirectory' => [ 'string', 'boolean', 'null', ], 'Logos' => [ 'object', 'boolean', ], 'ReferrerPolicy' => [ 'array', 'string', 'boolean', ], 'ActionPaths' => 'object', 'MainPageIsDomainRoot' => 'boolean', 'ImgAuthUrlPathMap' => 'object', 'LocalFileRepo' => 'object', 'ForeignFileRepos' => 'array', 'UseSharedUploads' => 'boolean', 'SharedUploadDirectory' => [ 'string', 'null', ], 'SharedUploadPath' => [ 'string', 'null', ], 'HashedSharedUploadDirectory' => 'boolean', 'FetchCommonsDescriptions' => 'boolean', 'SharedUploadDBname' => [ 'boolean', 'string', ], 'SharedUploadDBprefix' => 'string', 'CacheSharedUploads' => 'boolean', 'ForeignUploadTargets' => 'array', 'UploadDialog' => 'object', 'FileBackends' => 'object', 'LockManagers' => 'array', 'CopyUploadsDomains' => 'array', 'CopyUploadTimeout' => [ 'boolean', 'integer', ], 'SharedThumbnailScriptPath' => [ 'string', 'boolean', ], 'HashedUploadDirectory' => 'boolean', 'CSPUploadEntryPoint' => 'boolean', 'FileExtensions' => 'array', 'ProhibitedFileExtensions' => 'array', 'MimeTypeExclusions' => 'array', 'TrustedMediaFormats' => 'array', 'MediaHandlers' => 'object', 'NativeImageLazyLoading' => 'boolean', 'ParserTestMediaHandlers' => 'object', 'MaxInterlacingAreas' => 'object', 'SVGConverters' => 'object', 'SVGNativeRendering' => [ 'string', 'boolean', ], 'MaxImageArea' => [ 'string', 'integer', 'boolean', ], 'TiffThumbnailType' => 'array', 'GenerateThumbnailOnParse' => 'boolean', 'EnableAutoRotation' => [ 'boolean', 'null', ], 'Antivirus' => [ 'string', 'null', ], 'AntivirusSetup' => 'object', 'MimeDetectorCommand' => [ 'string', 'null', ], 'XMLMimeTypes' => 'object', 'ImageLimits' => 'array', 'ThumbLimits' => 'array', 'ThumbnailNamespaces' => 'array', 'ThumbnailSteps' => [ 'array', 'null', ], 'ThumbnailStepsRatio' => [ 'number', 'null', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EmailConfirmationBanner' => 'boolean', 'EnotifRevealEditorAddress' => 'boolean', 'UsersNotifiedOnAllChanges' => 'object', 'DBmwschema' => [ 'string', 'null', ], 'SharedTables' => 'array', 'DBservers' => [ 'boolean', 'array', ], 'LBFactoryConf' => 'object', 'LocalDatabases' => 'array', 'VirtualDomainsMapping' => 'object', 'FileSchemaMigrationStage' => 'integer', 'ExternalLinksDomainGaps' => 'object', 'ContentHandlers' => 'object', 'NamespaceContentModels' => 'object', 'TextModelsToParse' => 'array', 'ExternalStores' => 'array', 'ExternalServers' => 'object', 'DefaultExternalStore' => [ 'array', 'boolean', ], 'RevisionCacheExpiry' => 'integer', 'PageLanguageUseDB' => 'boolean', 'DiffEngine' => [ 'string', 'null', ], 'ExternalDiffEngine' => [ 'string', 'boolean', ], 'Wikidiff2Options' => 'object', 'RequestTimeLimit' => [ 'integer', 'null', ], 'CriticalSectionTimeLimit' => 'number', 'PoolCounterConf' => [ 'object', 'null', ], 'PoolCountClientConf' => 'object', 'MaxUserDBWriteDuration' => [ 'integer', 'boolean', ], 'MaxJobDBWriteDuration' => [ 'integer', 'boolean', ], 'MultiShardSiteStats' => 'boolean', 'ObjectCaches' => 'object', 'WANObjectCache' => 'object', 'MicroStashType' => [ 'string', 'integer', ], 'ParsoidCacheConfig' => 'object', 'ParsoidSelectiveUpdateSampleRate' => 'integer', 'ParserCacheFilterConfig' => 'object', 'ChronologyProtectorSecret' => 'string', 'PHPSessionHandling' => 'string', 'SuspiciousIpExpiry' => [ 'integer', 'boolean', ], 'MemCachedServers' => 'array', 'LocalisationCacheConf' => 'object', 'ExtensionInfoMTime' => [ 'integer', 'boolean', ], 'CdnServers' => 'object', 'CdnServersNoPurge' => 'object', 'HTCPRouting' => 'object', 'GrammarForms' => 'object', 'ExtraInterlanguageLinkPrefixes' => 'array', 'InterlanguageLinkCodeMap' => 'object', 'ExtraLanguageNames' => 'object', 'ExtraLanguageCodes' => 'object', 'DummyLanguageCodes' => 'object', 'DisabledVariants' => 'object', 'ForceUIMsgAsContentMsg' => 'object', 'RawHtmlMessages' => 'array', 'OverrideUcfirstCharacters' => 'object', 'XhtmlNamespaces' => 'object', 'BrowserFormatDetection' => 'string', 'SkinMetaTags' => 'object', 'SkipSkins' => 'object', 'FragmentMode' => 'array', 'FooterIcons' => 'object', 'InterwikiLogoOverride' => 'array', 'ResourceModules' => 'object', 'ResourceModuleSkinStyles' => 'object', 'ResourceLoaderSources' => 'object', 'ResourceLoaderMaxage' => 'object', 'ResourceLoaderMaxQueryLength' => [ 'integer', 'boolean', ], 'CanonicalNamespaceNames' => 'object', 'ExtraNamespaces' => 'object', 'ExtraGenderNamespaces' => 'object', 'NamespaceAliases' => 'object', 'CapitalLinkOverrides' => 'object', 'NamespacesWithSubpages' => 'object', 'ContentNamespaces' => 'array', 'ShortPagesNamespaceExclusions' => 'array', 'ExtraSignatureNamespaces' => 'array', 'InvalidRedirectTargets' => 'array', 'LocalInterwikis' => 'array', 'InterwikiCache' => [ 'boolean', 'object', ], 'SiteTypes' => 'object', 'UrlProtocols' => 'array', 'TidyConfig' => 'object', 'ParsoidSettings' => 'object', 'ParsoidExperimentalParserFunctionOutput' => 'boolean', 'NoFollowNsExceptions' => 'array', 'NoFollowDomainExceptions' => 'array', 'ExternalLinksIgnoreDomains' => 'array', 'EnableMagicLinks' => 'object', 'ManualRevertSearchRadius' => 'integer', 'RevertedTagMaxDepth' => 'integer', 'CentralIdLookupProviders' => 'object', 'CentralIdLookupProvider' => 'string', 'UserRegistrationProviders' => 'object', 'PasswordPolicy' => 'object', 'AuthManagerConfig' => [ 'object', 'null', ], 'AuthManagerAutoConfig' => 'object', 'RememberMe' => 'string', 'ReauthenticateTime' => 'object', 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => 'object', 'ChangeCredentialsBlacklist' => 'array', 'RemoveCredentialsBlacklist' => 'array', 'PasswordConfig' => 'object', 'PasswordResetRoutes' => 'object', 'SignatureAllowedLintErrors' => 'array', 'ReservedUsernames' => 'array', 'DefaultUserOptions' => 'object', 'ConditionalUserOptions' => 'object', 'HiddenPrefs' => 'array', 'UserJsPrefLimit' => 'integer', 'AuthenticationTokenVersion' => [ 'string', 'null', ], 'SessionProviders' => 'object', 'AutoCreateTempUser' => 'object', 'AutoblockExemptions' => 'array', 'BlockCIDRLimit' => 'object', 'EnableMultiBlocks' => 'boolean', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', 'UserRequirementsPrivateConditions' => 'array', 'RestrictionTypes' => 'array', 'RestrictionLevels' => 'array', 'CascadingRestrictionLevels' => 'array', 'SemiprotectedRestrictionLevels' => 'array', 'NamespaceProtection' => 'object', 'NonincludableNamespaces' => 'object', 'Autopromote' => 'object', 'AutopromoteOnce' => 'object', 'AutopromoteOnceRCExcludedGroups' => 'array', 'AddGroups' => 'object', 'RemoveGroups' => 'object', 'AvailableRights' => 'array', 'ImplicitRights' => 'array', 'AccountCreationThrottle' => [ 'integer', 'array', ], 'TempAccountCreationThrottle' => 'array', 'TempAccountNameAcquisitionThrottle' => 'array', 'SpamRegex' => 'array', 'SummarySpamRegex' => 'array', 'DnsBlacklistUrls' => 'array', 'ProxyList' => [ 'string', 'array', ], 'ProxyWhitelist' => 'array', 'SoftBlockRanges' => 'array', 'RateLimits' => 'object', 'RateLimitsExcludedIPs' => 'array', 'ExternalQuerySources' => 'object', 'PasswordAttemptThrottle' => 'array', 'GrantPermissions' => 'object', 'GrantPermissionGroups' => 'object', 'GrantRiskGroups' => 'object', 'EnableBotPasswords' => 'boolean', 'BotPasswordsCluster' => [ 'string', 'boolean', ], 'BotPasswordsDatabase' => [ 'string', 'boolean', ], 'BotPasswordsLimit' => 'integer', 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPFalsePositiveUrls' => 'object', 'AllowCrossOrigin' => 'boolean', 'RestAllowCrossOriginCookieAuth' => 'boolean', 'CookieSameSite' => [ 'string', 'null', ], 'CacheVaryCookies' => 'array', 'TrxProfilerLimits' => 'object', 'DebugLogGroups' => 'object', 'MWLoggerDefaultSpi' => 'object', 'Profiler' => 'object', 'StatsTarget' => [ 'string', 'null', ], 'StatsFormat' => [ 'string', 'null', ], 'StatsPrefix' => 'string', 'OpenTelemetryConfig' => [ 'object', 'null', ], 'OpenSearchTemplates' => 'object', 'NamespacesToBeSearchedDefault' => 'object', 'SitemapNamespaces' => [ 'boolean', 'array', ], 'SitemapNamespacesPriorities' => [ 'boolean', 'object', ], 'SitemapApiConfig' => 'object', 'SpecialSearchFormOptions' => 'object', 'SearchMatchRedirectPreference' => 'boolean', 'SearchRunSuggestedQuery' => 'boolean', 'PreviewOnOpenNamespaces' => 'object', 'ReadOnlyWatchedItemStore' => 'boolean', 'GitRepositoryViewers' => 'object', 'InstallerInitialPages' => 'array', 'RCLinkLimits' => 'array', 'RCLinkDays' => 'array', 'RCFeeds' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchlistLabels' => 'boolean', 'WatchlistLabelsMaxPerUser' => 'integer', 'WatchlistPurgeRate' => 'number', 'WatchlistExpiryMaxDuration' => [ 'string', 'null', ], 'EnableChangesListQueryPartitioning' => 'boolean', 'ImportSources' => 'object', 'ExtensionFunctions' => 'array', 'ExtensionMessagesFiles' => 'object', 'MessagesDirs' => 'object', 'TranslationAliasesDirs' => 'object', 'ExtensionEntryPointListFiles' => 'object', 'ValidSkinNames' => 'object', 'SpecialPages' => 'object', 'ExtensionCredits' => 'object', 'Hooks' => 'object', 'ServiceWiringFiles' => 'array', 'JobClasses' => 'object', 'JobTypesExcludedFromDefaultQueue' => 'array', 'JobBackoffThrottling' => 'object', 'JobTypeConf' => 'object', 'SpecialPageCacheUpdates' => 'object', 'PagePropLinkInvalidations' => 'object', 'TempCategoryCollations' => 'array', 'SortedCategories' => 'boolean', 'TrackingCategories' => 'array', 'LogTypes' => 'array', 'LogRestrictions' => 'object', 'FilterLogTypes' => 'object', 'LogNames' => 'object', 'LogHeaders' => 'object', 'LogActions' => 'object', 'LogActionsHandlers' => 'object', 'ActionFilteredLogs' => 'object', 'RangeContributionsCIDRLimit' => 'object', 'Actions' => 'object', 'NamespaceRobotPolicies' => 'object', 'ArticleRobotPolicies' => 'object', 'ExemptFromUserRobotsControl' => [ 'array', 'null', ], 'APIModules' => 'object', 'APIFormatModules' => 'object', 'APIMetaModules' => 'object', 'APIPropModules' => 'object', 'APIListModules' => 'object', 'APIUselessQueryPages' => 'array', 'CrossSiteAJAXdomains' => 'object', 'CrossSiteAJAXdomainExceptions' => 'object', 'AllowedCorsHeaders' => 'array', 'RestAPIAdditionalRouteFiles' => 'array', 'RestSandboxSpecs' => 'object', 'ShellRestrictionMethod' => [ 'string', 'boolean', ], 'ShellboxUrls' => 'object', 'ShellboxSecretKey' => [ 'string', 'null', ], 'ShellboxShell' => [ 'string', 'null', ], 'HTTPTimeout' => 'number', 'HTTPConnectTimeout' => 'number', 'HTTPMaxTimeout' => 'number', 'HTTPMaxConnectTimeout' => 'number', 'LocalVirtualHosts' => 'object', 'LocalHTTPProxy' => [ 'string', 'boolean', ], 'GenerateReqIDFormat' => 'string', 'VirtualRestConfig' => 'object', 'EventRelayerConfig' => 'object', 'Pingback' => 'boolean', 'OriginTrials' => 'array', 'ReportToExpiry' => 'integer', 'ReportToEndpoints' => 'array', 'FeaturePolicyReportOnly' => 'array', 'SkinsPreferred' => 'array', 'SpecialContributeSkinsEnabled' => 'array', 'SpecialContributeNewPageTarget' => [ 'string', 'null', ], 'EnableEditRecovery' => 'boolean', 'EditRecoveryExpiry' => 'integer', 'UseCodexSpecialBlock' => 'boolean', 'ShowLogoutConfirmation' => 'boolean', 'EnableProtectionIndicators' => 'boolean', 'OutputPipelineStages' => 'object', 'FeatureShutdown' => 'array', 'CloneArticleParserOutput' => 'boolean', 'UseLeximorph' => 'boolean', 'UsePostprocCacheLegacy' => 'boolean', 'UsePostprocCacheParsoid' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', ], 'mergeStrategy' => [ 'TiffThumbnailType' => 'replace', 'LBFactoryConf' => 'replace', 'InterwikiCache' => 'replace', 'PasswordPolicy' => 'array_replace_recursive', 'AuthManagerAutoConfig' => 'array_plus_2d', 'GroupPermissions' => 'array_plus_2d', 'RevokePermissions' => 'array_plus_2d', 'AddGroups' => 'array_merge_recursive', 'RemoveGroups' => 'array_merge_recursive', 'RateLimits' => 'array_plus_2d', 'GrantPermissions' => 'array_plus_2d', 'MWLoggerDefaultSpi' => 'replace', 'Profiler' => 'replace', 'Hooks' => 'array_merge_recursive', 'VirtualRestConfig' => 'array_plus_2d', ], 'dynamicDefault' => [ 'UsePathInfo' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUsePathInfo', ], ], 'Script' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultScript', ], ], 'LoadScript' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLoadScript', ], ], 'RestPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultRestPath', ], ], 'StylePath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultStylePath', ], ], 'LocalStylePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalStylePath', ], ], 'ExtensionAssetsPath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultExtensionAssetsPath', ], ], 'ArticlePath' => [ 'use' => [ 'Script', 'UsePathInfo', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultArticlePath', ], ], 'UploadPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUploadPath', ], ], 'FileCacheDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultFileCacheDirectory', ], ], 'Logo' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLogo', ], ], 'DeletedDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDeletedDirectory', ], ], 'ShowEXIF' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultShowEXIF', ], ], 'SharedPrefix' => [ 'use' => [ 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedPrefix', ], ], 'SharedSchema' => [ 'use' => [ 'DBmwschema', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedSchema', ], ], 'DBerrorLogTZ' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDBerrorLogTZ', ], ], 'Localtimezone' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocaltimezone', ], ], 'LocalTZoffset' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalTZoffset', ], ], 'ResourceBasePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultResourceBasePath', ], ], 'MetaNamespace' => [ 'use' => [ 'Sitename', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultMetaNamespace', ], ], 'CookieSecure' => [ 'use' => [ 'ForceHTTPS', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookieSecure', ], ], 'CookiePrefix' => [ 'use' => [ 'SharedDB', 'SharedPrefix', 'SharedTables', 'DBname', 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookiePrefix', ], ], 'ReadOnlyFile' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultReadOnlyFile', ], ], ], ], 'config-schema' => [ 'UploadStashScalerBaseUrl' => [ 'deprecated' => 'since 1.36 Use thumbProxyUrl in $wgLocalFileRepo', ], 'IllegalFileChars' => [ 'deprecated' => 'since 1.41; no longer customizable', ], 'ThumbnailNamespaces' => [ 'items' => [ 'type' => 'integer', ], ], 'LocalDatabases' => [ 'items' => [ 'type' => 'string', ], ], 'ParserCacheFilterConfig' => [ 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of namespace IDs to filter definitions.', 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of filter names to values.', 'properties' => [ 'minCpuTime' => [ 'type' => 'number', ], ], ], ], ], 'PHPSessionHandling' => [ 'deprecated' => 'since 1.45 Integration with PHP session handling will be removed in the future', ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'ChangeCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'RemoveCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'GroupPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GroupInheritsPermissions' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'AvailableRights' => [ 'items' => [ 'type' => 'string', ], ], 'ImplicitRights' => [ 'items' => [ 'type' => 'string', ], ], 'SoftBlockRanges' => [ 'items' => [ 'type' => 'string', ], ], 'ExternalQuerySources' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'enabled' => [ 'type' => 'boolean', 'default' => false, ], 'url' => [ 'type' => 'string', 'format' => 'uri', ], 'timeout' => [ 'type' => 'integer', 'default' => 10, ], ], 'required' => [ 'enabled', 'url', ], 'additionalProperties' => false, ], ], 'GrantPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GrantPermissionGroups' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'SitemapNamespacesPriorities' => [ 'deprecated' => 'since 1.45 and ignored', ], 'SitemapApiConfig' => [ 'additionalProperties' => [ 'enabled' => [ 'type' => 'bool', ], 'sitemapsPerIndex' => [ 'type' => 'int', ], 'pagesPerSitemap' => [ 'type' => 'int', ], 'expiry' => [ 'type' => 'int', ], ], ], 'SoftwareTags' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'JobBackoffThrottling' => [ 'additionalProperties' => [ 'type' => 'number', ], ], 'JobTypeConf' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'class' => [ 'type' => 'string', ], 'order' => [ 'type' => 'string', ], 'claimTTL' => [ 'type' => 'integer', ], ], ], ], 'TrackingCategories' => [ 'deprecated' => 'since 1.25 Extensions should now register tracking categories using the new extension registration system.', ], 'RangeContributionsCIDRLimit' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'RestSandboxSpecs' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'url' => [ 'type' => 'string', 'format' => 'url', ], 'name' => [ 'type' => 'string', ], 'file' => [ 'type' => 'string', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], ], ], 'ShellboxUrls' => [ 'additionalProperties' => [ 'type' => [ 'string', 'boolean', 'null', ], ], ], ], 'obsolete-config' => [ 'MangleFlashPolicy' => 'Since 1.39; no longer has any effect.', 'EnableOpenSearchSuggest' => 'Since 1.35, no longer used', 'AutoloadAttemptLowercase' => 'Since 1.40; no longer has any effect.', ],]
Represents a block that may prevent users from performing specific operations.
Definition Block.php:31
Interface for objects representing user identity.
Interface for database access objects.
msg( $key,... $params)