MediaWiki master
Skin.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\Skin;
8
10use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
36use Wikimedia\IPUtils;
39
52abstract class Skin extends ContextSource {
53 use ProtectedHookAccessorTrait;
54
58 private $defaultLinkOptions;
59
63 protected $skinname = null;
64
68 protected $options = [];
70 protected $mRelevantTitle = null;
71
75 private $mRelevantUser = false;
76
78 protected const VERSION_MAJOR = 1;
79
81 private $languageLinks;
82
84 private $sidebar;
85
89 private $componentRegistry = null;
90
98 public static function getVersion() {
100 }
101
107 final protected function getComponent( string $name ): SkinComponent {
108 return $this->componentRegistry->getComponent( $name );
109 }
110
132 public function getTemplateData() {
133 $title = $this->getTitle();
134 $out = $this->getOutput();
135 $user = $this->getUser();
136 $isMainPage = $title->isMainPage();
137 $blankedHeading = false;
138 // Heading can only be blanked on "views". It should
139 // still show on action=edit, diff pages and action=history
140 $isHeadingOverridable = $this->getContext()->getActionName() === 'view' &&
141 !$this->getRequest()->getRawVal( 'diff' );
142
143 if ( $isMainPage && $isHeadingOverridable ) {
144 // Special casing for the main page to allow more freedom to editors, to
145 // design their home page differently. This came up in T290480.
146 // The parameter for logged in users is optional and may
147 // or may not be used.
148 $titleMsg = $user->isAnon() ?
149 $this->msg( 'mainpage-title' ) :
150 $this->msg( 'mainpage-title-loggedin', $user->getName() );
151
152 // T298715: Use content language rather than user language so that
153 // the custom page heading is shown to all users, not just those that have
154 // their interface set to the site content language.
155 //
156 // T331095: Avoid Message::inContentLanuguage and, just like Parser,
157 // pick the language variant based on the current URL and/or user
158 // preference if their variant relates to the content language.
159 $forceUIMsgAsContentMsg = $this->getConfig()
161 if ( !in_array( $titleMsg->getKey(), (array)$forceUIMsgAsContentMsg ) ) {
162 $services = MediaWikiServices::getInstance();
163 $contLangVariant = $services->getLanguageConverterFactory()
164 ->getLanguageConverter( $services->getContentLanguage() )
165 ->getPreferredVariant();
166 $titleMsg->inLanguage( $contLangVariant );
167 }
168 $titleMsg->setInterfaceMessageFlag( true );
169 $blankedHeading = $titleMsg->isBlank();
170 if ( !$titleMsg->isDisabled() ) {
171 $htmlTitle = $titleMsg->parse();
172 } else {
173 $htmlTitle = $out->getPageTitle();
174 }
175 } else {
176 $htmlTitle = $out->getPageTitle();
177 }
178
179 $data = [
180 // raw HTML
181 'html-title-heading' => Html::rawElement(
182 'h1',
183 [
184 'id' => 'firstHeading',
185 'class' => 'firstHeading mw-first-heading',
186 'style' => $blankedHeading ? 'display: none' : null
187 ] + $this->getUserLanguageAttributes(),
188 $htmlTitle
189 ),
190 'html-title' => $htmlTitle ?: null,
191 // Boolean values
192 'is-title-blank' => $blankedHeading, // @since 1.38
193 'is-anon' => $user->isAnon(),
194 'is-article' => $out->isArticle(),
195 'is-mainpage' => $isMainPage,
196 'is-specialpage' => $title->isSpecialPage(),
197 'canonical-url' => $this->getCanonicalUrl(),
198 ];
199
200 $components = $this->componentRegistry->getComponents();
201 foreach ( $components as $componentName => $component ) {
202 $data['data-' . $componentName] = $component->getTemplateData();
203 }
204 return $data;
205 }
206
216 public static function normalizeKey( string $key ) {
217 $config = MediaWikiServices::getInstance()->getMainConfig();
218 $defaultSkin = $config->get( MainConfigNames::DefaultSkin );
219 $fallbackSkin = $config->get( MainConfigNames::FallbackSkin );
220 $skinFactory = MediaWikiServices::getInstance()->getSkinFactory();
221 $skinNames = $skinFactory->getInstalledSkins();
222
223 // Make keys lowercase for case-insensitive matching.
224 $skinNames = array_change_key_case( $skinNames, CASE_LOWER );
225 $key = strtolower( $key );
226 $defaultSkin = strtolower( $defaultSkin );
227 $fallbackSkin = strtolower( $fallbackSkin );
228
229 if ( $key == '' || $key == 'default' ) {
230 // Don't return the default immediately;
231 // in a misconfiguration we need to fall back.
232 $key = $defaultSkin;
233 }
234
235 if ( isset( $skinNames[$key] ) ) {
236 return $key;
237 }
238
239 // Older versions of the software used a numeric setting
240 // in the user preferences.
241 $fallback = [
242 0 => $defaultSkin,
243 2 => 'cologneblue'
244 ];
245
246 if ( isset( $fallback[$key] ) ) {
247 // @phan-suppress-next-line PhanTypeMismatchDimFetch False positive
248 $key = $fallback[$key];
249 }
250
251 if ( isset( $skinNames[$key] ) ) {
252 return $key;
253 } elseif ( isset( $skinNames[$defaultSkin] ) ) {
254 return $defaultSkin;
255 } else {
256 return $fallbackSkin;
257 }
258 }
259
333 public function __construct( $options = null ) {
334 if ( is_string( $options ) ) {
335 $this->skinname = $options;
336 } elseif ( $options ) {
337 $name = $options['name'] ?? null;
338
339 if ( !$name ) {
340 throw new SkinException( 'Skin name must be specified' );
341 }
342
343 // Defaults are set in Skin::getOptions()
344 $this->options = $options;
345 $this->skinname = $name;
346 }
347 $this->defaultLinkOptions = $this->getOptions()['link'];
348 $this->componentRegistry = new SkinComponentRegistry(
350 );
351 }
352
356 public function getSkinName() {
357 return $this->skinname;
358 }
359
369 public function isResponsive() {
370 $isSkinResponsiveCapable = $this->getOptions()['responsive'];
371 $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
372
373 return $isSkinResponsiveCapable &&
374 $userOptionsLookup->getBoolOption( $this->getUser(), 'skin-responsive' );
375 }
376
381 public function initPage( OutputPage $out ) {
382 $skinMetaTags = $this->getConfig()->get( MainConfigNames::SkinMetaTags );
383 $siteName = $this->getConfig()->get( MainConfigNames::Sitename );
384 $this->preloadExistence();
385
386 if ( $this->isResponsive() ) {
387 $out->addMeta(
388 'viewport',
389 'width=device-width, initial-scale=1.0, ' .
390 'user-scalable=yes, minimum-scale=0.25, maximum-scale=5.0'
391 );
392 } else {
393 // Force the desktop experience on an iPad by resizing the mobile viewport to
394 // the value of @min-width-breakpoint-desktop (1120px).
395 // This is as @min-width-breakpoint-desktop-wide usually tends to optimize
396 // for larger screens with max-widths and margins.
397 // The initial-scale SHOULD NOT be set here as defining it will impact zoom
398 // on mobile devices. To allow font-size adjustment in iOS devices (see T311795)
399 // we will define a zoom in JavaScript on certain devices (see resources/src/mediawiki.page.ready/ready.js)
400 $out->addMeta(
401 'viewport',
402 'width=1120'
403 );
404 }
405
406 $tags = [
407 'og:site_name' => $siteName,
408 'og:title' => $out->getHTMLTitle(),
409 'twitter:card' => 'summary_large_image',
410 'og:type' => 'website',
411 ];
412
413 // Support sharing on platforms such as Facebook and Twitter
414 foreach ( $tags as $key => $value ) {
415 if ( in_array( $key, $skinMetaTags ) ) {
416 $out->addMeta( $key, $value );
417 }
418 }
419 }
420
432 public function getDefaultModules() {
433 $out = $this->getOutput();
434
435 $options = $this->getOptions();
436 // Modules declared in the $modules literal are loaded
437 // for ALL users, on ALL pages, in ALL skins.
438 // Keep this list as small as possible!
439 $modules = [
440 // The 'styles' key sets render-blocking style modules
441 // Unlike other keys in $modules, this is an associative array
442 // where each key is its own group pointing to a list of modules
443 'styles' => [
444 'skin' => $options['styles'],
445 'core' => [],
446 'content' => [],
447 'syndicate' => [],
448 'user' => []
449 ],
450 'core' => [
451 'site',
452 'mediawiki.page.ready',
453 ],
454 // modules that enhance the content in some way
455 'content' => [],
456 // modules relating to search functionality
457 'search' => [],
458 // Skins can register their own scripts
459 'skin' => $options['scripts'],
460 // modules relating to functionality relating to watching an article
461 'watch' => [],
462 // modules which relate to the current users preferences
463 'user' => [],
464 // modules relating to RSS/Atom Feeds
465 'syndicate' => [],
466 ];
467
468 $bodyHtml = $out->getHTML();
469 // Preload jquery.tablesorter for mediawiki.page.ready
470 if ( str_contains( $bodyHtml, 'sortable' ) ) {
471 $modules['content'][] = 'jquery.tablesorter';
472 $modules['styles']['content'][] = 'jquery.tablesorter.styles';
473 }
474
475 // Preload jquery.makeCollapsible for mediawiki.page.ready
476 if ( str_contains( $bodyHtml, 'mw-collapsible' ) ) {
477 $modules['content'][] = 'jquery.makeCollapsible';
478 $modules['styles']['content'][] = 'jquery.makeCollapsible.styles';
479 }
480
481 // Load relevant styles on wiki pages that use mw-ui-button.
482 // Since 1.26, this no longer loads unconditionally. Special pages
483 // and extensions should load this via addModuleStyles() instead.
484 if ( str_contains( $bodyHtml, 'mw-ui-button' ) ) {
485 $modules['styles']['content'][] = 'mediawiki.ui.button';
486 }
487 // Since 1.41, styling for mw-message-box is only required for
488 // messages that appear in article content.
489 // This should only be removed when a suitable alternative exists
490 // e.g. https://phabricator.wikimedia.org/T363607 is resolved.
491 if ( str_contains( $bodyHtml, 'mw-message-box' ) ) {
492 $modules['styles']['content'][] = 'mediawiki.legacy.messageBox';
493 }
494 // Since 1.46, links to temporary accounts in page content are expected to be styled.
495 if ( str_contains( $bodyHtml, 'mw-tempuserlink' ) ) {
496 $modules['styles']['content'][] = 'mediawiki.interface.helpers.styles';
497 $modules['styles']['content'][] = 'mediawiki.interface.helpers.linker.styles';
498 }
499
500 $title = $this->getTitle();
501 $namespace = $title ? $title->getNamespace() : 0;
502 // If the page is using Codex message box markup load Codex styles.
503 // Since 1.41. Skins can unset this if they prefer to handle this via other
504 // means.
505 // For content, this should not be considered stable, and will likely
506 // be removed when https://phabricator.wikimedia.org/T363607 is resolved.
507 $containsUserGeneratedContent = str_contains( $bodyHtml, 'mw-parser-output' );
508 $containsCodexMessageBox = str_contains( $bodyHtml, 'cdx-message' );
509 if ( $containsCodexMessageBox && $containsUserGeneratedContent && $namespace !== NS_SPECIAL ) {
510 $modules['styles']['content'][] = 'mediawiki.codex.messagebox.styles';
511 }
512
513 if ( $out->isTOCEnabled() ) {
514 $modules['content'][] = 'mediawiki.toc';
515 }
516
517 $authority = $this->getAuthority();
518 $relevantTitle = $this->getRelevantTitle();
519 if ( $authority->isRegistered()
520 && $authority->isAllowedAll( 'viewmywatchlist', 'editmywatchlist' )
521 && $relevantTitle && $relevantTitle->canExist()
522 ) {
523 $modules['watch'][] = 'mediawiki.page.watch.ajax';
524 }
525
526 $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
527 $userIdentity = $authority->getUser();
528 if ( $userOptionsLookup->getBoolOption( $userIdentity, 'editsectiononrightclick' )
529 || ( $out->isArticle() && $userOptionsLookup->getOption( $userIdentity, 'editondblclick' ) )
530 ) {
531 $modules['user'][] = 'mediawiki.misc-authed-pref';
532 }
533
534 if ( $out->isSyndicated() ) {
535 $modules['styles']['syndicate'][] = 'mediawiki.feedlink';
536 }
537
538 if ( $authority->isTemp() ) {
539 $modules['user'][] = 'mediawiki.tempUserBanner';
540 $modules['styles']['user'][] = 'mediawiki.tempUserBanner.styles';
541 }
542
543 if ( $namespace === NS_FILE ) {
544 $modules['styles']['core'][] = 'filepage'; // local Filepage.css, T31277, T356505
545 }
546
547 return $modules;
548 }
549
553 private function preloadExistence() {
554 $titles = [];
555
556 // User/talk link
557 $user = $this->getUser();
558 if ( $user->isRegistered() ) {
559 $titles[] = $user->getUserPage();
560 $titles[] = $user->getTalkPage();
561 }
562
563 // Check, if the page can hold some kind of content, otherwise do nothing
564 $title = $this->getRelevantTitle();
565 if ( $title && $title->canExist() && $title->canHaveTalkPage() ) {
566 $namespaceInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
567 if ( $title->isTalkPage() ) {
568 $titles[] = $namespaceInfo->getSubjectPage( $title );
569 } else {
570 $titles[] = $namespaceInfo->getTalkPage( $title );
571 }
572 }
573
574 // Preload for self::getCategoryLinks
575 $allCats = $this->getOutput()->getCategoryLinks();
576 if ( isset( $allCats['normal'] ) && $allCats['normal'] !== [] ) {
577 $catLink = Title::newFromText( $this->msg( 'pagecategorieslink' )->inContentLanguage()->text() );
578 if ( $catLink ) {
579 // If this is a special page, the LinkBatch would skip it
580 $titles[] = $catLink;
581 }
582 }
583
584 $this->getHookRunner()->onSkinPreloadExistence( $titles, $this );
585
586 if ( $titles ) {
587 $linkBatchFactory = MediaWikiServices::getInstance()->getLinkBatchFactory();
588 $linkBatchFactory->newLinkBatch( $titles )
589 ->setCaller( __METHOD__ )
590 ->execute();
591 }
592 }
593
598 public function setRelevantTitle( $t ) {
599 $this->mRelevantTitle = $t;
600 }
601
613 public function getRelevantTitle() {
614 return $this->mRelevantTitle ?? $this->getTitle();
615 }
616
621 public function setRelevantUser( ?UserIdentity $u ) {
622 $this->mRelevantUser = $u;
623 }
624
634 public function getRelevantUser(): ?UserIdentity {
635 if ( $this->mRelevantUser === false ) {
636 $this->mRelevantUser = null; // false indicates we never attempted to load it.
637 $title = $this->getRelevantTitle();
638 if ( $title->hasSubjectNamespace( NS_USER ) ) {
639 $services = MediaWikiServices::getInstance();
640 $rootUser = $title->getRootText();
641 $userNameUtils = $services->getUserNameUtils();
642 if ( $userNameUtils->isIP( $rootUser ) ) {
643 $this->mRelevantUser = UserIdentityValue::newAnonymous( $rootUser );
644 } else {
645 $user = $services->getUserIdentityLookup()->getUserIdentityByName( $rootUser );
646 $this->mRelevantUser = $user && $user->isRegistered() ? $user : null;
647 }
648 }
649 }
650
651 // The relevant user should only be set if it exists. However, if it exists but is hidden,
652 // and the viewer cannot see hidden users, this exposes the fact that the user exists;
653 // pretend like the user does not exist in such cases, by setting it to null. T120883
654 if ( $this->mRelevantUser && $this->mRelevantUser->isRegistered() ) {
655 $userBlock = MediaWikiServices::getInstance()
656 ->getBlockManager()
657 ->getBlock( $this->mRelevantUser, null );
658 if ( $userBlock && $userBlock->getHideName() &&
659 !$this->getAuthority()->isAllowed( 'hideuser' )
660 ) {
661 $this->mRelevantUser = null;
662 }
663 }
664
665 return $this->mRelevantUser;
666 }
667
672 final public function outputPageFinal( OutputPage $out ) {
673 // generate body
674 ob_start();
675 $this->outputPage();
676 $html = ob_get_contents();
677 ob_end_clean();
678
679 // T259955: OutputPage::headElement must be called last
680 // as it calls OutputPage::getRlClient, which freezes the ResourceLoader
681 // modules queue for the current page load.
682 // Since Skins can add ResourceLoader modules via OutputPage::addModule
683 // and OutputPage::addModuleStyles changing this order can lead to
684 // bugs.
685 $head = $out->headElement( $this );
686 $tail = $out->tailElement( $this );
687
688 echo $head . $html . $tail;
689 }
690
694 abstract public function outputPage();
695
701 public function getPageClasses( $title ) {
702 $services = MediaWikiServices::getInstance();
703 $ns = $title->getNamespace();
704 $numeric = 'ns-' . $ns;
705
706 if ( $title->isSpecialPage() ) {
707 $type = 'ns-special';
708 // T25315: provide a class based on the canonical special page name without subpages
709 [ $canonicalName ] = $services->getSpecialPageFactory()->resolveAlias( $title->getDBkey() );
710 if ( $canonicalName ) {
711 $type .= ' ' . Sanitizer::escapeClass( "mw-special-$canonicalName" );
712 } else {
713 $type .= ' mw-invalidspecialpage';
714 }
715 } else {
716 if ( $title->isTalkPage() ) {
717 $type = 'ns-talk';
718 } else {
719 $type = 'ns-subject';
720 }
721 // T208315: add HTML class when the user can edit the page
722 if ( $this->getAuthority()->probablyCan( 'edit', $title ) ) {
723 $type .= ' mw-editable';
724 }
725 }
726
727 $titleFormatter = $services->getTitleFormatter();
728 $name = Sanitizer::escapeClass( 'page-' . $titleFormatter->getPrefixedText( $title ) );
729 $root = Sanitizer::escapeClass( 'rootpage-' . $titleFormatter->formatTitle( $ns, $title->getRootText() ) );
730 // Add a static class that is not subject to translation to allow extensions/skins/global code to target main
731 // pages reliably (T363281)
732 if ( $title->isMainPage() ) {
733 $name .= ' page-Main_Page';
734 }
735
736 return "$numeric $type $name $root";
737 }
738
743 public function getHtmlElementAttributes() {
744 $lang = $this->getLanguage();
745 return [
746 'lang' => $lang->getHtmlCode(),
747 'dir' => $lang->getDir(),
748 'class' => 'client-nojs',
749 ];
750 }
751
755 public function getCategoryLinks() {
756 $out = $this->getOutput();
757 $allCats = $out->getCategoryLinks();
758 $title = $this->getTitle();
759 $services = MediaWikiServices::getInstance();
760 $linkRenderer = $services->getLinkRenderer();
761
762 if ( $allCats === [] ) {
763 return '';
764 }
765
766 $embed = "<li>";
767 $pop = "</li>";
768
769 $s = '';
770 $colon = $this->msg( 'colon-separator' )->escaped();
771
772 if ( !empty( $allCats['normal'] ) ) {
773 $t = $embed . implode( $pop . $embed, $allCats['normal'] ) . $pop;
774
775 $msg = $this->msg( 'pagecategories' )->numParams( count( $allCats['normal'] ) );
776 $linkPage = $this->msg( 'pagecategorieslink' )->inContentLanguage()->text();
777 $pageCategoriesLinkTitle = Title::newFromText( $linkPage );
778 if ( $pageCategoriesLinkTitle ) {
779 $link = $linkRenderer->makeLink( $pageCategoriesLinkTitle, $msg->text() );
780 } else {
781 $link = $msg->escaped();
782 }
783 $s .= Html::rawElement(
784 'div',
785 [ 'id' => 'mw-normal-catlinks', 'class' => 'mw-normal-catlinks' ],
786 $link . $colon . Html::rawElement( 'ul', [], $t )
787 );
788 }
789
790 # Hidden categories
791 if ( isset( $allCats['hidden'] ) ) {
792 $userOptionsLookup = $services->getUserOptionsLookup();
793
794 if ( $userOptionsLookup->getBoolOption( $this->getUser(), 'showhiddencats' ) ) {
795 $class = ' mw-hidden-cats-user-shown';
796 } elseif ( $title->inNamespace( NS_CATEGORY ) ) {
797 $class = ' mw-hidden-cats-ns-shown';
798 } else {
799 $class = ' mw-hidden-cats-hidden';
800 }
801
802 $s .= Html::rawElement(
803 'div',
804 [ 'id' => 'mw-hidden-catlinks', 'class' => "mw-hidden-catlinks$class" ],
805 $this->msg( 'hidden-categories' )->numParams( count( $allCats['hidden'] ) )->escaped() .
806 $colon .
807 Html::rawElement(
808 'ul',
809 [],
810 $embed . implode( $pop . $embed, $allCats['hidden'] ) . $pop
811 )
812 );
813 }
814
815 return $s;
816 }
817
821 public function getCategories() {
822 $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
823 $showHiddenCats = $userOptionsLookup->getBoolOption( $this->getUser(), 'showhiddencats' );
824
825 $catlinks = $this->getCategoryLinks();
826 // Check what we're showing
827 $allCats = $this->getOutput()->getCategoryLinks();
828 $showHidden = $showHiddenCats || $this->getTitle()->inNamespace( NS_CATEGORY );
829
830 $classes = [ 'catlinks' ];
831 if ( empty( $allCats['normal'] ) && !( !empty( $allCats['hidden'] ) && $showHidden ) ) {
832 $classes[] = 'catlinks-allhidden';
833 }
834
835 return Html::rawElement(
836 'div',
837 [ 'id' => 'catlinks', 'class' => $classes, 'data-mw' => 'interface' ],
838 $catlinks
839 );
840 }
841
856 protected function afterContentHook() {
857 $data = '';
858
859 if ( $this->getHookRunner()->onSkinAfterContent( $data, $this ) ) {
860 // adding just some spaces shouldn't toggle the output
861 // of the whole <div/>, so we use trim() here
862 if ( trim( $data ) != '' ) {
863 // Doing this here instead of in the skins to
864 // ensure that the div has the same ID in all
865 // skins
866 $data = "<div id='mw-data-after-content'>\n" .
867 "\t$data\n" .
868 "</div>\n";
869 }
870 } else {
871 wfDebug( "Hook SkinAfterContent changed output processing." );
872 }
873
874 return $data;
875 }
876
882 private function getCanonicalUrl() {
883 $title = $this->getTitle();
884 $oldid = $this->getOutput()->getRevisionId();
885 if ( $oldid ) {
886 return $title->getCanonicalURL( 'oldid=' . $oldid );
887 } else {
888 // oldid not available for non existing pages
889 return $title->getCanonicalURL();
890 }
891 }
892
900 public function printSource() {
901 $urlUtils = MediaWikiServices::getInstance()->getUrlUtils();
902 $url = htmlspecialchars( $urlUtils->expandIRI( $this->getCanonicalUrl() ) ?? '' );
903
904 return $this->msg( 'retrievedfrom' )
905 ->rawParams( '<a dir="ltr" href="' . $url . '">' . $url . '</a>' )
906 ->parse();
907 }
908
912 public function getUndeleteLink() {
913 $action = $this->getRequest()->getRawVal( 'action' ) ?? 'view';
914 $title = $this->getTitle();
915 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
916
917 if ( ( !$title->exists() || $action == 'history' ) &&
918 $this->getAuthority()->probablyCan( 'deletedhistory', $title )
919 ) {
920 $n = $title->getDeletedEditsCount();
921
922 if ( $n ) {
923 if ( $this->getAuthority()->probablyCan( 'undelete', $title ) ) {
924 $msg = 'thisisdeleted';
925 } else {
926 $msg = 'viewdeleted';
927 }
928
929 $subtitle = $this->msg( $msg )->rawParams(
930 $linkRenderer->makeKnownLink(
931 SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedDBkey() ),
932 $this->msg( 'restorelink' )->numParams( $n )->text() )
933 )->escaped();
934
935 $links = [];
936 // Add link to page logs, unless we're on the history page (which
937 // already has one)
938 if ( $action !== 'history' ) {
939 $links[] = $linkRenderer->makeKnownLink(
940 SpecialPage::getTitleFor( 'Log' ),
941 $this->msg( 'viewpagelogs-lowercase' )->text(),
942 [],
943 [ 'page' => $title->getPrefixedText() ]
944 );
945 }
946
947 // Allow extensions to add more links
948 $this->getHookRunner()->onUndeletePageToolLinks(
949 $this->getContext(), $linkRenderer, $links );
950
951 if ( $links ) {
952 $subtitle .= ''
953 . $this->msg( 'word-separator' )->escaped()
954 . $this->msg( 'parentheses' )
955 ->rawParams( $this->getLanguage()->pipeList( $links ) )
956 ->escaped();
957 }
958
959 return Html::rawElement( 'div', [ 'class' => 'mw-undelete-subtitle' ], $subtitle );
960 }
961 }
962
963 return '';
964 }
965
969 private function subPageSubtitleInternal() {
970 $services = MediaWikiServices::getInstance();
971 $linkRenderer = $services->getLinkRenderer();
972 $out = $this->getOutput();
973 $title = $out->getTitle();
974 $subpages = '';
975
976 if ( !$this->getHookRunner()->onSkinSubPageSubtitle( $subpages, $this, $out ) ) {
977 return $subpages;
978 }
979
980 $hasSubpages = $services->getNamespaceInfo()->hasSubpages( $title->getNamespace() );
981 if ( !$out->isArticle() || !$hasSubpages ) {
982 return $subpages;
983 }
984
985 $ptext = $title->getPrefixedText();
986 if ( str_contains( $ptext, '/' ) ) {
987 $links = explode( '/', $ptext );
988 array_pop( $links );
989 $count = 0;
990 $growingLink = '';
991 $display = '';
992 $lang = $this->getLanguage();
993
994 foreach ( $links as $link ) {
995 $growingLink .= $link;
996 $display .= $link;
997 $linkObj = Title::newFromText( $growingLink );
998
999 if ( $linkObj && $linkObj->isKnown() ) {
1000 $getlink = $linkRenderer->makeKnownLink( $linkObj, $display );
1001
1002 $count++;
1003
1004 if ( $count > 1 ) {
1005 $subpages .= $this->msg( 'pipe-separator' )->escaped();
1006 } else {
1007 $subpages .= '&lt; ';
1008 }
1009
1010 $subpages .= Html::rawElement( 'bdi', [ 'dir' => $lang->getDir() ], $getlink );
1011 $display = '';
1012 } else {
1013 $display .= '/';
1014 }
1015 $growingLink .= '/';
1016 }
1017 }
1018
1019 return $subpages;
1020 }
1021
1029 private function getFooterTemplateDataItem( string $dataKey, string $name ) {
1030 $footerData = $this->getComponent( 'footer' )->getTemplateData();
1031 $items = $footerData[ $dataKey ]['array-items'] ?? [];
1032 foreach ( $items as $item ) {
1033 if ( $item['name'] === $name ) {
1034 return $item['html'];
1035 }
1036 }
1037 return '';
1038 }
1039
1040 final public function getCopyright(): string {
1041 return $this->getFooterTemplateDataItem( 'data-info', 'copyright' );
1042 }
1043
1048 public function logoText( $align = '' ) {
1049 if ( $align != '' ) {
1050 $a = " style='float: {$align};'";
1051 } else {
1052 $a = '';
1053 }
1054
1055 $mp = $this->msg( 'mainpage' )->escaped();
1056 $url = htmlspecialchars( Title::newMainPage()->getLocalURL() );
1057
1058 $logourl = RL\SkinModule::getAvailableLogos(
1059 $this->getConfig(),
1060 $this->getLanguage()->getCode()
1061 )[ '1x' ];
1062 return "<a href='{$url}'><img{$a} src='{$logourl}' alt='[{$mp}]' /></a>";
1063 }
1064
1074 final public function getFooterIcons() {
1075 return SkinComponentFooter::getFooterIconsData(
1076 $this->getConfig()
1077 );
1078 }
1079
1091 final public function makeFooterIcon( $icon, $withImage = 'withImage' ) {
1092 return SkinComponentFooter::makeFooterIconHTML(
1093 $this->getConfig(), $icon, $withImage
1094 );
1095 }
1096
1104 public function editUrlOptions() {
1105 $options = [ 'action' => 'edit' ];
1106 $out = $this->getOutput();
1107
1108 if ( !$out->isRevisionCurrent() ) {
1109 $options['oldid'] = intval( $out->getRevisionId() );
1110 }
1111
1112 return $options;
1113 }
1114
1119 public function showEmailUser( $id ) {
1120 if ( $id instanceof UserIdentity ) {
1121 $targetUser = User::newFromIdentity( $id );
1122 } else {
1123 $targetUser = User::newFromId( $id );
1124 }
1125
1126 # The sending user must have a confirmed email address and the receiving
1127 # user must accept emails from the sender.
1128 $emailUser = MediaWikiServices::getInstance()->getEmailUserFactory()
1129 ->newEmailUser( $this->getUser() );
1130
1131 return $emailUser->canSend()->isOK()
1132 && $emailUser->validateTarget( $targetUser )->isOK();
1133 }
1134
1135 /* these are used extensively in SkinTemplate, but also some other places */
1136
1141 public static function makeMainPageUrl( $urlaction = '' ) {
1142 $title = Title::newMainPage();
1143
1144 return $title->getLinkURL( $urlaction );
1145 }
1146
1153 public static function makeInternalOrExternalUrl( $name ) {
1154 $protocols = MediaWikiServices::getInstance()->getUrlUtils()->validProtocols();
1155
1156 if ( preg_match( '/^(?i:' . $protocols . ')/', $name ) ) {
1157 return $name;
1158 } else {
1159 $title = $name instanceof Title ? $name : Title::newFromText( $name );
1160 return $title ? $title->getLinkURL() : '';
1161 }
1162 }
1163
1170 protected static function makeUrlDetails( $name, $urlaction = '' ) {
1171 $title = $name instanceof Title ? $name : Title::newFromText( $name );
1172 return [
1173 'href' => $title ? $title->getLocalURL( $urlaction ) : '',
1174 'exists' => $title && $title->isKnown(),
1175 ];
1176 }
1177
1184 protected static function makeKnownUrlDetails( $name, $urlaction = '' ) {
1185 $title = $name instanceof Title ? $name : Title::newFromText( $name );
1186 return [
1187 'href' => $title ? $title->getLocalURL( $urlaction ) : '',
1188 'exists' => (bool)$title,
1189 ];
1190 }
1191
1200 public function mapInterwikiToLanguage( $code ) {
1201 $map = $this->getConfig()->get( MainConfigNames::InterlanguageLinkCodeMap );
1202 return $map[ $code ] ?? $code;
1203 }
1204
1213 public function getLanguages() {
1214 if ( $this->getConfig()->get( MainConfigNames::HideInterlanguageLinks ) ) {
1215 return [];
1216 }
1217 if ( $this->languageLinks === null ) {
1218 $hookRunner = $this->getHookRunner();
1219
1220 $userLang = $this->getLanguage();
1221 $languageLinks = [];
1222 $langNameUtils = MediaWikiServices::getInstance()->getLanguageNameUtils();
1223
1224 foreach ( $this->getOutput()->getLanguageLinks() as $languageLinkText ) {
1225 [ $prefix, $title ] = explode( ':', $languageLinkText, 2 );
1226 $class = 'interlanguage-link interwiki-' . $prefix;
1227
1228 [ $title, $frag ] = array_pad( explode( '#', $title, 2 ), 2, '' );
1229 $languageLinkTitle = TitleValue::tryNew( NS_MAIN, $title, $frag, $prefix );
1230 if ( $languageLinkTitle === null ) {
1231 continue;
1232 }
1233 $ilInterwikiCode = $this->mapInterwikiToLanguage( $prefix );
1234
1235 $ilLangName = $langNameUtils->getLanguageName( $ilInterwikiCode );
1236
1237 if ( strval( $ilLangName ) === '' ) {
1238 $ilDisplayTextMsg = $this->msg( "interlanguage-link-$ilInterwikiCode" );
1239 if ( !$ilDisplayTextMsg->isDisabled() ) {
1240 // Use custom MW message for the display text
1241 $ilLangName = $ilDisplayTextMsg->text();
1242 } else {
1243 // Last resort: fallback to the language link target
1244 $ilLangName = $languageLinkText;
1245 }
1246 } else {
1247 // Use the language autonym as display text
1248 $ilLangName = $this->getLanguage()->ucfirst( $ilLangName );
1249 }
1250
1251 // CLDR extension or similar is required to localize the language name;
1252 // otherwise we'll end up with the autonym again.
1253 $ilLangLocalName =
1254 $langNameUtils->getLanguageName( $ilInterwikiCode, $userLang->getCode() );
1255
1256 $languageLinkTitleText = $languageLinkTitle->getText();
1257 if ( $ilLangLocalName === '' ) {
1258 $ilFriendlySiteName =
1259 $this->msg( "interlanguage-link-sitename-$ilInterwikiCode" );
1260 if ( !$ilFriendlySiteName->isDisabled() ) {
1261 if ( $languageLinkTitleText === '' ) {
1262 $ilTitle =
1263 $this->msg( 'interlanguage-link-title-nonlangonly',
1264 $ilFriendlySiteName->text() )->text();
1265 } else {
1266 $ilTitle =
1267 $this->msg( 'interlanguage-link-title-nonlang',
1268 $languageLinkTitleText, $ilFriendlySiteName->text() )->text();
1269 }
1270 } else {
1271 // we have nothing friendly to put in the title, so fall back to
1272 // displaying the interlanguage link itself in the title text
1273 // (similar to what is done in page content)
1274 $ilTitle = $languageLinkTitle->getInterwiki() . ":$languageLinkTitleText";
1275 }
1276 } elseif ( $languageLinkTitleText === '' ) {
1277 $ilTitle =
1278 $this->msg( 'interlanguage-link-title-langonly', $ilLangLocalName )->text();
1279 } else {
1280 $ilTitle =
1281 $this->msg( 'interlanguage-link-title', $languageLinkTitleText,
1282 $ilLangLocalName )->text();
1283 }
1284
1285 $ilInterwikiCodeBCP47 = LanguageCode::bcp47( $ilInterwikiCode );
1286 // A TitleValue is sufficient above this point, but we need
1287 // a full Title for ::getFullURL() and the hook invocation
1288 $languageLinkFullTitle = Title::newFromLinkTarget( $languageLinkTitle );
1289 $languageLink = [
1290 'href' => $languageLinkFullTitle->getFullURL(),
1291 'text' => $ilLangName,
1292 'title' => $ilTitle,
1293 'class' => $class,
1294 'link-class' => 'interlanguage-link-target',
1295 'lang' => $ilInterwikiCodeBCP47,
1296 'hreflang' => $ilInterwikiCodeBCP47,
1297 'data-title' => $languageLinkTitleText,
1298 'data-language-autonym' => $ilLangName,
1299 'data-language-local-name' => $ilLangLocalName,
1300 ];
1301 $hookRunner->onSkinTemplateGetLanguageLink(
1302 $languageLink, $languageLinkFullTitle, $this->getTitle(), $this->getOutput()
1303 );
1304 $languageLinks[] = $languageLink;
1305 }
1306 $this->languageLinks = $languageLinks;
1307 }
1308
1309 return $this->languageLinks;
1310 }
1311
1318 protected function buildNavUrls() {
1319 $services = MediaWikiServices::getInstance();
1320 $out = $this->getOutput();
1321 $title = $this->getTitle();
1322 $thispage = $title->getPrefixedDBkey();
1323 $uploadNavigationUrl = $this->getConfig()->get( MainConfigNames::UploadNavigationUrl );
1324
1325 $nav_urls = [];
1326 $nav_urls['mainpage'] = [ 'href' => self::makeMainPageUrl() ];
1327 if ( $uploadNavigationUrl ) {
1328 $nav_urls['upload'] = [ 'href' => $uploadNavigationUrl ];
1329 } elseif ( UploadBase::isEnabled() && UploadBase::isAllowed( $this->getAuthority() ) === true ) {
1330 $nav_urls['upload'] = [ 'href' => SkinComponentUtils::makeSpecialUrl( 'Upload' ) ];
1331 } else {
1332 $nav_urls['upload'] = false;
1333 }
1334
1335 $nav_urls['print'] = false;
1336 $nav_urls['permalink'] = false;
1337 $nav_urls['info'] = false;
1338 $nav_urls['whatlinkshere'] = false;
1339 $nav_urls['recentchangeslinked'] = false;
1340 $nav_urls['contributions'] = false;
1341 $nav_urls['log'] = false;
1342 $nav_urls['blockip'] = false;
1343 $nav_urls['changeblockip'] = false;
1344 $nav_urls['unblockip'] = false;
1345 $nav_urls['mute'] = false;
1346 $nav_urls['emailuser'] = false;
1347 $nav_urls['userrights'] = false;
1348
1349 // A print stylesheet is attached to all pages, but nobody ever
1350 // figures that out. :) Add a link...
1351 if ( !$out->isPrintable() && ( $out->isArticle() || $title->isSpecialPage() ) ) {
1352 $nav_urls['print'] = [
1353 'text' => $this->msg( 'printableversion' )->text(),
1354 'href' => 'javascript:print();'
1355 ];
1356 }
1357
1358 if ( $out->isArticle() ) {
1359 // Also add a "permalink" while we're at it
1360 $revid = $out->getRevisionId();
1361 if ( $revid ) {
1362 $nav_urls['permalink'] = [
1363 'icon' => 'link',
1364 'text' => $this->msg( 'permalink' )->text(),
1365 'href' => $title->getLocalURL( "oldid=$revid" )
1366 ];
1367 }
1368 }
1369
1370 if ( $out->isArticleRelated() ) {
1371 $nav_urls['whatlinkshere'] = [
1372 'href' => SpecialPage::getTitleFor( 'Whatlinkshere', $thispage )->getLocalURL()
1373 ];
1374
1375 $nav_urls['info'] = [
1376 'icon' => 'infoFilled',
1377 'text' => $this->msg( 'pageinfo-toolboxlink' )->text(),
1378 'href' => $title->getLocalURL( "action=info" )
1379 ];
1380
1381 if ( $title->exists() || $title->inNamespace( NS_CATEGORY ) ) {
1382 $nav_urls['recentchangeslinked'] = [
1383 'href' => SpecialPage::getTitleFor( 'Recentchangeslinked', $thispage )->getLocalURL()
1384 ];
1385 }
1386 }
1387
1388 $user = $this->getRelevantUser();
1389 $target = false;
1390 $targetIsIpRange = false;
1391 if ( $user ) {
1392 // This will either be an account or an IP
1393 $target = $user->getName();
1394 } else {
1395 // Support finding the IP range if its the target
1396 $pageTarget = $this->getPageTarget();
1397 if ( $pageTarget ) {
1398 $CIDRLimit = $this->getConfig()
1399 ->get( MainConfigNames::BlockCIDRLimit );
1400 [ $ip, $range ] = explode( '/', $pageTarget, 2 );
1401 if (
1402 ( IPUtils::isIPv4( $ip ) && $range >= $CIDRLimit['IPv4'] ) ||
1403 ( IPUtils::isIPv6( $ip ) && $range >= $CIDRLimit['IPv6'] )
1404 ) {
1405 $target = IPUtils::sanitizeRange( $pageTarget );
1406 $targetIsIpRange = true;
1407 }
1408 }
1409 }
1410 if ( !$target ) {
1411 return $nav_urls;
1412 }
1413
1414 $nav_urls['contributions'] = [
1415 'text' => $this->msg( 'tool-link-contributions', $target )->text(),
1416 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Contributions', $target ),
1417 'tooltip-params' => [ $target ],
1418 ];
1419 $nav_urls['log'] = [
1420 'icon' => 'listBullet',
1421 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Log', $target )
1422 ];
1423
1424 // Check if the user/ip/ip range is blocked
1425 if ( $this->getAuthority()->isAllowed( 'block' ) ) {
1426 $userBlock = null;
1427 if ( $targetIsIpRange ) {
1428 // getBlock doesn't support ip range lookups so check independently if the target is a range
1429 $userBlock = $services
1430 ->getBlockManager()
1431 ->getIpRangeBlock( $target );
1432 } elseif ( $user ) {
1433 // Check if the user or IP is already blocked
1434 $userBlock = $services
1435 ->getBlockManager()
1436 ->getBlock( $user, null );
1437 }
1438
1439 if ( $userBlock ) {
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->getConfig()->get( MainConfigNames::EnableSpecialMute ) &&
1476 $this->getUser()->isNamed()
1477 ) {
1478 $nav_urls['mute'] = [
1479 'text' => $this->msg( 'mute-preferences' )->text(),
1480 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Mute', $target )
1481 ];
1482 }
1483
1484 // Don't show links to Special:UserRights for temporary accounts (as they cannot have groups)
1485 $userNameUtils = $services->getUserNameUtils();
1486 $userGroupsAssignmentService = $services->getUserGroupAssignmentService();
1487 if ( !$userNameUtils->isTemp( $user->getName() ) ) {
1488 $canChange = $userGroupsAssignmentService->userCanChangeRights(
1489 $this->getAuthority(),
1490 $user
1491 );
1492 $delimiter = $this->getConfig()->get(
1493 MainConfigNames::UserrightsInterwikiDelimiter );
1494 if ( str_contains( $target, $delimiter ) ) {
1495 // Username contains interwiki delimiter, link it via the
1496 // #{userid} syntax. (T260222)
1497 $linkArgs = [ false, [ 'user' => '#' . $user->getId() ] ];
1498 } else {
1499 $linkArgs = [ $target ];
1500 }
1501 $nav_urls['userrights'] = [
1502 'icon' => 'userGroup',
1503 'text' => $this->msg(
1504 $canChange ? 'tool-link-userrights' : 'tool-link-userrights-readonly',
1505 $target
1506 )->text(),
1507 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Userrights', ...$linkArgs )
1508 ];
1509 }
1510 }
1511 }
1512
1513 return $nav_urls;
1514 }
1515
1521 final protected function buildFeedUrls() {
1522 $feeds = [];
1523 $out = $this->getOutput();
1524 if ( $out->isSyndicated() ) {
1525 foreach ( $out->getSyndicationLinks() as $format => $link ) {
1526 $feeds[$format] = [
1527 // Messages: feed-atom, feed-rss
1528 'text' => $this->msg( "feed-$format" )->text(),
1529 'href' => $link
1530 ];
1531 }
1532 }
1533 return $feeds;
1534 }
1535
1561 public function buildSidebar() {
1562 if ( $this->sidebar === null ) {
1563 $services = MediaWikiServices::getInstance();
1564 $callback = function ( $old = null, &$ttl = null ) {
1565 $bar = [];
1566 $this->addToSidebar( $bar, 'sidebar' );
1567
1568 // This hook may vary its behaviour by skin.
1569 $this->getHookRunner()->onSkinBuildSidebar( $this, $bar );
1570 $msgCache = MediaWikiServices::getInstance()->getMessageCache();
1571 if ( $msgCache->isDisabled() ) {
1572 // Don't cache the fallback if DB query failed. T133069
1573 $ttl = WANObjectCache::TTL_UNCACHEABLE;
1574 }
1575
1576 return $bar;
1577 };
1578
1579 $msgCache = $services->getMessageCache();
1580 $wanCache = $services->getMainWANObjectCache();
1581 $config = $this->getConfig();
1582 $languageCode = $this->getLanguage()->getCode();
1583
1584 $sidebar = $config->get( MainConfigNames::EnableSidebarCache )
1585 ? $wanCache->getWithSetCallback(
1586 $wanCache->makeKey( 'sidebar', $languageCode, $this->getSkinName() ?? '' ),
1587 $config->get( MainConfigNames::SidebarCacheExpiry ),
1588 $callback,
1589 [
1590 'checkKeys' => [
1591 // Unless there is both no exact $code override nor an i18n definition
1592 // in the software, the only MediaWiki page to check is for $code.
1593 $msgCache->getCheckKey( $languageCode )
1594 ],
1595 'lockTSE' => 30
1596 ]
1597 )
1598 : $callback();
1599
1600 $sidebar['TOOLBOX'] = array_merge(
1601 $this->makeToolbox(
1602 $this->buildNavUrls(),
1603 $this->buildFeedUrls()
1604 ), $sidebar['TOOLBOX'] ?? []
1605 );
1606
1607 $sidebar['LANGUAGES'] = $this->getLanguages();
1608 // Apply post-processing to the cached value
1609 $this->getHookRunner()->onSidebarBeforeOutput( $this, $sidebar );
1610
1611 $this->sidebar = $sidebar;
1612 }
1613
1614 return $this->sidebar;
1615 }
1616
1626 public function addToSidebar( &$bar, $message ) {
1627 $this->addToSidebarPlain( $bar, $this->msg( $message )->inContentLanguage()->plain() );
1628 }
1629
1636 private function createSidebarItem( $target, $text ) {
1637 $config = $this->getConfig();
1638 $messageTitle = $config->get( MainConfigNames::EnableSidebarCache )
1639 ? Title::newMainPage() : $this->getTitle();
1640 $services = MediaWikiServices::getInstance();
1641 $urlUtils = $services->getUrlUtils();
1642
1643 $extraAttribs = [];
1644
1645 $msgLink = $this->msg( $target )->page( $messageTitle )->inContentLanguage();
1646 if ( $msgLink->exists() ) {
1647 $link = $msgLink->text();
1648 // Extra check in case a message does fancy stuff with {{#if:… and such
1649 if ( $link === '-' ) {
1650 return null;
1651 }
1652 } else {
1653 $link = $target;
1654 }
1655 $msgText = $this->msg( $text )->page( $messageTitle );
1656 if ( $msgText->exists() ) {
1657 $parsedText = $msgText->text();
1658 } else {
1659 $parsedText = $text;
1660 }
1661
1662 if ( preg_match( '/^(?i:' . $urlUtils->validProtocols() . ')/', $link ) ) {
1663 $href = $link;
1664
1665 // Parser::getExternalLinkAttribs won't work here because of the Namespace things
1666 if ( $config->get( MainConfigNames::NoFollowLinks ) &&
1667 !$urlUtils->matchesDomainList(
1668 (string)$href,
1669 (array)$config->get( MainConfigNames::NoFollowDomainExceptions )
1670 )
1671 ) {
1672 $extraAttribs['rel'] = 'nofollow';
1673 }
1674
1675 if ( $config->get( MainConfigNames::ExternalLinkTarget ) ) {
1676 $extraAttribs['target'] =
1677 $config->get( MainConfigNames::ExternalLinkTarget );
1678 }
1679 } else {
1680 $title = Title::newFromText( $link );
1681 $href = $title ? $title->fixSpecialName()->getLinkURL() : '';
1682 }
1683
1684 $id = strtr( $text, ' ', '-' );
1685 return $extraAttribs + [
1686 'text' => $parsedText,
1687 'href' => $href,
1688 'icon' => $this->getSidebarIcon( $id ),
1689 'id' => Sanitizer::escapeIdForAttribute( 'n-' . $id ),
1690 'active' => false,
1691 ];
1692 }
1693
1701 public function addToSidebarPlain( &$bar, $text ) {
1702 $lines = explode( "\n", $text );
1703
1704 $heading = '';
1705 $config = $this->getConfig();
1706 $messageTitle = $config->get( MainConfigNames::EnableSidebarCache )
1707 ? Title::newMainPage() : $this->getTitle();
1708 $services = MediaWikiServices::getInstance();
1709 $messageParser = $services->getMessageParser();
1710 $urlUtils = $services->getUrlUtils();
1711
1712 foreach ( $lines as $line ) {
1713 if ( !str_starts_with( $line, '*' ) ) {
1714 continue;
1715 }
1716 $line = rtrim( $line, "\r" ); // for Windows compat
1717
1718 if ( !str_starts_with( $line, '**' ) ) {
1719 $heading = trim( $line, '* ' );
1720 if ( !array_key_exists( $heading, $bar ) ) {
1721 $bar[$heading] = [];
1722 }
1723 } else {
1724 $line = trim( $line, '* ' );
1725
1726 if ( str_contains( $line, '|' ) ) {
1727 $line = $messageParser->transform( $line, false, null, $messageTitle );
1728 $line = array_map( 'trim', explode( '|', $line, 2 ) );
1729 if ( count( $line ) !== 2 ) {
1730 // Second check, could be hit by people doing
1731 // funky stuff with parserfuncs... (T35321)
1732 continue;
1733 }
1734
1735 $item = $this->createSidebarItem( $line[0], $line[1] );
1736 if ( $item !== null ) {
1737 $bar[$heading][] = $item;
1738 }
1739 }
1740 }
1741 }
1742
1743 return $bar;
1744 }
1745
1750 private function getSidebarIcon( string $id ) {
1751 switch ( $id ) {
1752 case 'mainpage-description':
1753 return 'home';
1754 case 'randompage':
1755 return 'die';
1756 case 'recentchanges':
1757 return 'recentChanges';
1758 // These menu items are commonly added in MediaWiki:Sidebar. We should
1759 // reconsider the location of this logic in future.
1760 case 'help':
1761 case 'help-mediawiki':
1762 return 'help';
1763 case 'specialpages':
1764 return 'specialPages';
1765 default:
1766 return null;
1767 }
1768 }
1769
1786 private function hideNewTalkMessagesForCurrentSession() {
1787 // Only show new talk page notification if there is a session,
1788 // (the client edited a page from this browser, or is logged-in).
1789 return !$this->getRequest()->getSession()->isPersistent();
1790 }
1791
1797 public function getNewtalks() {
1798 if ( $this->hideNewTalkMessagesForCurrentSession() ) {
1799 return '';
1800 }
1801
1802 $newMessagesAlert = '';
1803 $user = $this->getUser();
1804 $services = MediaWikiServices::getInstance();
1805 $linkRenderer = $services->getLinkRenderer();
1806 $userHasNewMessages = $services->getTalkPageNotificationManager()
1807 ->userHasNewMessages( $user );
1808 $timestamp = $services->getTalkPageNotificationManager()
1809 ->getLatestSeenMessageTimestamp( $user );
1810 $newtalks = !$userHasNewMessages ? [] : [
1811 [
1812 // TODO: Deprecate adding wiki and link to array and redesign GetNewMessagesAlert hook
1813 'wiki' => WikiMap::getCurrentWikiId(),
1814 'link' => $user->getTalkPage()->getLocalURL(),
1815 'rev' => $timestamp ? $services->getRevisionLookup()
1816 ->getRevisionByTimestamp( $user->getTalkPage(), $timestamp ) : null
1817 ]
1818 ];
1819 $out = $this->getOutput();
1820
1821 // Allow extensions to disable or modify the new messages alert
1822 if ( !$this->getHookRunner()->onGetNewMessagesAlert(
1823 $newMessagesAlert, $newtalks, $user, $out )
1824 ) {
1825 return '';
1826 }
1827 if ( $newMessagesAlert ) {
1828 return $newMessagesAlert;
1829 }
1830
1831 if ( $newtalks !== [] ) {
1832 $uTalkTitle = $user->getTalkPage();
1833 $lastSeenRev = $newtalks[0]['rev'];
1834 $numAuthors = 0;
1835 if ( $lastSeenRev !== null ) {
1836 $plural = true; // Default if we have a last seen revision: if unknown, use plural
1837 $revStore = $services->getRevisionStore();
1838 $latestRev = $revStore->getRevisionByTitle(
1839 $uTalkTitle,
1840 0,
1841 IDBAccessObject::READ_NORMAL
1842 );
1843 if ( $latestRev !== null ) {
1844 // Singular if only 1 unseen revision, plural if several unseen revisions.
1845 $plural = $latestRev->getParentId() !== $lastSeenRev->getId();
1846 $numAuthors = $revStore->countAuthorsBetween(
1847 $uTalkTitle->getArticleID(),
1848 $lastSeenRev,
1849 $latestRev,
1850 null,
1851 10,
1852 RevisionStore::INCLUDE_NEW
1853 );
1854 }
1855 } else {
1856 // Singular if no revision -> diff link will show latest change only in any case
1857 $plural = false;
1858 }
1859 $plural = $plural ? 999 : 1;
1860 // 999 signifies "more than one revision". We don't know how many, and even if we did,
1861 // the number of revisions or authors is not necessarily the same as the number of
1862 // "messages".
1863 $newMessagesLink = $linkRenderer->makeKnownLink(
1864 $uTalkTitle,
1865 $this->msg( 'new-messages-link-plural' )->params( $plural )->text(),
1866 [],
1867 $uTalkTitle->isRedirect() ? [ 'redirect' => 'no' ] : []
1868 );
1869
1870 $newMessagesDiffLink = $linkRenderer->makeKnownLink(
1871 $uTalkTitle,
1872 $this->msg( 'new-messages-diff-link-plural' )->params( $plural )->text(),
1873 [],
1874 $lastSeenRev !== null
1875 ? [ 'oldid' => $lastSeenRev->getId(), 'diff' => 'cur' ]
1876 : [ 'diff' => 'cur' ]
1877 );
1878
1879 if ( $numAuthors >= 1 && $numAuthors <= 10 ) {
1880 $newMessagesAlert = $this->msg(
1881 'new-messages-from-users'
1882 )->rawParams(
1883 $newMessagesLink,
1884 $newMessagesDiffLink
1885 )->numParams(
1886 $numAuthors,
1887 $plural
1888 );
1889 } else {
1890 // $numAuthors === 11 signifies "11 or more" ("more than 10")
1891 $newMessagesAlert = $this->msg(
1892 $numAuthors > 10 ? 'new-messages-from-many-users' : 'new-messages'
1893 )->rawParams(
1894 $newMessagesLink,
1895 $newMessagesDiffLink
1896 )->numParams( $plural );
1897 }
1898 $newMessagesAlert = $newMessagesAlert->parse();
1899 }
1900
1901 return $newMessagesAlert;
1902 }
1903
1911 private function getCachedNotice( $name ) {
1912 $config = $this->getConfig();
1913
1914 if ( $name === 'default' ) {
1915 // special case
1916 $notice = $config->get( MainConfigNames::SiteNotice );
1917 if ( !$notice ) {
1918 return false;
1919 }
1920 } else {
1921 $msg = $this->msg( $name )->inContentLanguage();
1922 if ( $msg->isBlank() ) {
1923 return '';
1924 } elseif ( $msg->isDisabled() ) {
1925 return false;
1926 }
1927 $notice = $msg->plain();
1928 }
1929
1930 $services = MediaWikiServices::getInstance();
1931 $cache = $services->getMainWANObjectCache();
1932 $parsed = $cache->getWithSetCallback(
1933 // Use the extra hash appender to let eg SSL variants separately cache
1934 // Key is verified with md5 hash of unparsed wikitext
1935 $cache->makeKey(
1936 $name, $config->get( MainConfigNames::RenderHashAppend ), md5( $notice ) ),
1937 // TTL in seconds
1938 600,
1939 function () use ( $notice ) {
1940 return $this->getOutput()->parseAsInterface( $notice );
1941 }
1942 );
1943
1944 $contLang = $services->getContentLanguage();
1945 return Html::rawElement(
1946 'div',
1947 [
1948 'class' => $name,
1949 'lang' => $contLang->getHtmlCode(),
1950 'dir' => $contLang->getDir()
1951 ],
1952 $parsed
1953 );
1954 }
1955
1959 public function getSiteNotice() {
1960 $siteNotice = '';
1961
1962 if ( $this->getHookRunner()->onSiteNoticeBefore( $siteNotice, $this ) ) {
1963 if ( $this->getUser()->isRegistered() ) {
1964 $siteNotice = $this->getCachedNotice( 'sitenotice' );
1965 } else {
1966 $anonNotice = $this->getCachedNotice( 'anonnotice' );
1967 if ( $anonNotice === false ) {
1968 $siteNotice = $this->getCachedNotice( 'sitenotice' );
1969 } else {
1970 $siteNotice = $anonNotice;
1971 }
1972 }
1973 if ( $siteNotice === false ) {
1974 $siteNotice = $this->getCachedNotice( 'default' ) ?: '';
1975 }
1976 if ( $this->canUseWikiPage() ) {
1977 $ns = $this->getWikiPage()->getNamespace();
1978 $nsNotice = $this->getCachedNotice( "namespacenotice-$ns" );
1979 if ( $nsNotice ) {
1980 $siteNotice .= $nsNotice;
1981 }
1982 }
1983 if ( $siteNotice !== '' ) {
1984 $siteNotice = Html::rawElement( 'div', [ 'id' => 'localNotice', 'data-nosnippet' => '' ], $siteNotice );
1985 }
1986 }
1987
1988 $this->getHookRunner()->onSiteNoticeAfter( $siteNotice, $this );
1989 if ( $this->getOptions()[ 'wrapSiteNotice' ] ) {
1990 $siteNotice = Html::rawElement( 'div', [ 'id' => 'siteNotice' ], $siteNotice );
1991 }
1992 return $siteNotice;
1993 }
1994
2007 public function doEditSectionLink( Title $nt, $section, $sectionTitle, Language $lang ) {
2008 // HTML generated here should probably have userlangattributes
2009 // added to it for LTR text on RTL pages
2010
2011 $attribs = [];
2012 $attribs['title'] = $this->msg( 'editsectionhint' )->plaintextParams( $sectionTitle )
2013 ->inLanguage( $lang )->text();
2014
2015 $links = [
2016 'editsection' => [
2017 'icon' => 'edit',
2018 'text' => $this->msg( 'editsection' )->inLanguage( $lang )->text(),
2019 'targetTitle' => $nt,
2020 'attribs' => $attribs,
2021 'query' => [ 'action' => 'edit', 'section' => $section ]
2022 ]
2023 ];
2024
2025 $this->getHookRunner()->onSkinEditSectionLinks( $this, $nt, $section, $sectionTitle, $links, $lang );
2026
2027 $linkRenderer = MediaWikiServices::getInstance()->getLinkRenderer();
2028 $newLinks = [];
2029 $options = $this->defaultLinkOptions + [
2030 'class-as-property' => true,
2031 ];
2032 $ctx = $this->getContext();
2033 foreach ( $links as $key => $linkDetails ) {
2034 $targetTitle = $linkDetails['targetTitle'];
2035 $attrs = $linkDetails['attribs'];
2036 $query = $linkDetails['query'];
2037 unset( $linkDetails['targetTitle'] );
2038 unset( $linkDetails['query'] );
2039 unset( $linkDetails['attribs'] );
2040 unset( $linkDetails['options' ] );
2041 $component = new SkinComponentLink(
2042 $key, $linkDetails + [
2043 'href' => Title::newFromLinkTarget( $targetTitle )->getLinkURL( $query, false ),
2044 ] + $attrs, $ctx, $options
2045 );
2046 $newLinks[] = $component->getTemplateData();
2047 }
2048 return $this->doEditSectionLinksHTML( $newLinks, $lang );
2049 }
2050
2058 protected function doEditSectionLinksHTML( array $links, Language $lang ) {
2059 $result = Html::openElement( 'span', [ 'class' => 'mw-editsection' ] );
2060 $result .= Html::rawElement( 'span', [ 'class' => 'mw-editsection-bracket' ], '[' );
2061
2062 $linksHtml = array_column( $links, 'html' );
2063
2064 if ( count( $linksHtml ) === 1 ) {
2065 $result .= $linksHtml[0];
2066 } else {
2067 $result .= implode(
2068 Html::rawElement(
2069 'span',
2070 [ 'class' => 'mw-editsection-divider' ],
2071 $this->msg( 'pipe-separator' )->inLanguage( $lang )->escaped()
2072 ),
2073 $linksHtml
2074 );
2075 }
2076
2077 $result .= Html::rawElement( 'span', [ 'class' => 'mw-editsection-bracket' ], ']' );
2078 $result .= Html::closeElement( 'span' );
2079 return $result;
2080 }
2081
2091 public function makeToolbox( $navUrls, $feedUrls ) {
2092 $toolbox = [];
2093 if ( $navUrls['whatlinkshere'] ?? null ) {
2094 $toolbox['whatlinkshere'] = $navUrls['whatlinkshere'];
2095 $toolbox['whatlinkshere']['id'] = 't-whatlinkshere';
2096 $toolbox['whatlinkshere']['icon'] = 'articleRedirect';
2097 }
2098 if ( $navUrls['recentchangeslinked'] ?? null ) {
2099 $toolbox['recentchangeslinked'] = $navUrls['recentchangeslinked'];
2100 $toolbox['recentchangeslinked']['msg'] = 'recentchangeslinked-toolbox';
2101 $toolbox['recentchangeslinked']['id'] = 't-recentchangeslinked';
2102 $toolbox['recentchangeslinked']['rel'] = 'nofollow';
2103 }
2104 if ( $feedUrls ) {
2105 $toolbox['feeds']['id'] = 'feedlinks';
2106 $toolbox['feeds']['links'] = [];
2107 foreach ( $feedUrls as $key => $feed ) {
2108 $toolbox['feeds']['links'][$key] = $feed;
2109 $toolbox['feeds']['links'][$key]['id'] = "feed-$key";
2110 $toolbox['feeds']['links'][$key]['rel'] = 'alternate';
2111 $toolbox['feeds']['links'][$key]['type'] = "application/{$key}+xml";
2112 $toolbox['feeds']['links'][$key]['class'] = 'feedlink';
2113 }
2114 }
2115 foreach ( [ 'contributions', 'log', 'blockip', 'changeblockip', 'unblockip',
2116 'block-manage-blocks', 'emailuser', 'mute', 'userrights', 'upload' ] as $special
2117 ) {
2118 if ( $navUrls[$special] ?? null ) {
2119 $toolbox[$special] = $navUrls[$special];
2120 $toolbox[$special]['id'] = "t-$special";
2121 }
2122 }
2123 if ( $navUrls['print'] ?? null ) {
2124 $toolbox['print'] = $navUrls['print'];
2125 $toolbox['print']['id'] = 't-print';
2126 $toolbox['print']['rel'] = 'alternate';
2127 $toolbox['print']['msg'] = 'printableversion';
2128 }
2129 if ( $navUrls['permalink'] ?? null ) {
2130 $toolbox['permalink'] = $navUrls['permalink'];
2131 $toolbox['permalink']['id'] = 't-permalink';
2132 }
2133 if ( $navUrls['info'] ?? null ) {
2134 $toolbox['info'] = $navUrls['info'];
2135 $toolbox['info']['id'] = 't-info';
2136 }
2137
2138 return $toolbox;
2139 }
2140
2147 protected function getIndicatorsData( array $indicators ): array {
2148 $indicatorData = [];
2149 foreach ( $indicators as $id => $content ) {
2150 $indicatorData[] = [
2151 'id' => Sanitizer::escapeIdForAttribute( "mw-indicator-$id" ),
2152 'class' => 'mw-indicator',
2153 'html' => $content,
2154 ];
2155 }
2156 return $indicatorData;
2157 }
2158
2173 final public function getPersonalToolsForMakeListItem( $urls, $applyClassesToListItems = false ) {
2174 $personal_tools = [];
2175 foreach ( $urls as $key => $plink ) {
2176 # The class on a personal_urls item is meant to go on the <a> instead
2177 # of the <li> so we have to use a single item "links" array instead
2178 # of using most of the personal_url's keys directly.
2179 $ptool = [
2180 'links' => [
2181 [ 'single-id' => "pt-$key" ],
2182 ],
2183 'id' => "pt-$key",
2184 'icon' => $plink[ 'icon' ] ?? null,
2185 ];
2186 if ( $applyClassesToListItems && isset( $plink['class'] ) ) {
2187 $ptool['class'] = $plink['class'];
2188 }
2189 if ( isset( $plink['active'] ) ) {
2190 $ptool['active'] = $plink['active'];
2191 }
2192 // Set class for the link to link-class, when defined.
2193 // This allows newer notifications content navigation to retain their classes
2194 // when merged back into the personal tools.
2195 // Doing this here allows the loop below to overwrite the class if defined directly.
2196 if ( isset( $plink['link-class'] ) ) {
2197 $ptool['links'][0]['class'] = $plink['link-class'];
2198 }
2199 $props = [
2200 'href',
2201 'text',
2202 'dir',
2203 'data',
2204 'exists',
2205 // @todo: Remove data-mw once migration from data-mw to data-mw-interface is complete.
2206 // this should probably go through the deprecation process for 3rd party support.
2207 'data-mw',
2208 'data-mw-interface',
2209 'link-html',
2210 ];
2211 if ( !$applyClassesToListItems ) {
2212 $props[] = 'class';
2213 }
2214 foreach ( $props as $k ) {
2215 if ( isset( $plink[$k] ) ) {
2216 $ptool['links'][0][$k] = $plink[$k];
2217 }
2218 }
2219 $personal_tools[$key] = $ptool;
2220 }
2221 return $personal_tools;
2222 }
2223
2285 final public function makeLink( $key, $item, $linkOptions = [] ) {
2286 $options = $linkOptions + $this->defaultLinkOptions;
2287 $component = new SkinComponentLink(
2288 $key, $item, $this->getContext(), $options
2289 );
2290 return $component->getTemplateData()[ 'html' ];
2291 }
2292
2328 final public function makeListItem( $key, $item, $options = [] ) {
2329 $component = new SkinComponentListItem(
2330 $key, $item, $this->getContext(), $options, $this->defaultLinkOptions
2331 );
2332 return $component->getTemplateData()[ 'html-item' ];
2333 }
2334
2345 public function getAfterPortlet( string $name ): string {
2346 $html = '';
2347
2348 $this->getHookRunner()->onSkinAfterPortlet( $this, $name, $html );
2349
2350 return $html;
2351 }
2352
2359 final public function prepareSubtitle( bool $withContainer = true ) {
2360 $out = $this->getOutput();
2361 $subpagestr = $this->subPageSubtitleInternal();
2362 if ( $subpagestr !== '' ) {
2363 $subpagestr = Html::rawElement( 'div', [ 'class' => 'subpages' ], $subpagestr );
2364 }
2365 $html = $subpagestr . $out->getSubtitle();
2366 return $withContainer ? Html::rawElement( 'div', [
2367 'id' => 'mw-content-subtitle',
2368 ] + $this->getUserLanguageAttributes(), $html ) : $html;
2369 }
2370
2378 protected function getJsConfigVars(): array {
2379 return [];
2380 }
2381
2387 final protected function getUserLanguageAttributes() {
2388 $userLang = $this->getLanguage();
2389 $userLangCode = $userLang->getHtmlCode();
2390 $userLangDir = $userLang->getDir();
2391 $contLang = MediaWikiServices::getInstance()->getContentLanguage();
2392 if (
2393 $userLangCode !== $contLang->getHtmlCode() ||
2394 $userLangDir !== $contLang->getDir()
2395 ) {
2396 return [
2397 'lang' => $userLangCode,
2398 'dir' => $userLangDir,
2399 ];
2400 }
2401 return [];
2402 }
2403
2409 final protected function prepareUserLanguageAttributes() {
2410 return Html::expandAttributes(
2411 $this->getUserLanguageAttributes()
2412 );
2413 }
2414
2420 final protected function prepareUndeleteLink() {
2421 $undelete = $this->getUndeleteLink();
2422 return $undelete === '' ? null : '<div class="subpages">' . $undelete . '</div>';
2423 }
2424
2433 protected function wrapHTML( $title, $html ) {
2434 // This wraps the "real" body content (i.e. parser output or special page).
2435 // On page views, elements like categories and contentSub are outside of this.
2436 return Html::rawElement( 'div', [
2437 'id' => 'mw-content-text',
2438 'class' => [
2439 'mw-body-content',
2440 ],
2441 ], $html );
2442 }
2443
2452 final public function getOptions(): array {
2453 return $this->options + [
2454 'styles' => [],
2455 'scripts' => [],
2456 'toc' => true,
2457 'format' => 'html',
2458 'bodyClasses' => [],
2459 'clientPrefEnabled' => false,
2460 'responsive' => false,
2461 'link' => [],
2462 'tempUserBanner' => false,
2463 'wrapSiteNotice' => false,
2464 'menus' => [
2465 // Legacy keys that are enabled by default for backwards compatibility
2466 'namespaces',
2467 'views',
2468 'actions',
2469 'variants',
2470 // Opt-in menus
2471 // * 'associated-pages'
2472 // * 'notifications'
2473 // * 'user-interface-preferences',
2474 // * 'user-page',
2475 // * 'user-menu',
2476 ]
2477 ];
2478 }
2479
2488 public function supportsMenu( string $menu ): bool {
2489 $options = $this->getOptions();
2490 return in_array( $menu, $options['menus'] );
2491 }
2492
2507 public static function getPortletLinkOptions( RL\Context $context ): array {
2508 $skinName = $context->getSkin();
2509 $skinFactory = MediaWikiServices::getInstance()->getSkinFactory();
2510 $options = $skinFactory->getSkinOptions( $skinName );
2511 $portletLinkOptions = $options['link'] ?? [];
2512 // Normalize link options to always have this key
2513 $portletLinkOptions += [ 'text-wrapper' => [] ];
2514 // Normalize text-wrapper to always be an array of arrays
2515 if ( isset( $portletLinkOptions['text-wrapper']['tag'] ) ) {
2516 $portletLinkOptions['text-wrapper'] = [ $portletLinkOptions['text-wrapper'] ];
2517 }
2518 return $portletLinkOptions;
2519 }
2520
2528 final protected function getPortletData( string $name, array $items ): array {
2529 $portletComponent = new SkinComponentMenu(
2530 $name,
2531 $items,
2532 $this->getContext(),
2533 '',
2534 $this->defaultLinkOptions,
2535 $this->getAfterPortlet( $name )
2536 );
2537 return $portletComponent->getTemplateData();
2538 }
2539
2551 public function getPageTarget() {
2552 $target = '';
2553 // Check if the target user is a valid user or IP
2554 $relUser = $this->getRelevantUser();
2555 if ( $relUser ) {
2556 $target = $relUser->getName();
2557 }
2558
2559 // Otherwise, check if the target is an IP range which should also be supported
2560 if ( !$target ) {
2561 // Check for the target parameter first
2562 $pageTarget = trim( $this->getRequest()->getText( 'target' ) );
2563
2564 // If it doesn't exist, check for the subpage next
2565 if ( !$pageTarget ) {
2566 $pageTarget = $this->getTitle()->getFullSubpageText();
2567 }
2568
2569 // If it exists, only set the target if it's an IP range
2570 // as that's the only case not covered by Skin->getRelevantUser()
2571 if (
2572 $pageTarget &&
2573 IPUtils::isValidRange( $pageTarget )
2574 ) {
2575 $target = $pageTarget;
2576 }
2577 }
2578
2579 return $target;
2580 }
2581}
2582
2584class_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:68
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:43
Methods for dealing with language codes.
Base class for language-specific code.
Definition Language.php:70
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:52
buildNavUrls()
Build array of common navigation links.
Definition Skin.php:1318
getRelevantTitle()
Return the "relevant" title.
Definition Skin.php:613
array $options
Skin options passed into constructor.
Definition Skin.php:68
buildFeedUrls()
Build data structure representing syndication links.
Definition Skin.php:1521
string null $skinname
Definition Skin.php:63
getDefaultModules()
Defines the ResourceLoader modules that should be added to the skin It is recommended that skins wish...
Definition Skin.php:432
static getVersion()
Get the current major version of Skin.
Definition Skin.php:98
logoText( $align='')
Definition Skin.php:1048
getPageClasses( $title)
TODO: document.
Definition Skin.php:701
supportsMenu(string $menu)
Does the skin support the named menu? e.g.
Definition Skin.php:2488
getJsConfigVars()
Returns array of config variables that should be added only to this skin for use in JavaScript.
Definition Skin.php:2378
getComponent(string $name)
Definition Skin.php:107
doEditSectionLink(Title $nt, $section, $sectionTitle, Language $lang)
Create a section edit link.
Definition Skin.php:2007
static makeKnownUrlDetails( $name, $urlaction='')
Make URL details where the article exists (or at least it's convenient to think so)
Definition Skin.php:1184
mapInterwikiToLanguage( $code)
Allows correcting the language of interlanguage links which, mostly due to legacy reasons,...
Definition Skin.php:1200
getAfterPortlet(string $name)
Allows extensions to hook into known portlets and add stuff to them.
Definition Skin.php:2345
static makeInternalOrExternalUrl( $name)
If url string starts with http, consider as external URL, else internal.
Definition Skin.php:1153
prepareUndeleteLink()
Prepare undelete link for output in page.
Definition Skin.php:2420
outputPageFinal(OutputPage $out)
Outputs the HTML for the page.
Definition Skin.php:672
afterContentHook()
This runs a hook to allow extensions placing their stuff after content and article metadata (e....
Definition Skin.php:856
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:2091
static makeMainPageUrl( $urlaction='')
Definition Skin.php:1141
setRelevantTitle( $t)
Definition Skin.php:598
prepareUserLanguageAttributes()
Prepare user language attribute links.
Definition Skin.php:2409
addToSidebar(&$bar, $message)
Add content from a sidebar system message Currently only used for MediaWiki:Sidebar (but may be used ...
Definition Skin.php:1626
static getPortletLinkOptions(RL\Context $context)
Returns skin options for portlet links, used by addPortletLink.
Definition Skin.php:2507
editUrlOptions()
Return URL options for the 'edit page' link.
Definition Skin.php:1104
buildSidebar()
Build an array that represents the sidebar(s), the navigation bar among them.
Definition Skin.php:1561
makeFooterIcon( $icon, $withImage='withImage')
Renders a $wgFooterIcons icon according to the method's arguments.
Definition Skin.php:1091
getOptions()
Get current skin's options.
Definition Skin.php:2452
initPage(OutputPage $out)
Definition Skin.php:381
getPersonalToolsForMakeListItem( $urls, $applyClassesToListItems=false)
Create an array of personal tools items from the data in the quicktemplate stored by SkinTemplate.
Definition Skin.php:2173
static normalizeKey(string $key)
Normalize a skin preference value to a form that can be loaded.
Definition Skin.php:216
wrapHTML( $title, $html)
Wrap the body text with language information and identifiable element.
Definition Skin.php:2433
getUserLanguageAttributes()
Get user language attribute links array.
Definition Skin.php:2387
Title null $mRelevantTitle
Definition Skin.php:70
static makeUrlDetails( $name, $urlaction='')
these return an array with the 'href' and boolean 'exists'
Definition Skin.php:1170
getPortletData(string $name, array $items)
Definition Skin.php:2528
printSource()
Text with the permalink to the source page, usually shown on the footer of a printed page.
Definition Skin.php:900
const VERSION_MAJOR
The current major version of the skin specification.
Definition Skin.php:78
prepareSubtitle(bool $withContainer=true)
Prepare the subtitle of the page for output in the skin if one has been set.
Definition Skin.php:2359
doEditSectionLinksHTML(array $links, Language $lang)
Definition Skin.php:2058
getHtmlElementAttributes()
Return values for <html> element.
Definition Skin.php:743
makeListItem( $key, $item, $options=[])
Generates a list item for a navigation, portlet, portal, sidebar... list.
Definition Skin.php:2328
getIndicatorsData(array $indicators)
Return an array of indicator data.
Definition Skin.php:2147
isResponsive()
Indicates if this skin is responsive.
Definition Skin.php:369
setRelevantUser(?UserIdentity $u)
Definition Skin.php:621
__construct( $options=null)
Definition Skin.php:333
getFooterIcons()
Get template representation of the footer.
Definition Skin.php:1074
getLanguages()
Generates array of language links for the current page.
Definition Skin.php:1213
getNewtalks()
Gets new talk page messages for the current user and returns an appropriate alert message (or an empt...
Definition Skin.php:1797
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:2285
getRelevantUser()
Return the "relevant" user.
Definition Skin.php:634
addToSidebarPlain(&$bar, $text)
Add content from plain text.
Definition Skin.php:1701
Parent class for all special pages.
Represents the target of a wiki link.
Represents a title within MediaWiki.
Definition Title.php:70
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:110
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', 'sodipodi'=> ' $path/sodipodi -z -w $width -f $input -e $output', 'inkscape'=> ' $path/inkscape -z -w $width -f $input -e $output', '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', 'imgserv'=> ' $path/imgserv-wrapper -i svg -o png -w$width $input $output', 'ImagickExt'=>['SvgHandler::rasterizeImagickExt',],], 'SVGConverter'=> 'ImageMagick', 'SVGConverterPath'=> '', 'SVGMaxSize'=> 5120, 'SVGMetadataCutoff'=> 5242880, 'SVGNativeRendering'=> false, '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, 250, 300,], '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, 'DjvuUseBoxedCommand'=> false, 'DjvuDump'=> null, 'DjvuRenderer'=> null, 'DjvuTxt'=> null, 'DjvuPostProcessor'=> 'pnmtojpeg', 'DjvuOutputExtension'=> 'jpg', 'EmergencyContact'=> false, 'PasswordSender'=> false, 'NoReplyAddress'=> false, 'EnableEmail'=> true, 'EnableUserEmail'=> true, 'EnableSpecialMute'=> false, 'EnableUserEmailMuteList'=> false, 'UserEmailUseReplyTo'=> true, 'PasswordReminderResendTime'=> 24, 'NewPasswordExpiry'=> 604800, 'UserEmailConfirmationTokenExpiry'=> 604800, 'UserEmailConfirmationUseHTML'=> false, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, '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'=> '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,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> '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, 'BlockTargetMigrationStage' => 768, '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, ], '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' => [ ], '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, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => 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, '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, '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, '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, '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, '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' => [ ], 'RCEngines' => [ 'redis' => 'MediaWiki\\RCFeed\\RedisPubSubFeedEngine', 'udp' => 'MediaWiki\\RCFeed\\UDPRCFeedEngine', ], '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, '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, 'UsePostprocCache' => false, ], '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', ], 'UserEmailConfirmationUseHTML' => 'boolean', 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => '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', 'BlockTargetMigrationStage' => 'integer', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', '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', ], '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', 'RCEngines' => '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', ], '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', 'UsePostprocCache' => 'boolean', ], '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', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], 'required' => [ 'url', ], ], ], '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.', ],]
Interface for objects representing user identity.
Interface for database access objects.
msg( $key,... $params)