MediaWiki master
SkinTemplate.php
Go to the documentation of this file.
1<?php
9namespace MediaWiki\Skin;
10
11use InvalidArgumentException;
28use RuntimeException;
32use Wikimedia\Timestamp\TimestampFormat as TS;
33
42class SkinTemplate extends Skin {
47 public $template;
48
50 public $thispage;
52 public $titletxt;
54 public $userpage;
56 public $loggedin;
58 public $username;
61
63 private $isTempUser;
64
66 private $isAnonUser;
67
69 private $templateContextSet = false;
71 private $contentNavigationCached;
73 private $portletsCached;
74
83 protected function setupTemplate( $classname ) {
84 return new $classname( $this->getConfig() );
85 }
86
90 protected function setupTemplateForOutput() {
91 $this->setupTemplateContext();
92 $template = $this->options['template'] ?? $this->template;
93 if ( !$template ) {
94 throw new RuntimeException(
95 'SkinTemplate skins must define a `template` either as a public'
96 . ' property of by passing in a`template` option to the constructor.'
97 );
98 }
99 $tpl = $this->setupTemplate( $template );
100 return $tpl;
101 }
102
112 final protected function setupTemplateContext() {
113 if ( $this->templateContextSet ) {
114 return;
115 }
116
117 $request = $this->getRequest();
118 $user = $this->getUser();
119 $title = $this->getTitle();
120 $this->thispage = $title->getPrefixedDBkey();
121 $this->titletxt = $title->getPrefixedText();
122 $userpageTitle = $user->getUserPage();
123 $this->userpage = $userpageTitle->getPrefixedText();
124 $this->loggedin = $user->isRegistered();
125 $this->username = $user->getName();
126 $this->isTempUser = $user->isTemp();
127 $this->isAnonUser = $user->isAnon();
128
129 if ( $this->loggedin ) {
130 $this->userpageUrlDetails = self::makeUrlDetails( $userpageTitle );
131 } else {
132 # This won't be used in the standard skins, but we define it to preserve the interface
133 # To save time, we check for existence
134 $this->userpageUrlDetails = self::makeKnownUrlDetails( $userpageTitle );
135 }
136
137 $this->templateContextSet = true;
138 }
139
147 public function generateHTML() {
148 $tpl = $this->prepareQuickTemplate();
149 $options = $this->getOptions();
150 $out = $this->getOutput();
151 // execute template
152 ob_start();
153 $tpl->execute();
154 $html = ob_get_contents();
155 ob_end_clean();
156
157 return $html;
158 }
159
164 public function outputPage() {
165 Profiler::instance()->setAllowOutput();
166 $out = $this->getOutput();
167
168 $this->initPage( $out );
169 $out->addJsConfigVars( $this->getJsConfigVars() );
170
171 // result may be an error
172 echo $this->generateHTML();
173 }
174
178 public function getTemplateData() {
179 return parent::getTemplateData() + $this->getPortletsTemplateData();
180 }
181
188 protected function prepareQuickTemplate() {
189 $title = $this->getTitle();
190 $request = $this->getRequest();
191 $out = $this->getOutput();
192 $config = $this->getConfig();
193 $tpl = $this->setupTemplateForOutput();
194
195 $tpl->set( 'title', $out->getPageTitle() );
196 $tpl->set( 'pagetitle', $out->getHTMLTitle() );
197
198 $tpl->set( 'thispage', $this->thispage );
199 $tpl->set( 'titleprefixeddbkey', $this->thispage );
200 $tpl->set( 'titletext', $title->getText() );
201 $tpl->set( 'articleid', $title->getArticleID() );
202
203 $tpl->set( 'isarticle', $out->isArticle() );
204
205 $tpl->set( 'subtitle', $this->prepareSubtitle() );
206 $tpl->set( 'undelete', $this->prepareUndeleteLink() );
207
208 $tpl->set( 'catlinks', $this->getCategories() );
209 $feeds = $this->buildFeedUrls();
210 $tpl->set( 'feeds', count( $feeds ) ? $feeds : false );
211
212 $tpl->set( 'mimetype', $config->get( MainConfigNames::MimeType ) );
213 $tpl->set( 'charset', 'UTF-8' );
214 $tpl->set( 'wgScript', $config->get( MainConfigNames::Script ) );
215 $tpl->set( 'skinname', $this->skinname );
216 $tpl->set( 'skinclass', static::class );
217 $tpl->set( 'skin', $this );
218 $tpl->set( 'printable', $out->isPrintable() );
219 $tpl->set( 'handheld', $request->getBool( 'handheld' ) );
220 $tpl->set( 'loggedin', $this->loggedin );
221 $tpl->set( 'notspecialpage', !$title->isSpecialPage() );
222
223 $searchTitle = SpecialPage::newSearchPage( $this->getUser() );
224 $searchLink = $searchTitle->getLocalURL();
225 $tpl->set( 'searchaction', $searchLink );
226 $tpl->deprecate( 'searchaction', '1.36' );
227
228 $tpl->set( 'searchtitle', $searchTitle->getPrefixedDBkey() );
229 $tpl->set( 'search', trim( $request->getVal( 'search', '' ) ) );
230 $tpl->set( 'stylepath', $config->get( MainConfigNames::StylePath ) );
231 $tpl->set( 'articlepath', $config->get( MainConfigNames::ArticlePath ) );
232 $tpl->set( 'scriptpath', $config->get( MainConfigNames::ScriptPath ) );
233 $tpl->set( 'serverurl', $config->get( MainConfigNames::Server ) );
234 $tpl->set( 'sitename', $config->get( MainConfigNames::Sitename ) );
235
236 $userLang = $this->getLanguage();
237 $userLangCode = $userLang->getHtmlCode();
238 $userLangDir = $userLang->getDir();
239
240 $tpl->set( 'lang', $userLangCode );
241 $tpl->set( 'dir', $userLangDir );
242 $tpl->set( 'rtl', $userLang->isRTL() );
243
244 $logos = RL\SkinModule::getAvailableLogos( $config, $userLangCode );
245 $tpl->set( 'logopath', $logos['1x'] );
246
247 $tpl->set( 'showjumplinks', true ); // showjumplinks preference has been removed
248 $tpl->set( 'username', $this->loggedin ? $this->username : null );
249 $tpl->set( 'userpage', $this->userpage );
250 $tpl->set( 'userpageurl', $this->userpageUrlDetails['href'] );
251 $tpl->set( 'userlang', $userLangCode );
252
253 // Users can have their language set differently than the
254 // content of the wiki. For these users, tell the web browser
255 // that interface elements are in a different language.
256 $tpl->set( 'userlangattributes', $this->prepareUserLanguageAttributes() );
257 $tpl->set( 'specialpageattributes', '' ); # obsolete
258 // Used by VectorBeta to insert HTML before content but after the
259 // heading for the page title. Defaults to empty string.
260 $tpl->set( 'prebodyhtml', '' );
261
262 $tpl->set( 'newtalk', $this->getNewtalks() );
263 $tpl->set( 'logo', $this->logoText() );
264
265 $footerData = $this->getComponent( 'footer' )->getTemplateData();
266 $tpl->set( 'copyright', $footerData['info']['copyright'] ?? false );
267 // No longer used
268 $tpl->set( 'viewcount', false );
269 $tpl->set( 'lastmod', $footerData['info']['lastmod'] ?? false );
270 $tpl->set( 'credits', $footerData['info']['credits'] ?? false );
271 $tpl->set( 'numberofwatchingusers', false );
272
273 $tpl->set( 'disclaimer', $footerData['places']['disclaimer'] ?? false );
274 $tpl->set( 'privacy', $footerData['places']['privacy'] ?? false );
275 $tpl->set( 'about', $footerData['places']['about'] ?? false );
276
277 // Flatten for compat with the 'footerlinks' key in QuickTemplate-based skins.
278 $flattenedfooterlinks = [];
279 foreach ( $footerData as $category => $data ) {
280 if ( $category !== 'data-icons' ) {
281 foreach ( $data['array-items'] as $item ) {
282 $key = str_replace( 'data-', '', $category );
283 $flattenedfooterlinks[$key][] = $item['name'];
284 // For full support with BaseTemplate we also need to
285 // copy over the keys.
286 $tpl->set( $item['name'], $item['html'] );
287 }
288 }
289 }
290 $tpl->set( 'footerlinks', $flattenedfooterlinks );
291 $tpl->set( 'footericons', $this->getFooterIcons() );
292
293 $tpl->set( 'indicators', $out->getIndicators() );
294
295 $tpl->set( 'sitenotice', $this->getSiteNotice() );
296 $tpl->set( 'printfooter', $this->printSource() );
297 // Wrap the bodyText with #mw-content-text element
298 $tpl->set( 'bodytext', $this->wrapHTML( $title, $out->getHTML() ) );
299
300 $tpl->set( 'language_urls', $this->getLanguages() ?: false );
301
302 $content_navigation = $this->buildContentNavigationUrlsInternal();
303 $requestedMenus = $this->getOptions()['menus'];
304 # Personal toolbar
305 if ( in_array( 'personal', $requestedMenus ) ) {
306 $tpl->set( 'personal_urls', $this->makeSkinTemplatePersonalUrls( $content_navigation ) );
307 }
308 $tpl->deprecate( 'personal_urls', 'Use content_navigation instead' );
309 // The user-menu, notifications, and user-interface-preferences are new content navigation entries which aren't
310 // expected to be part of content_navigation or content_actions. Adding them in there breaks skins that do not
311 // expect it. (See T316196)
312 $optInKeys = [
313 'user-menu',
314 'notifications',
315 'user-page',
316 'user-interface-preferences',
317 'category-normal',
318 'category-hidden',
319 'associated-pages',
320 // All historic menus are covered by requested menus so can be unset
321 // This should match the default for Skin::getOptions()['menus']
322 'namespaces',
323 'views',
324 'actions',
325 'variants'
326 ];
327 // We could iterate on keys of $requestedMenus but that might break skins making use of their own custom menus
328 // This is safer for backwards compatibility!
329 foreach ( $optInKeys as $key ) {
330 if ( !in_array( $key, $requestedMenus ) ) {
331 unset( $content_navigation[ $key ] );
332 }
333 }
334 $content_actions = $this->buildContentActionUrls( $content_navigation );
335 $tpl->set( 'content_navigation', $content_navigation );
336 $tpl->set( 'content_actions', $content_actions );
337 $tpl->deprecate( 'content_actions', '1.46' );
338
339 $tpl->set( 'sidebar', $this->buildSidebar() );
340 $tpl->set( 'nav_urls', $this->buildNavUrls() );
341
342 $tpl->set( 'debug', '' );
343 $tpl->set( 'debughtml', MWDebug::getHTMLDebugLog() );
344
345 // Set the bodytext to another key so that skins can just output it on its own
346 // and output printfooter and debughtml separately
347 $tpl->set( 'bodycontent', $tpl->data['bodytext'] );
348
349 // Append printfooter and debughtml onto bodytext so that skins that
350 // were already using bodytext before they were split out don't suddenly
351 // start not outputting information.
352 $tpl->data['bodytext'] .= Html::rawElement(
353 'div',
354 [ 'class' => 'printfooter' ],
355 "\n{$tpl->data['printfooter']}"
356 ) . "\n";
357 $tpl->data['bodytext'] .= $tpl->data['debughtml'];
358
359 // allow extensions adding stuff after the page content.
360 // See Skin::afterContentHook() for further documentation.
361 $tpl->set( 'dataAfterContent', $this->afterContentHook() );
362
363 return $tpl;
364 }
365
374 public function makePersonalToolsList( $personalTools = null, $options = [] ) {
375 $personalTools ??= $this->getPersonalToolsForMakeListItem(
376 $this->buildPersonalUrls()
377 );
378
379 $html = '';
380 foreach ( $personalTools as $key => $item ) {
381 $html .= $this->makeListItem( $key, $item, $options );
382 }
383 return $html;
384 }
385
393 public function getStructuredPersonalTools() {
395 $this->buildPersonalUrls()
396 );
397 }
398
406 protected function buildPersonalUrls( bool $includeNotifications = true ) {
407 $this->setupTemplateContext();
408 $title = $this->getTitle();
409 $authority = $this->getAuthority();
410 $request = $this->getRequest();
411 $pageurl = $title->getLocalURL();
412 $services = MediaWikiServices::getInstance();
413 $authManager = $services->getAuthManager();
414 $groupPermissionsLookup = $services->getGroupPermissionsLookup();
415 $tempUserConfig = $services->getTempUserConfig();
416 $returnto = SkinComponentUtils::getReturnToParam( $title, $request, $authority );
417 $shouldHideUserLinks = $this->isAnonUser && $tempUserConfig->isKnown();
418
419 /* set up the default links for the personal toolbar */
420 $personal_urls = [];
421
422 if ( $this->loggedin ) {
423 $this->addPersonalPageItem( $personal_urls, '' );
424 if ( $this->isTempUser ) {
425 $this->addAccountLinks( $personal_urls, $returnto );
426 }
427 // Merge notifications into the personal menu for older skins.
428 if ( $includeNotifications ) {
429 $contentNavigation = $this->buildContentNavigationUrlsInternal();
430
431 if ( isset( $contentNavigation['notifications'] ) ) {
432 $personal_urls += $contentNavigation['notifications'];
433 }
434 }
435
436 $usertalkUrlDetails = $this->makeTalkUrlDetails( $this->userpage );
437 $personal_urls['mytalk'] = [
438 'text' => $this->msg( 'mytalk' )->text(),
439 'href' => &$usertalkUrlDetails['href'],
440 'class' => $usertalkUrlDetails['exists'] ? null : 'new',
441 'exists' => $usertalkUrlDetails['exists'],
442 'active' => ( $usertalkUrlDetails['href'] == $pageurl ),
443 'icon' => 'userTalk'
444 ];
445 if ( !$this->isTempUser ) {
446 $href = SkinComponentUtils::makeSpecialUrl( 'Preferences' );
447 $personal_urls['preferences'] = [
448 'text' => $this->msg( 'mypreferences' )->text(),
449 'href' => $href,
450 'active' => ( $href == $pageurl ),
451 'icon' => 'settings',
452 ];
453 }
454
455 if ( $authority->isAllowed( 'viewmywatchlist' ) ) {
456 $personal_urls['watchlist'] = self::buildWatchlistData();
457 }
458
459 # We need to do an explicit check for Special:Contributions, as we
460 # have to match both the title, and the target, which could come
461 # from request values (Special:Contributions?target=Jimbo_Wales)
462 # or be specified in "subpage" form
463 # (Special:Contributions/Jimbo_Wales). The plot
464 # thickens, because the Title object is altered for special pages,
465 # so it doesn't contain the original alias-with-subpage.
466 $origTitle = Title::newFromText( $request->getText( 'title' ) );
467 if ( $origTitle instanceof Title && $origTitle->isSpecialPage() ) {
468 [ $spName, $spPar ] =
469 MediaWikiServices::getInstance()->getSpecialPageFactory()->
470 resolveAlias( $origTitle->getText() );
471 $active = $spName == 'Contributions'
472 && ( ( $spPar && $spPar == $this->username )
473 || $request->getText( 'target' ) == $this->username );
474 } else {
475 $active = false;
476 }
477
478 $personal_urls = $this->makeContributionsLink( $personal_urls, 'mycontris', $this->username, $active );
479
480 // if we can't set the user, we can't unset it either
481 if ( $request->getSession()->canSetUser() ) {
482 $personal_urls['logout'] = $this->buildLogoutLinkData();
483 }
484 } elseif ( !$shouldHideUserLinks ) {
485 $canEdit = $authority->isAllowed( 'edit' );
486 $canEditWithTemp = $tempUserConfig->isAutoCreateAction( 'edit' );
487 // No need to show Talk and Contributions to anons if they can't contribute!
488 if ( $canEdit || $canEditWithTemp ) {
489 // Non interactive placeholder for anonymous users.
490 // It's unstyled by default (black color). Skin that
491 // needs it, can style it using the 'pt-anonuserpage' id.
492 // Skin that does not need it should unset it.
493 $personal_urls['anonuserpage'] = [
494 'text' => $this->msg( 'notloggedin' )->text(),
495 ];
496 }
497 if ( $canEdit ) {
498 // Because of caching, we can't link directly to the IP talk and
499 // contributions pages. Instead we use the special page shortcuts
500 // (which work correctly regardless of caching). This means we can't
501 // determine whether these links are active or not, but since major
502 // skins (MonoBook, Vector) don't use this information, it's not a
503 // huge loss.
504 $personal_urls['anontalk'] = [
505 'text' => $this->msg( 'anontalk' )->text(),
506 'href' => SkinComponentUtils::makeSpecialUrlSubpage( 'Mytalk', false ),
507 'active' => false,
508 'icon' => 'userTalk',
509 ];
510 $personal_urls = $this->makeContributionsLink( $personal_urls, 'anoncontribs', null, false );
511 }
512 }
513
514 if ( !$this->loggedin ) {
515 $this->addAccountLinks( $personal_urls, $returnto );
516 }
517
518 return $personal_urls;
519 }
520
524 private function addAccountLinks( array &$personal_urls, array $returnto ): void {
525 $services = MediaWikiServices::getInstance();
526 $authority = $this->getAuthority();
527 $authManager = $services->getAuthManager();
528 $groupPermissionsLookup = $services->getGroupPermissionsLookup();
529 $useCombinedLoginLink = $this->useCombinedLoginLink();
530 $login_url = $this->buildLoginData( $returnto, $useCombinedLoginLink );
531 $createaccount_url = $this->buildCreateAccountData( $returnto );
532
533 if (
534 $authManager->canCreateAccounts()
535 && $authority->isAllowed( 'createaccount' )
536 && !$useCombinedLoginLink
537 ) {
538 $personal_urls['createaccount'] = $createaccount_url;
539 }
540
541 if ( $authManager->canAuthenticateNow() ) {
542 // TODO: easy way to get anon authority
543 $key = $groupPermissionsLookup->groupHasPermission( '*', 'read' )
544 ? 'login'
545 : 'login-private';
546 $personal_urls[$key] = $login_url;
547 }
548 }
549
556 protected function useCombinedLoginLink() {
557 $services = MediaWikiServices::getInstance();
558 $authManager = $services->getAuthManager();
559 $useCombinedLoginLink = $this->getConfig()->get( MainConfigNames::UseCombinedLoginLink );
560 if ( !$authManager->canCreateAccounts() || !$authManager->canAuthenticateNow() ) {
561 // don't show combined login/signup link if one of those is actually not available
562 $useCombinedLoginLink = false;
563 }
564
565 return $useCombinedLoginLink;
566 }
567
577 protected function buildLoginData( $returnto, $useCombinedLoginLink ) {
578 $title = $this->getTitle();
579
580 $loginlink = $this->getAuthority()->isAllowed( 'createaccount' )
581 && $useCombinedLoginLink ? 'nav-login-createaccount' : 'pt-login';
582
583 $login_url = [
584 'single-id' => 'pt-login',
585 'text' => $this->msg( $loginlink )->text(),
586 'href' => SkinComponentUtils::makeSpecialUrl( 'Userlogin', $returnto ),
587 'active' => $title->isSpecial( 'Userlogin' )
588 || ( $title->isSpecial( 'CreateAccount' ) && $useCombinedLoginLink ),
589 'icon' => 'logIn'
590 ];
591
592 return $login_url;
593 }
594
599 private function getCategoryPortletsData( array $links ): array {
600 $categories = [];
601 foreach ( $links as $group => $groupLinks ) {
602 $allLinks = [];
603 $groupName = 'category-' . $group;
604 foreach ( $groupLinks as $i => $link ) {
605 $allLinks[$groupName . '-' . $i] = [
606 'html' => $link,
607 ];
608 }
609 $categories[ $groupName ] = $allLinks;
610 }
611 return $categories;
612 }
613
618 public function getCategoryLinks() {
619 $afterPortlet = $this->getPortletsTemplateData()['data-portlets']['data-category-normal']['html-after-portal']
620 ?? '';
621 return parent::getCategoryLinks() . $afterPortlet;
622 }
623
627 private function getPortletsTemplateData() {
628 if ( $this->portletsCached ) {
629 return $this->portletsCached;
630 }
631 $portlets = [];
632 $contentNavigation = $this->buildContentNavigationUrlsInternal();
633 $sidebar = [];
634 $sidebarData = $this->buildSidebar();
635 foreach ( $sidebarData as $name => $items ) {
636 if ( is_array( $items ) ) {
637 // Numeric strings gets an integer when set as key, cast back - T73639
638 $name = (string)$name;
639 switch ( $name ) {
640 // ignore search
641 case 'SEARCH':
642 break;
643 // Map toolbox to `tb` id.
644 case 'TOOLBOX':
645 $sidebar[] = $this->getPortletData( 'tb', $items );
646 break;
647 // Languages is no longer be tied to sidebar
648 case 'LANGUAGES':
649 // The language portal will be added provided either
650 // languages exist or there is a value in html-after-portal
651 // for example to show the add language wikidata link (T252800)
652 $portal = $this->getPortletData( 'lang', $items );
653 if ( count( $items ) || $portal['html-after-portal'] ) {
654 $portlets['data-languages'] = $portal;
655 }
656 break;
657 default:
658 $sidebar[] = $this->getPortletData( $name, $items );
659 break;
660 }
661 }
662 }
663
664 foreach ( $contentNavigation as $name => $items ) {
665 if ( $name === 'user-menu' ) {
666 $items = $this->getPersonalToolsForMakeListItem( $items, true );
667 }
668
669 $portlets['data-' . $name] = $this->getPortletData( $name, $items );
670 }
671
672 $menuOptions = $this->getOptions()['menus'];
673 $intro = 'Skins must now pass `menus` key to skin definition in skin.json. Default value is: '
674 . "['namespaces', 'views', 'actions', 'variants', 'personal']. <br>";
675 if ( in_array( 'namespaces', $menuOptions ) ) {
677 $intro . 'Menu "namespaces" is deprecated. Please replace with "associated-pages".',
678 '1.46'
679 );
680 }
681
682 // A menu that includes the notifications. Now deprecated.
683 if ( in_array( 'personal', $menuOptions ) ) {
685 $intro . 'Menu "personal" is deprecated. Replace with "user-page", "user-interface-preferences",'
686 . '"notifications" and "user-menu".',
687 '1.46'
688 );
689 $portlets['data-personal'] = $this->getPortletData(
690 'personal',
691 $this->getPersonalToolsForMakeListItem(
692 $this->injectLegacyMenusIntoPersonalTools( $contentNavigation )
693 )
694 );
695 }
696
697 $this->portletsCached = [
698 'data-portlets' => $portlets,
699 'data-portlets-sidebar' => [
700 'data-portlets-first' => $sidebar[0] ?? null,
701 'array-portlets-rest' => array_slice( $sidebar, 1 ),
702 ],
703 ];
704 return $this->portletsCached;
705 }
706
716 final protected function buildLogoutLinkData() {
717 $title = $this->getTitle();
718 $request = $this->getRequest();
719 $authority = $this->getAuthority();
720 $returnto = SkinComponentUtils::getReturnToParam( $title, $request, $authority );
721 $isTemp = $this->isTempUser;
722 $msg = $isTemp ? 'templogout' : 'pt-userlogout';
723
724 return [
725 'single-id' => 'pt-logout',
726 'text' => $this->msg( $msg )->text(),
727 'data-mw-interface' => '1',
728 'href' => SkinComponentUtils::makeSpecialUrl( 'Userlogout', $returnto ),
729 'active' => false,
730 'icon' => 'logOut'
731 ];
732 }
733
741 protected function buildCreateAccountData( $returnto ) {
742 $title = $this->getTitle();
743
744 return [
745 'single-id' => 'pt-createaccount',
746 'text' => $this->msg( 'pt-createaccount' )->text(),
747 'href' => SkinComponentUtils::makeSpecialUrl( 'CreateAccount', $returnto ),
748 'active' => $title->isSpecial( 'CreateAccount' ),
749 'icon' => 'userAdd'
750 ];
751 }
752
759 private function addPersonalPageItem( &$links, $idSuffix ) {
760 if ( $this->loggedin ) {
761 $links['userpage'] = $this->buildPersonalPageItem( 'pt-userpage' . $idSuffix );
762 }
763 }
764
771 protected function buildPersonalPageItem( $id = 'pt-userpage' ): array {
772 $linkClasses = $this->userpageUrlDetails['exists'] ? [] : [ 'new' ];
773 $icon = $this->isTempUser ? 'userTemporary' : 'userAvatar';
774 if ( $this->isTempUser ) {
775 $linkClasses[] = 'mw-temp-user-link';
776 }
777 $href = &$this->userpageUrlDetails['href'];
778 return [
779 'id' => $id,
780 'single-id' => 'pt-userpage',
781 'text' => $this->username,
782 'href' => $href,
783 'link-class' => $linkClasses,
784 'exists' => $this->userpageUrlDetails['exists'],
785 'active' => ( $this->userpageUrlDetails['href'] == $this->getTitle()->getLocalURL() ),
786 'icon' => $icon,
787 ];
788 }
789
795 private function buildWatchlistData() {
796 $href = SkinComponentUtils::makeSpecialUrl( 'Watchlist' );
797 $pageurl = $this->getTitle()->getLocalURL();
798
799 return [
800 'single-id' => 'pt-watchlist',
801 'text' => $this->msg( 'mywatchlist' )->text(),
802 'href' => $href,
803 'active' => ( $href == $pageurl ),
804 'icon' => 'watchlist'
805 ];
806 }
807
821 public function tabAction( $title, $message, $selected, $query = '', $checkEdit = false ) {
822 $classes = [];
823 if ( $selected ) {
824 $classes[] = 'selected';
825 }
826 $exists = true;
827 $services = MediaWikiServices::getInstance();
828 $linkClass = $services->getLinkRenderer()->getLinkClasses( $title );
829 if ( $checkEdit && !$title->isKnown() ) {
830 // Selected tabs should not show as red link. It doesn't make sense
831 // to show a red link on a page the user has already navigated to.
832 // https://phabricator.wikimedia.org/T294129#7451549
833 if ( !$selected ) {
834 // For historic reasons we add to the LI element
835 $classes[] = 'new';
836 // but adding the class to the A element is more appropriate.
837 $linkClass .= ' new';
838 }
839 $exists = false;
840 if ( $query !== '' ) {
841 $query = 'action=edit&redlink=1&' . $query;
842 } else {
843 $query = 'action=edit&redlink=1';
844 }
845 } elseif ( $title->isRedirect() ) {
846 // Do not redirect on redirect pages, see T5324
847 $origTitle = $this->getRelevantTitle();
848 // FIXME: If T385340 is resolved, this check can be removed
849 $action = $this->getContext()->getActionName();
850 $out = $this->getOutput();
851 $notCurrentActionView = $action !== 'view' || !$out->isRevisionCurrent();
852
853 if ( $origTitle instanceof Title && $title->isSamePageAs( $origTitle ) && $notCurrentActionView ) {
854 if ( $query !== '' ) {
855 $query .= '&redirect=no';
856 } else {
857 $query = 'redirect=no';
858 }
859 }
860 }
861
862 if ( $message instanceof MessageSpecifier ) {
863 $msg = new Message( $message );
864 } else {
865 // wfMessageFallback will nicely accept $message as an array of fallbacks
866 // or just a single key
867 $msg = wfMessageFallback( $message );
868 }
869 $msg->setContext( $this->getContext() );
870 if ( !$msg->isDisabled() ) {
871 $text = $msg->text();
872 } else {
873 $text = $services->getLanguageConverterFactory()
874 ->getLanguageConverter( $services->getContentLanguage() )
875 ->convertNamespace(
876 $services->getNamespaceInfo()
877 ->getSubject( $title->getNamespace() )
878 );
879 }
880
881 $result = [
882 // Use a string instead of a class list for hook compatibility (T393504)
883 'class' => implode( ' ', $classes ),
884 'text' => $text,
885 'href' => $title->getLocalURL( $query ),
886 'exists' => $exists,
887 'primary' => true ];
888 if ( $linkClass !== '' ) {
889 $result['link-class'] = trim( $linkClass );
890 }
891
892 return $result;
893 }
894
902 private function getSkinNavOverrideableLabel( $labelMessageKey, $param = null ) {
903 $skname = $this->skinname;
904 // The following messages can be used here:
905 // * skin-action-addsection
906 // * skin-action-delete
907 // * skin-action-move
908 // * skin-action-protect
909 // * skin-action-undelete
910 // * skin-action-unprotect
911 // * skin-action-viewdeleted
912 // * skin-action-viewsource
913 // * skin-view-create
914 // * skin-view-create-local
915 // * skin-view-edit
916 // * skin-view-edit-local
917 // * skin-view-foreign
918 // * skin-view-history
919 // * skin-view-view
920 $msg = wfMessageFallback(
921 "$skname-$labelMessageKey",
922 "skin-$labelMessageKey"
923 )->setContext( $this->getContext() );
924
925 if ( $param ) {
926 if ( is_numeric( $param ) ) {
927 $msg->numParams( $param );
928 } else {
929 $msg->params( $param );
930 }
931 }
932 return $msg->text();
933 }
934
940 private function makeTalkUrlDetails( $name, $urlaction = '' ) {
941 $title = Title::newFromTextThrow( $name )->getTalkPage();
942 return [
943 'href' => $title->getLocalURL( $urlaction ),
944 'exists' => $title->isKnown(),
945 ];
946 }
947
957 private function getWatchLinkAttrs(
958 string $mode, Authority $performer, Title $title, ?string $action, bool $onPage
959 ): array {
960 $isWatchMode = $action == 'watch';
961 $class = 'mw-watchlink ' . (
962 $onPage && ( $isWatchMode || $action == 'unwatch' ) ? 'selected' : ''
963 );
964
965 $services = MediaWikiServices::getInstance();
966 $watchlistManager = $services->getWatchlistManager();
967 $watchIcon = $mode === 'unwatch' ? 'unStar' : 'star';
968 $watchExpiry = null;
969 // Modify tooltip and add class identifying the page is temporarily watched, if applicable.
970 if ( $this->getConfig()->get( MainConfigNames::WatchlistExpiry ) &&
971 $watchlistManager->isTempWatched( $performer, $title )
972 ) {
973 $class .= ' mw-watchlink-temp';
974 $watchIcon = 'halfStar';
975
976 $watchStore = $services->getWatchedItemStore();
977 $watchedItem = $watchStore->getWatchedItem( $performer->getUser(), $title );
978 $diffInDays = $watchedItem->getExpiryInDays();
979 $watchExpiry = $watchedItem->getExpiry( TS::ISO_8601 );
980 if ( $diffInDays ) {
981 $msgParams = [ $diffInDays ];
982 // Resolves to tooltip-ca-unwatch-expiring message
983 $tooltip = 'ca-unwatch-expiring';
984 } else {
985 // Resolves to tooltip-ca-unwatch-expiring-hours message
986 $tooltip = 'ca-unwatch-expiring-hours';
987 }
988 }
989
990 return [
991 'class' => $class,
992 'icon' => $watchIcon,
993 // uses 'watch' or 'unwatch' message
994 'text' => $this->msg( $mode )->text(),
995 'single-id' => $tooltip ?? null,
996 'tooltip-params' => $msgParams ?? null,
997 'href' => $title->getLocalURL( [ 'action' => $mode ] ),
998 // Set a data-mw-interface attribute, which the mediawiki.page.ajax
999 // module will look for to make sure it's a trusted link
1000 'data' => [
1001 'mw-interface' => '1',
1002 'mw-expiry' => $watchExpiry,
1003 ],
1004 ];
1005 }
1006
1016 protected function runOnSkinTemplateNavigationHooks( SkinTemplate $skin, &$content_navigation ) {
1017 $beforeHookAssociatedPages = array_keys( $content_navigation['associated-pages'] ?? [] );
1018 $beforeHookNamespaces = array_keys( $content_navigation['namespaces'] ?? [] );
1019 $fallbackNeeded = count( $beforeHookAssociatedPages ) === count( $beforeHookNamespaces );
1020
1021 // Equiv to SkinTemplateContentActions, run
1022 $this->getHookRunner()->onSkinTemplateNavigation__Universal(
1023 $skin, $content_navigation );
1024 if ( !$fallbackNeeded ) {
1025 return;
1026 }
1027 // The new `associatedPages` menu (added in 1.39)
1028 // should be backwards compatible with `namespaces`.
1029 // To do this we look for hook modifications to both keys. If modifications are not
1030 // made the new key, but are made to the old key, associatedPages reverts back to the
1031 // links in the namespaces menu.
1032 // It's expected in future that `namespaces` menu will become an alias for `associatedPages`
1033 // at which point this code can be removed.
1034 $afterHookNamespaces = array_keys( $content_navigation[ 'namespaces' ] ?? [] );
1035 $afterHookAssociatedPages = array_keys( $content_navigation[ 'associated-pages' ] ?? [] );
1036 $associatedPagesChanged = count( array_diff( $afterHookAssociatedPages, $beforeHookAssociatedPages ) ) > 0;
1037 $namespacesChanged = count( array_diff( $afterHookNamespaces, $beforeHookNamespaces ) ) > 0;
1038 // If some change occurred to namespaces via the hook, revert back to namespaces.
1039 if ( !$associatedPagesChanged && $namespacesChanged ) {
1041 'Modification of the `namespaces` menu using SkinTemplateNavigation__Universal is ' .
1042 'now deprecated. Please use `associated-pages` instead.',
1043 '1.46'
1044 );
1045 $content_navigation['associated-pages'] = $content_navigation['namespaces'];
1046 }
1047 }
1048
1083 private function buildContentNavigationUrlsInternal() {
1084 if ( $this->contentNavigationCached ) {
1085 return $this->contentNavigationCached;
1086 }
1087 // Display tabs for the relevant title rather than always the title itself
1088 $title = $this->getRelevantTitle();
1089 $onPage = $title->equals( $this->getTitle() );
1090
1091 $out = $this->getOutput();
1092 $request = $this->getRequest();
1093 $performer = $this->getAuthority();
1094 $action = $this->getContext()->getActionName();
1095 $services = MediaWikiServices::getInstance();
1096 $permissionManager = $services->getPermissionManager();
1097 $categoriesData = $this->getCategoryPortletsData( $this->getOutput()->getCategoryLinks() );
1098 $userPageLink = [];
1099 $this->addPersonalPageItem( $userPageLink, '-2' );
1100
1101 $userMenu = $this->buildPersonalUrls( false );
1102 $requestedMenus = $this->getOptions()['menus'];
1103 if ( in_array( 'user-page', $requestedMenus ) ) {
1104 unset( $userMenu['userpage' ] );
1105 }
1106 $legacySupportNamespaces = in_array( 'namespaces', $requestedMenus );
1107 $legacyUserMenuSupport = in_array( 'personal', $requestedMenus );
1108 $content_navigation = $categoriesData + [
1109 // Modern keys: Please ensure these get unset inside Skin::prepareQuickTemplate
1110 'user-interface-preferences' => [],
1111 'user-page' => $userPageLink,
1112 'user-menu' => $userMenu,
1113 'notifications' => [],
1114 'associated-pages' => [],
1115 // Added in 1.44: a fixed position menu at bottom of page
1116 'dock-bottom' => [],
1117 // Legacy keys
1118 'views' => [],
1119 'actions' => [],
1120 'variants' => [],
1121 ];
1122 if ( $legacySupportNamespaces ) {
1123 $content_navigation['namespaces'] = [];
1124 }
1125
1126 $associatedPages = [];
1127 $namespaces = [];
1128 $userCanRead = $this->getAuthority()->probablyCan( 'read', $title );
1129
1130 // Checks if page is some kind of content
1131 if ( $title->canExist() ) {
1132 // Gets page objects for the associatedPages namespaces
1133 $subjectPage = $title->getSubjectPage();
1134 $talkPage = $title->getTalkPage();
1135
1136 // Determines if this is a talk page
1137 $isTalk = $title->isTalkPage();
1138
1139 // Generates XML IDs from namespace names
1140 $subjectId = $title->getNamespaceKey( '' );
1141
1142 if ( $subjectId == 'main' ) {
1143 $talkId = 'talk';
1144 } else {
1145 $talkId = "{$subjectId}_talk";
1146 }
1147
1148 // Adds namespace links
1149 if ( $subjectId === 'user' ) {
1150 $subjectMsg = $this->msg( 'nstab-user', $subjectPage->getRootText() );
1151 } else {
1152 // The following messages are used here:
1153 // * nstab-main
1154 // * nstab-media
1155 // * nstab-special
1156 // * nstab-project
1157 // * nstab-image
1158 // * nstab-mediawiki
1159 // * nstab-template
1160 // * nstab-help
1161 // * nstab-category
1162 // * nstab-<subject namespace key>
1163 $subjectMsg = [ "nstab-$subjectId" ];
1164
1165 if ( $subjectPage->isMainPage() ) {
1166 array_unshift( $subjectMsg, 'nstab-mainpage' );
1167 }
1168 }
1169
1170 $associatedPages[$subjectId] = $this->tabAction(
1171 $subjectPage, $subjectMsg, !$isTalk, '', $userCanRead
1172 );
1173 $associatedPages[$subjectId]['context'] = 'subject';
1174 // Use the following messages if defined or talk if not:
1175 // * nstab-talk, nstab-user_talk, nstab-media_talk, nstab-project_talk
1176 // * nstab-image_talk, nstab-mediawiki_talk, nstab-template_talk
1177 // * nstab-help_talk, nstab-category_talk,
1178 // * nstab-<subject namespace key>_talk
1179 $associatedPages[$talkId] = $this->tabAction(
1180 $talkPage, [ "nstab-$talkId", "talk" ], $isTalk, '', $userCanRead
1181 );
1182 $associatedPages[$talkId]['context'] = 'talk';
1183
1184 if ( $userCanRead ) {
1185 // Adds "view" view link
1186 if ( $title->isKnown() ) {
1187 $content_navigation['views']['view'] = $this->tabAction(
1188 $isTalk ? $talkPage : $subjectPage,
1189 'view-view',
1190 ( $onPage && ( $action == 'view' || $action == 'purge' ) ), '', true
1191 );
1192 $content_navigation['views']['view']['text'] = $this->getSkinNavOverrideableLabel(
1193 'view-view'
1194 );
1195 $content_navigation['views']['view']['icon'] = 'eye';
1196 // signal to hide this from simple content_actions
1197 $content_navigation['views']['view']['redundant'] = true;
1198 }
1199
1200 $page = $this->canUseWikiPage() ? $this->getWikiPage() : false;
1201 $isRemoteContent = $page && !$page->isLocal();
1202
1203 // If it is a non-local file, show a link to the file in its own repository
1204 // @todo abstract this for remote content that isn't a file
1205 if ( $isRemoteContent ) {
1206 $content_navigation['views']['view-foreign'] = [
1207 'text' => $this->getSkinNavOverrideableLabel(
1208 'view-foreign', $page->getWikiDisplayName()
1209 ),
1210 'icon' => 'eye',
1211 'href' => $page->getSourceURL(),
1212 'primary' => false,
1213 ];
1214 }
1215
1216 // Checks if user can edit the current page if it exists or create it otherwise
1217 if ( $this->getAuthority()->probablyCan( 'edit', $title ) ) {
1218 // Builds CSS class for talk page links
1219 $isTalkClass = $isTalk ? ' istalk' : '';
1220 // Whether the user is editing the page
1221 $isEditing = $onPage && ( $action == 'edit' || $action == 'submit' );
1222 $isRedirect = $page && $page->isRedirect();
1223 // Whether to show the "Add a new section" tab
1224 $showNewSection = !$out->getOutputFlag( ParserOutputFlags::HIDE_NEW_SECTION ) && (
1225 (
1226 $isTalk && !$isRedirect && $out->isRevisionCurrent()
1227 ) ||
1228 $out->getOutputFlag( ParserOutputFlags::NEW_SECTION )
1229 );
1230 $section = $request->getVal( 'section' );
1231
1232 if ( $title->exists()
1233 || ( $title->inNamespace( NS_MEDIAWIKI )
1234 && $title->getDefaultMessageText() !== false
1235 )
1236 ) {
1237 $msgKey = $isRemoteContent ? 'edit-local' : 'edit';
1238 } else {
1239 $msgKey = $isRemoteContent ? 'create-local' : 'create';
1240 }
1241 $content_navigation['views']['edit'] = [
1242 'class' => ( $isEditing && ( $section !== 'new' || !$showNewSection )
1243 ? 'selected'
1244 : null
1245 ) . $isTalkClass,
1246 'icon' => 'edit',
1247 'text' => $this->getSkinNavOverrideableLabel(
1248 "view-$msgKey"
1249 ),
1250 'single-id' => "ca-$msgKey",
1251 'href' => $title->getLocalURL( $this->editUrlOptions() ),
1252 'primary' => !$isRemoteContent, // don't collapse this in vector
1253 ];
1254
1255 // section link
1256 if ( $showNewSection ) {
1257 // Adds new section link
1258 // $content_navigation['actions']['addsection']
1259 $content_navigation['views']['addsection'] = [
1260 'class' => ( $isEditing && $section == 'new' ) ? 'selected' : null,
1261 'text' => $this->getSkinNavOverrideableLabel(
1262 "action-addsection"
1263 ),
1264 'icon' => 'speechBubbleAdd',
1265 'href' => $title->getLocalURL( 'action=edit&section=new' )
1266 ];
1267 }
1268 // Checks if the page has some kind of viewable source content
1269 } elseif ( $title->hasSourceText() ) {
1270 // Adds view source view link
1271 $content_navigation['views']['viewsource'] = [
1272 'class' => ( $onPage && $action == 'edit' ) ? 'selected' : null,
1273 'text' => $this->getSkinNavOverrideableLabel(
1274 "action-viewsource"
1275 ),
1276 'icon' => 'editLock',
1277 'href' => $title->getLocalURL( $this->editUrlOptions() ),
1278 'primary' => true, // don't collapse this in vector
1279 ];
1280 }
1281
1282 // Checks if the page exists
1283 if ( $title->exists() ) {
1284 // Adds history view link
1285 $content_navigation['views']['history'] = [
1286 'class' => ( $onPage && $action == 'history' ) ? 'selected' : null,
1287 'text' => $this->getSkinNavOverrideableLabel(
1288 'view-history'
1289 ),
1290 'icon' => 'history',
1291 'href' => $title->getLocalURL( 'action=history' ),
1292 ];
1293
1294 if ( $this->getAuthority()->probablyCan( 'delete', $title ) ) {
1295 $content_navigation['actions']['delete'] = [
1296 'icon' => 'trash',
1297 'class' => ( $onPage && $action == 'delete' ) ? 'selected' : null,
1298 'text' => $this->getSkinNavOverrideableLabel(
1299 'action-delete'
1300 ),
1301 'href' => $title->getLocalURL( [
1302 'action' => 'delete',
1303 'oldid' => $title->getLatestRevID(),
1304 ] )
1305 ];
1306 }
1307
1308 if ( $this->getAuthority()->probablyCan( 'move', $title ) ) {
1309 $moveTitle = SpecialPage::getTitleFor( 'Movepage', $title->getPrefixedDBkey() );
1310 $content_navigation['actions']['move'] = [
1311 'class' => $this->getTitle()->isSpecial( 'Movepage' ) ? 'selected' : null,
1312 'text' => $this->getSkinNavOverrideableLabel(
1313 'action-move'
1314 ),
1315 'icon' => 'move',
1316 'href' => $moveTitle->getLocalURL()
1317 ];
1318 }
1319 } else {
1320 // article doesn't exist or is deleted
1321 if ( $this->getAuthority()->probablyCan( 'deletedhistory', $title ) ) {
1322 $n = $title->getDeletedEditsCount();
1323 if ( $n ) {
1324 $undelTitle = SpecialPage::getTitleFor( 'Undelete', $title->getPrefixedDBkey() );
1325 // If the user can't undelete but can view deleted
1326 // history show them a "View .. deleted" tab instead.
1327 $msgKey = $this->getAuthority()->probablyCan( 'undelete', $title ) ?
1328 'undelete' : 'viewdeleted';
1329 $content_navigation['actions']['undelete'] = [
1330 'class' => $this->getTitle()->isSpecial( 'Undelete' ) ? 'selected' : null,
1331 'text' => $this->getSkinNavOverrideableLabel(
1332 "action-$msgKey", $n
1333 ),
1334 'icon' => 'trash',
1335 'href' => $undelTitle->getLocalURL()
1336 ];
1337 }
1338 }
1339 }
1340
1341 $restrictionStore = $services->getRestrictionStore();
1342 if ( $this->getAuthority()->probablyCan( 'protect', $title ) &&
1343 $restrictionStore->listApplicableRestrictionTypes( $title ) &&
1344 $permissionManager->getNamespaceRestrictionLevels(
1345 $title->getNamespace(),
1346 $performer->getUser()
1347 ) !== [ '' ]
1348 ) {
1349 $isProtected = $restrictionStore->isProtected( $title );
1350 $mode = $isProtected ? 'unprotect' : 'protect';
1351 $content_navigation['actions'][$mode] = [
1352 'class' => ( $onPage && $action == $mode ) ? 'selected' : null,
1353 'text' => $this->getSkinNavOverrideableLabel(
1354 "action-$mode"
1355 ),
1356 'icon' => $isProtected ? 'unLock' : 'lock',
1357 'href' => $title->getLocalURL( "action=$mode" )
1358 ];
1359 }
1360
1361 if ( $this->loggedin && $this->getAuthority()
1362 ->isAllowedAll( 'viewmywatchlist', 'editmywatchlist' )
1363 ) {
1373 $mode = MediaWikiServices::getInstance()->getWatchlistManager()
1374 ->isWatched( $performer, $title ) ? 'unwatch' : 'watch';
1375
1376 // Add the watch/unwatch link.
1377 $content_navigation['actions'][$mode] = $this->getWatchLinkAttrs(
1378 $mode,
1379 $performer,
1380 $title,
1381 $action,
1382 $onPage
1383 );
1384 }
1385 }
1386
1387 // Add language variants
1388 $languageConverterFactory = MediaWikiServices::getInstance()->getLanguageConverterFactory();
1389
1390 if ( $userCanRead && !$languageConverterFactory->isConversionDisabled() ) {
1391 $pageLang = $title->getPageLanguage();
1392 $converter = $languageConverterFactory
1393 ->getLanguageConverter( $pageLang );
1394 // Checks that language conversion is enabled and variants exist
1395 // And if it is not in the special namespace
1396 if ( $converter->hasVariants() ) {
1397 // Gets list of language variants
1398 $variants = $converter->getVariants();
1399 // Gets preferred variant (note that user preference is
1400 // only possible for wiki content language variant)
1401 $preferred = $converter->getPreferredVariant();
1402 if ( $action === 'view' ) {
1403 $params = $request->getQueryValues();
1404 unset( $params['title'] );
1405 } else {
1406 $params = [];
1407 }
1408 // Loops over each variant
1409 foreach ( $variants as $code ) {
1410 // Gets variant name from language code
1411 $varname = $pageLang->getVariantname( $code );
1412 // Appends variant link
1413 $content_navigation['variants'][] = [
1414 'class' => ( $code == $preferred ) ? 'selected' : null,
1415 'text' => $varname,
1416 'href' => $title->getLocalURL( [ 'variant' => $code ] + $params ),
1417 'lang' => LanguageCode::bcp47( $code ),
1418 'hreflang' => LanguageCode::bcp47( $code ),
1419 ];
1420 }
1421 }
1422 }
1423 $namespaces = $associatedPages;
1424 } else {
1425 // If it's not content, and a request URL is set it's got to be a special page
1426 try {
1427 $url = $request->getRequestURL();
1428 } catch ( MWException ) {
1429 $url = false;
1430 }
1431 $namespaces['special'] = [
1432 'class' => 'selected',
1433 'text' => $this->msg( 'nstab-special' )->text(),
1434 'href' => $url, // @see: T4457, T4510
1435 'context' => 'subject'
1436 ];
1437 $associatedPages += $this->getSpecialPageAssociatedNavigationLinks( $title );
1438 }
1439
1440 if ( $legacySupportNamespaces ) {
1441 $content_navigation['namespaces'] = $namespaces;
1442 }
1443 $content_navigation['associated-pages'] = $associatedPages;
1444 $this->runOnSkinTemplateNavigationHooks( $this, $content_navigation );
1445
1446 // Setup xml ids and tooltip info
1447 foreach ( $content_navigation as $section => &$links ) {
1448 foreach ( $links as $key => &$link ) {
1449 // Allow links to set their own id for backwards compatibility reasons.
1450 if ( isset( $link['id'] ) || isset( $link['html' ] ) ) {
1451 continue;
1452 }
1453 $xmlID = $key;
1454 if ( isset( $link['context'] ) && $link['context'] == 'subject' ) {
1455 $xmlID = 'ca-nstab-' . $xmlID;
1456 } elseif ( isset( $link['context'] ) && $link['context'] == 'talk' ) {
1457 $xmlID = 'ca-talk';
1458 $link['rel'] = 'discussion';
1459 } elseif ( $section == 'variants' ) {
1460 $xmlID = 'ca-varlang-' . $xmlID;
1461 $link['class'] .= ' ca-variants-' . $link['lang'];
1462 } else {
1463 $xmlID = 'ca-' . $xmlID;
1464 }
1465 $link['id'] = $xmlID;
1466 }
1467 }
1468
1469 # We don't want to give the watch tab an accesskey if the
1470 # page is being edited, because that conflicts with the
1471 # accesskey on the watch checkbox. We also don't want to
1472 # give the edit tab an accesskey, because that's fairly
1473 # superfluous and conflicts with an accesskey (Ctrl-E) often
1474 # used for editing in Safari.
1475 if ( in_array( $action, [ 'edit', 'submit' ] ) ) {
1476 if ( isset( $content_navigation['views']['edit'] ) ) {
1477 $content_navigation['views']['edit']['tooltiponly'] = true;
1478 }
1479 if ( isset( $content_navigation['actions']['watch'] ) ) {
1480 $content_navigation['actions']['watch']['tooltiponly'] = true;
1481 }
1482 if ( isset( $content_navigation['actions']['unwatch'] ) ) {
1483 $content_navigation['actions']['unwatch']['tooltiponly'] = true;
1484 }
1485 }
1486
1487 $this->contentNavigationCached = $content_navigation;
1488 return $content_navigation;
1489 }
1490
1498 private function getSpecialPageAssociatedNavigationLinks( Title $title ): array {
1499 $specialAssociatedNavigationLinks = [];
1500 $specialFactory = MediaWikiServices::getInstance()->getSpecialPageFactory();
1501 $special = $specialFactory->getPage( $title->getText() );
1502 if ( $special === null ) {
1503 // not a valid special page
1504 return [];
1505 }
1506 $special->setContext( $this );
1507 $associatedNavigationLinks = $special->getAssociatedNavigationLinks();
1508 // If there are no subpages, we should not render
1509 if ( count( $associatedNavigationLinks ) === 0 ) {
1510 return [];
1511 }
1512
1513 foreach ( $associatedNavigationLinks as $i => $relatedTitleText ) {
1514 $relatedTitle = Title::newFromText( $relatedTitleText );
1515 $special = $specialFactory->getPage( $relatedTitle->getText() );
1516 if ( $special === null ) {
1517 $text = $relatedTitle->getText();
1518 } else {
1519 $text = $special->getShortDescription( $relatedTitle->getSubpageText() );
1520 }
1521 $specialAssociatedNavigationLinks['special-specialAssociatedNavigationLinks-link-' . $i ] = [
1522 'text' => $text,
1523 'href' => $relatedTitle->fixSpecialName()->getLocalURL(),
1524 'class' => $relatedTitle->fixSpecialName()->equals( $title->fixSpecialName() ) ? 'selected' : null,
1525 ];
1526 }
1527 return $specialAssociatedNavigationLinks;
1528 }
1529
1535 private function buildContentActionUrls( $content_navigation ) {
1536 // content_actions has been replaced with content_navigation for backwards
1537 // compatibility and also for skins that just want simple tabs content_actions
1538 // is now built by flattening the content_navigation arrays into one
1539
1540 $content_actions = [];
1541
1542 foreach ( $content_navigation as $links ) {
1543 foreach ( $links as $key => $value ) {
1544 if ( isset( $value['redundant'] ) && $value['redundant'] ) {
1545 // Redundant tabs are dropped from content_actions
1546 continue;
1547 }
1548
1549 // content_actions used to have ids built using the "ca-$key" pattern
1550 // so the xmlID based id is much closer to the actual $key that we want
1551 // for that reason we'll just strip out the ca- if present and use
1552 // the latter potion of the "id" as the $key
1553 if ( isset( $value['id'] ) && str_starts_with( $value['id'], 'ca-' ) ) {
1554 $key = substr( $value['id'], 3 );
1555 }
1556
1557 if ( isset( $content_actions[$key] ) ) {
1558 wfDebug( __METHOD__ . ": Found a duplicate key for $key while flattening " .
1559 "content_navigation into content_actions." );
1560 continue;
1561 }
1562
1563 $content_actions[$key] = $value;
1564 }
1565 }
1566
1567 return $content_actions;
1568 }
1569
1579 final protected function injectLegacyMenusIntoPersonalTools(
1580 array $contentNavigation
1581 ): array {
1582 wfDeprecated( __METHOD__, '1.46', 'Please make sure Skin option menus contains `user-menu` '
1583 . '(and possibly `notifications`, `user-interface-preferences`, `user-page`)' );
1584 $userMenu = $contentNavigation['user-menu'] ?? [];
1585 if ( isset( $contentNavigation['user-page']['userpage'] ) ) {
1586 $userMenu = [
1587 'userpage' => $contentNavigation['user-page']['userpage'],
1588 ] + $userMenu;
1589 }
1590
1591 // userpage is only defined for logged-in users, and ArrayUtils::insertAfter requires the
1592 // $after parameter to be a known key in the array.
1593 if ( isset( $userMenu['userpage'] ) && isset( $contentNavigation['notifications'] ) ) {
1594 $userMenu = ArrayUtils::insertAfter(
1595 $userMenu,
1596 $contentNavigation['notifications'],
1597 'userpage'
1598 );
1599 }
1600 if ( isset( $contentNavigation['user-interface-preferences'] ) ) {
1601 return array_merge(
1602 $contentNavigation['user-interface-preferences'],
1603 $userMenu
1604 );
1605 }
1606 return $userMenu;
1607 }
1608
1617 private function makeSkinTemplatePersonalUrls(
1618 array $contentNavigation
1619 ): array {
1620 if ( isset( $contentNavigation['user-menu'] ) ) {
1621 return $this->injectLegacyMenusIntoPersonalTools( $contentNavigation );
1622 }
1623 return [];
1624 }
1625
1632 public function makeSearchInput( $attrs = [] ) {
1633 // It's possible that getTemplateData might be calling
1634 // Skin::makeSearchInput. To avoid infinite recursion create a
1635 // new instance of the search component here.
1636 $searchBox = $this->getComponent( 'search-box' );
1637 $data = $searchBox->getTemplateData();
1638
1639 return Html::element( 'input',
1640 $data[ 'array-input-attributes' ] + $attrs
1641 );
1642 }
1643
1651 final public function makeSearchButton( $mode, $attrs = [] ) {
1652 // It's possible that getTemplateData might be calling
1653 // Skin::makeSearchInput. To avoid infinite recursion create a
1654 // new instance of the search component here.
1655 $searchBox = $this->getComponent( 'search-box' );
1656 $searchData = $searchBox->getTemplateData();
1657
1658 switch ( $mode ) {
1659 case 'go':
1660 $attrs['value'] ??= $this->msg( 'searcharticle' )->text();
1661 return Html::element(
1662 'input',
1663 array_merge(
1664 $searchData[ 'array-button-go-attributes' ], $attrs
1665 )
1666 );
1667 case 'fulltext':
1668 $attrs['value'] ??= $this->msg( 'searchbutton' )->text();
1669 return Html::element(
1670 'input',
1671 array_merge(
1672 $searchData[ 'array-button-fulltext-attributes' ], $attrs
1673 )
1674 );
1675 case 'image':
1676 $buttonAttrs = [
1677 'type' => 'submit',
1678 'name' => 'button',
1679 ];
1680 $buttonAttrs = array_merge(
1681 $buttonAttrs,
1682 Linker::tooltipAndAccesskeyAttribs( 'search-fulltext' ),
1683 $attrs
1684 );
1685 unset( $buttonAttrs['src'] );
1686 unset( $buttonAttrs['alt'] );
1687 unset( $buttonAttrs['width'] );
1688 unset( $buttonAttrs['height'] );
1689 $imgAttrs = [
1690 'src' => $attrs['src'],
1691 'alt' => $attrs['alt'] ?? $this->msg( 'searchbutton' )->text(),
1692 'width' => $attrs['width'] ?? null,
1693 'height' => $attrs['height'] ?? null,
1694 ];
1695 return Html::rawElement( 'button', $buttonAttrs, Html::element( 'img', $imgAttrs ) );
1696 default:
1697 throw new InvalidArgumentException( 'Unknown mode passed to ' . __METHOD__ );
1698 }
1699 }
1700
1701 private function isSpecialContributeShowable(): bool {
1702 return ContributeFactory::isEnabledOnCurrentSkin(
1703 $this,
1704 $this->getConfig()->get( MainConfigNames::SpecialContributeSkinsEnabled )
1705 );
1706 }
1707
1716 private function makeContributionsLink(
1717 array &$personal_urls,
1718 string $key,
1719 ?string $userName = null,
1720 bool $active = false
1721 ): array {
1722 $isSpecialContributeShowable = $this->isSpecialContributeShowable();
1723 $subpage = $userName ?? false;
1724 $user = $this->getUser();
1725 // If the "Contribute" page is showable and the user is anon. or has no edit count,
1726 // direct them to the "Contribute" page instead of the "Contributions" or "Mycontributions" pages.
1727 // Explanation:
1728 // a. For logged-in users: In wikis where the "Contribute" page is enabled, we only want
1729 // to navigate logged-in users to the "Contribute", when they have done no edits. Otherwise, we
1730 // want to navigate them to the "Mycontributions" page to easily access their edits/contributions.
1731 // Currently, the "Contribute" page is used as target for all logged-in users.
1732 // b. For anon. users: In wikis where the "Contribute" page is enabled, we still navigate the
1733 // anonymous users to the "Contribute" page.
1734 // Task: T369041
1735 if ( $isSpecialContributeShowable && (int)$user->getEditCount() === 0 ) {
1736 $href = SkinComponentUtils::makeSpecialUrlSubpage(
1737 'Contribute',
1738 false
1739 );
1740 $personal_urls['contribute'] = [
1741 'text' => $this->msg( 'contribute' )->text(),
1742 'href' => $href,
1743 'active' => $href == $this->getTitle()->getLocalURL(),
1744 'icon' => 'edit'
1745 ];
1746 } else {
1747 $href = SkinComponentUtils::makeSpecialUrlSubpage(
1748 $subpage !== false ? 'Contributions' : 'Mycontributions',
1749 $subpage
1750 );
1751 $personal_urls[$key] = [
1752 'text' => $this->msg( $key )->text(),
1753 'href' => $href,
1754 'active' => $active,
1755 'icon' => 'userContributions'
1756 ];
1757 }
1758 return $personal_urls;
1759 }
1760
1761}
1762
1764class_alias( SkinTemplate::class, 'SkinTemplate' );
const NS_MEDIAWIKI
Definition Defines.php:59
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
wfMessageFallback(... $keys)
This function accepts multiple message keys and returns a message instance for the first message whic...
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:69
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Debug toolbar.
Definition MWDebug.php:35
This class is a collection of static functions that serve two purposes:
Definition Html.php:44
Methods for dealing with language codes.
Some internal bits split of from Skin.php.
Definition Linker.php:47
A class containing constants representing the names of configuration variables.
const StylePath
Name constant for the StylePath setting, for use with Config::get()
const Server
Name constant for the Server setting, for use with Config::get()
const UseCombinedLoginLink
Name constant for the UseCombinedLoginLink setting, for use with Config::get()
const MimeType
Name constant for the MimeType setting, for use with Config::get()
const Sitename
Name constant for the Sitename setting, for use with Config::get()
const ArticlePath
Name constant for the ArticlePath setting, for use with Config::get()
const ScriptPath
Name constant for the ScriptPath setting, for use with Config::get()
const Script
Name constant for the Script 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.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:144
Profiler base class that defines the interface and some shared functionality.
Definition Profiler.php:26
Base class for QuickTemplate-based skins.
buildPersonalUrls(bool $includeNotifications=true)
Build array of urls for personal toolbar.
injectLegacyMenusIntoPersonalTools(array $contentNavigation)
Insert legacy menu items from content navigation into the personal toolbar.
generateHTML()
Subclasses not wishing to use the QuickTemplate render method can rewrite this method,...
runOnSkinTemplateNavigationHooks(SkinTemplate $skin, &$content_navigation)
Run hooks relating to navigation menu data.
setupTemplate( $classname)
Create the template engine object; we feed it a bunch of data and eventually it spits out some HTML.
tabAction( $title, $message, $selected, $query='', $checkEdit=false)
Builds an array with tab definition.
buildPersonalPageItem( $id='pt-userpage')
Build a user page link data.
buildCreateAccountData( $returnto)
Build "Create Account" link data.
makeSearchButton( $mode, $attrs=[])
prepareQuickTemplate()
initialize various variables and generate the template
getTemplateData()
to extend. Subclasses may extend this method to add additional template data. this method should neve...
getCategoryLinks()
Extends category links with Skin::getAfterPortlet functionality.
string $template
For QuickTemplate, the name of the subclass which will actually fill the template.
buildLogoutLinkData()
Build data required for "Logout" link.
outputPage()
Initialize various variables and generate the template.
makePersonalToolsList( $personalTools=null, $options=[])
Get the HTML for the personal tools list.
getStructuredPersonalTools()
Get personal tools for the user.
buildLoginData( $returnto, $useCombinedLoginLink)
Build "Login" link.
bool $loggedin
TODO: Rename this to $isRegistered (but that's a breaking change)
setupTemplateContext()
Setup class properties that are necessary prior to calling setupTemplateForOutput.
useCombinedLoginLink()
Returns if a combined login/signup link will be used.
The base class for all skins.
Definition Skin.php:53
buildNavUrls()
Build array of common navigation links.
Definition Skin.php:1247
array $options
Skin options passed into constructor.
Definition Skin.php:69
buildFeedUrls()
Build data structure representing syndication links.
Definition Skin.php:1452
logoText( $align='')
Definition Skin.php:1043
getJsConfigVars()
Returns array of config variables that should be added only to this skin for use in JavaScript.
Definition Skin.php:2349
getComponent(string $name)
Definition Skin.php:108
static makeKnownUrlDetails( $name, $urlaction='')
Make URL details where the article exists (or at least it's convenient to think so)
Definition Skin.php:1190
prepareUndeleteLink()
Prepare undelete link for output in page.
Definition Skin.php:2391
afterContentHook()
This runs a hook to allow extensions placing their stuff after content and article metadata (e....
Definition Skin.php:851
prepareUserLanguageAttributes()
Prepare user language attribute links.
Definition Skin.php:2380
buildSidebar()
Build an array that represents the sidebar(s), the navigation bar among them.
Definition Skin.php:1492
getOptions()
Get current skin's options.
Definition Skin.php:2423
initPage(OutputPage $out)
Definition Skin.php:376
getPersonalToolsForMakeListItem( $urls, $applyClassesToListItems=false)
Create an array of personal tools items from the data in the quicktemplate stored by SkinTemplate.
Definition Skin.php:2130
wrapHTML( $title, $html)
Wrap the body text with language information and identifiable element.
Definition Skin.php:2404
static makeUrlDetails( $name, $urlaction='')
these return an array with the 'href' and boolean 'exists'
Definition Skin.php:1176
printSource()
Text with the permalink to the source page, usually shown on the footer of a printed page.
Definition Skin.php:895
prepareSubtitle(bool $withContainer=true)
Prepare the subtitle of the page for output in the skin if one has been set.
Definition Skin.php:2330
makeListItem( $key, $item, $options=[])
Generates a list item for a navigation, portlet, portal, sidebar... list.
Definition Skin.php:2285
getFooterIcons()
Get template representation of the footer.
Definition Skin.php:1069
getLanguages()
Generates array of language links for the current page.
Definition Skin.php:1222
getNewtalks()
Gets new talk page messages for the current user and returns an appropriate alert message (or an empt...
Definition Skin.php:1728
Parent class for all special pages.
static newSearchPage(User $user)
Get the users preferred search page.
Represents a title within MediaWiki.
Definition Title.php:69
isSamePageAs(PageReference $other)
Checks whether the given PageReference refers to the same page as this PageReference....
Definition Title.php:3100
isSpecialPage()
Returns true if this is a special page.
Definition Title.php:1246
isTempWatched(Authority $performer, PageReference $target)
Check if the page is temporarily watched by the user and the user has permission to view their watchl...
A collection of static methods to play with arrays.
Value object representing a message parameter with one of the types from {.
return[ 'config-schema-inverse'=>['default'=>['ConfigRegistry'=>['main'=> 'MediaWiki\\Config\\GlobalVarConfig::newInstance',], 'Sitename'=> 'MediaWiki', 'Server'=> false, 'CanonicalServer'=> false, 'ServerName'=> false, 'AssumeProxiesUseDefaultProtocolPorts'=> true, 'HttpsPort'=> 443, 'ForceHTTPS'=> false, 'ScriptPath'=> '/wiki', 'UsePathInfo'=> null, 'Script'=> false, 'LoadScript'=> false, 'RestPath'=> false, 'StylePath'=> false, 'LocalStylePath'=> false, 'ExtensionAssetsPath'=> false, 'ExtensionDirectory'=> null, 'StyleDirectory'=> null, 'ArticlePath'=> false, 'UploadPath'=> false, 'ImgAuthPath'=> false, 'ThumbPath'=> false, 'UploadDirectory'=> false, 'FileCacheDirectory'=> false, 'Logo'=> false, 'Logos'=> false, 'Favicon'=> '/favicon.ico', 'AppleTouchIcon'=> false, 'ReferrerPolicy'=> false, 'TmpDirectory'=> false, 'UploadBaseUrl'=> '', 'UploadStashScalerBaseUrl'=> false, 'ActionPaths'=>[], 'MainPageIsDomainRoot'=> false, 'EnableUploads'=> false, 'UploadStashMaxAge'=> 21600, 'EnableAsyncUploads'=> false, 'EnableAsyncUploadsByURL'=> false, 'UploadMaintenance'=> false, 'IllegalFileChars'=> ':\\/\\\\', 'DeletedDirectory'=> false, 'ImgAuthDetails'=> false, 'ImgAuthUrlPathMap'=>[], 'LocalFileRepo'=>['class'=> 'MediaWiki\\FileRepo\\LocalRepo', 'name'=> 'local', 'directory'=> null, 'scriptDirUrl'=> null, 'favicon'=> null, 'url'=> null, 'hashLevels'=> null, 'thumbScriptUrl'=> null, 'transformVia404'=> null, 'deletedDir'=> null, 'deletedHashLevels'=> null, 'updateCompatibleMetadata'=> null, 'reserializeMetadata'=> null,], 'ForeignFileRepos'=>[], 'UseInstantCommons'=> false, 'UseSharedUploads'=> false, 'SharedUploadDirectory'=> null, 'SharedUploadPath'=> null, 'HashedSharedUploadDirectory'=> true, 'RepositoryBaseUrl'=> 'https:'FetchCommonsDescriptions'=> false, 'SharedUploadDBname'=> false, 'SharedUploadDBprefix'=> '', 'CacheSharedUploads'=> true, 'ForeignUploadTargets'=>['local',], 'UploadDialog'=>['fields'=>['description'=> true, 'date'=> false, 'categories'=> false,], 'licensemessages'=>['local'=> 'generic-local', 'foreign'=> 'generic-foreign',], 'comment'=>['local'=> '', 'foreign'=> '',], 'format'=>['filepage'=> ' $DESCRIPTION', 'description'=> ' $TEXT', 'ownwork'=> '', 'license'=> '', 'uncategorized'=> '',],], 'FileBackends'=>[], 'LockManagers'=>[], 'ShowEXIF'=> null, 'UpdateCompatibleMetadata'=> false, 'AllowCopyUploads'=> false, 'CopyUploadsDomains'=>[], 'CopyUploadsFromSpecialUpload'=> false, 'CopyUploadProxy'=> false, 'CopyUploadTimeout'=> false, 'CopyUploadAllowOnWikiDomainConfig'=> false, 'MaxUploadSize'=> 104857600, 'MinUploadChunkSize'=> 1024, 'UploadNavigationUrl'=> false, 'UploadMissingFileUrl'=> false, 'ThumbnailScriptPath'=> false, 'SharedThumbnailScriptPath'=> false, 'HashedUploadDirectory'=> true, 'CSPUploadEntryPoint'=> true, 'FileExtensions'=>['png', 'gif', 'jpg', 'jpeg', 'webp',], 'ProhibitedFileExtensions'=>['html', 'htm', 'js', 'jsb', 'mhtml', 'mht', 'xhtml', 'xht', 'php', 'phtml', 'php3', 'php4', 'php5', 'phps', 'phar', 'shtml', 'jhtml', 'pl', 'py', 'cgi', 'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl', 'xml',], 'MimeTypeExclusions'=>['text/html', 'application/javascript', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', 'application/x-php', 'text/x-php', 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', 'text/scriptlet', 'application/x-msdownload', 'application/x-msmetafile', 'application/java', 'application/xml', 'text/xml',], 'CheckFileExtensions'=> true, 'StrictFileExtensions'=> true, 'DisableUploadScriptChecks'=> false, 'UploadSizeWarning'=> false, 'TrustedMediaFormats'=>['BITMAP', 'AUDIO', 'VIDEO', 'image/svg+xml', 'application/pdf',], 'MediaHandlers'=>[], 'NativeImageLazyLoading'=> false, 'ParserTestMediaHandlers'=>['image/jpeg'=> 'MockBitmapHandler', 'image/png'=> 'MockBitmapHandler', 'image/gif'=> 'MockBitmapHandler', 'image/tiff'=> 'MockBitmapHandler', 'image/webp'=> 'MockBitmapHandler', 'image/x-ms-bmp'=> 'MockBitmapHandler', 'image/x-bmp'=> 'MockBitmapHandler', 'image/x-xcf'=> 'MockBitmapHandler', 'image/svg+xml'=> 'MockSvgHandler', 'image/vnd.djvu'=> 'MockDjVuHandler',], 'UseImageResize'=> true, 'UseImageMagick'=> false, 'ImageMagickConvertCommand'=> '/usr/bin/convert', 'MaxInterlacingAreas'=>[], 'SharpenParameter'=> '0x0.4', 'SharpenReductionThreshold'=> 0.85, 'ImageMagickTempDir'=> false, 'CustomConvertCommand'=> false, 'JpegTran'=> '/usr/bin/jpegtran', 'JpegPixelFormat'=> 'yuv420', 'JpegQuality'=> 80, 'Exiv2Command'=> '/usr/bin/exiv2', 'Exiftool'=> '/usr/bin/exiftool', 'SVGConverters'=>['ImageMagick'=> ' $path/convert -background "#ffffff00" -thumbnail $widthx$height\\! $input PNG:$output', 'inkscape'=> ' $path/inkscape -w $width -o $output $input', 'batik'=> 'java -Djava.awt.headless=true -jar $path/batik-rasterizer.jar -w $width -d $output $input', 'rsvg'=> ' $path/rsvg-convert -w $width -h $height -o $output $input', 'ImagickExt'=>['SvgHandler::rasterizeImagickExt',],], 'SVGConverter'=> 'ImageMagick', 'SVGConverterPath'=> '', 'SVGMaxSize'=> 5120, 'SVGMetadataCutoff'=> 5242880, 'SVGNativeRendering'=> true, 'SVGNativeRenderingSizeLimit'=> 51200, 'MediaInTargetLanguage'=> true, 'MaxImageArea'=> 12500000, 'MaxAnimatedGifArea'=> 12500000, 'TiffThumbnailType'=>[], 'ThumbnailEpoch'=> '20030516000000', 'AttemptFailureEpoch'=> 1, 'IgnoreImageErrors'=> false, 'GenerateThumbnailOnParse'=> true, 'ShowArchiveThumbnails'=> true, 'EnableAutoRotation'=> null, 'Antivirus'=> null, 'AntivirusSetup'=>['clamav'=>['command'=> 'clamscan --no-summary ', 'codemap'=>[0=> 0, 1=> 1, 52=> -1, ' *'=> false,], 'messagepattern'=> '/.*?:(.*)/sim',],], 'AntivirusRequired'=> true, 'VerifyMimeType'=> true, 'MimeTypeFile'=> 'internal', 'MimeInfoFile'=> 'internal', 'MimeDetectorCommand'=> null, 'TrivialMimeDetection'=> false, 'XMLMimeTypes'=>['http:'svg'=> 'image/svg+xml', 'http:'http:'html'=> 'text/html',], 'ImageLimits'=>[[320, 240,], [640, 480,], [800, 600,], [1024, 768,], [1280, 1024,], [2560, 2048,],], 'ThumbLimits'=>[120, 150, 180, 200, 220, 250, 300, 400,], 'ThumbnailNamespaces'=>[6,], 'ThumbnailSteps'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> false, 'TrackMediaRequestProvenance'=> false, 'DjvuUseBoxedCommand'=> false, 'DjvuDump'=> null, 'DjvuRenderer'=> null, 'DjvuTxt'=> null, 'DjvuPostProcessor'=> 'pnmtojpeg', 'DjvuOutputExtension'=> 'jpg', 'EmergencyContact'=> false, 'PasswordSender'=> false, 'NoReplyAddress'=> false, 'EnableEmail'=> true, 'EnableUserEmail'=> true, 'UserEmailUseReplyTo'=> true, 'PasswordReminderResendTime'=> 24, 'NewPasswordExpiry'=> 604800, 'UserEmailConfirmationTokenExpiry'=> 604800, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, 'EmailConfirmationBanner'=> false, 'EnotifWatchlist'=> false, 'EnotifUserTalk'=> false, 'EnotifRevealEditorAddress'=> false, 'EnotifMinorEdits'=> true, 'EnotifUseRealName'=> false, 'UsersNotifiedOnAllChanges'=>[], 'DBname'=> 'my_wiki', 'DBmwschema'=> null, 'DBprefix'=> '', 'DBserver'=> 'localhost', 'DBport'=> 5432, 'DBuser'=> 'wikiuser', 'DBpassword'=> '', 'DBtype'=> 'mysql', 'DBssl'=> false, 'DBcompress'=> false, 'DBStrictWarnings'=> false, 'DBadminuser'=> null, 'DBadminpassword'=> null, 'SearchType'=> null, 'SearchTypeAlternatives'=> null, 'DBTableOptions'=> 'ENGINE=InnoDB, DEFAULT CHARSET=binary', 'SQLMode'=> '', 'SQLiteDataDir'=> '', 'SharedDB'=> null, 'SharedPrefix'=> false, 'SharedTables'=>['user', 'user_properties', 'user_autocreate_serial',], 'SharedSchema'=> false, 'DBservers'=> false, 'LBFactoryConf'=>['class'=> 'Wikimedia\\Rdbms\\LBFactorySimple',], 'DataCenterUpdateStickTTL'=> 10, 'DBerrorLog'=> false, 'DBerrorLogTZ'=> false, 'LocalDatabases'=>[], 'DatabaseReplicaLagWarning'=> 10, 'DatabaseReplicaLagCritical'=> 30, 'MaxExecutionTimeForExpensiveQueries'=> 0, 'VirtualDomainsMapping'=>[], 'FileSchemaMigrationStage'=> 3, 'ExternalLinksDomainGaps'=>[], 'ContentHandlers'=>['wikitext'=>['class'=> 'MediaWiki\\Content\\WikitextContentHandler', 'services'=>['TitleFactory', 'ParserFactory', 'GlobalIdGenerator', 'LanguageNameUtils', 'LinkRenderer', 'MagicWordFactory', 'ParsoidParserFactory',],], 'javascript'=>['class'=> 'MediaWiki\\Content\\JavaScriptContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> 'MediaWiki\\ObjectCache\\SqlBagOStuff', 'loggroup'=> 'SQLBagOStuff',], 'memcached-php'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPhpBagOStuff', 'loggroup'=> 'memcached',], 'memcached-pecl'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPeclBagOStuff', 'loggroup'=> 'memcached',], 'hash'=>['class'=> 'Wikimedia\\ObjectCache\\HashBagOStuff', 'reportDupes'=> false,], 'apc'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,], 'apcu'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,],], 'WANObjectCache'=>[], 'MicroStashType'=> -1, 'MainStash'=> 1, 'ParsoidCacheConfig'=>['StashType'=> null, 'StashDuration'=> 86400, 'WarmParsoidParserCache'=> false,], 'ParsoidSelectiveUpdateSampleRate'=> 0, 'ParserCacheFilterConfig'=>['pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'JwtSessionCookieIssuer'=> null, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> 'MediaWiki\\Language\\LocalisationCache', 'store'=> 'detect', 'storeClass'=> false, 'storeDirectory'=> false, 'storeServer'=>[], 'forceRecache'=> false, 'manualRecache'=> false,], 'CachePages'=> true, 'CacheEpoch'=> '20030516000000', 'GitInfoCacheDirectory'=> false, 'UseFileCache'=> false, 'FileCacheDepth'=> 2, 'RenderHashAppend'=> '', 'EnableSidebarCache'=> false, 'SidebarCacheExpiry'=> 86400, 'UseGzip'=> false, 'InvalidateCacheOnLocalSettingsChange'=> true, 'ExtensionInfoMTime'=> false, 'EnableRemoteBagOStuffTests'=> false, 'UseCdn'=> false, 'VaryOnXFP'=> false, 'InternalServer'=> false, 'CdnMaxAge'=> 18000, 'CdnMaxageLagged'=> 30, 'CdnMaxageStale'=> 10, 'CdnReboundPurgeDelay'=> 0, 'CdnMaxageSubstitute'=> 60, 'ForcedRawSMaxage'=> 300, 'CdnServers'=>[], 'CdnServersNoPurge'=>[], 'HTCPRouting'=>[], 'HTCPMulticastTTL'=> 1, 'UsePrivateIPs'=> false, 'CdnMatchParameterOrder'=> true, 'LanguageCode'=> 'en', 'GrammarForms'=>[], 'InterwikiMagic'=> true, 'HideInterlanguageLinks'=> false, 'ExtraInterlanguageLinkPrefixes'=>[], 'InterlanguageLinkCodeMap'=>[], 'ExtraLanguageNames'=>[], 'ExtraLanguageCodes'=>['bh'=> 'bho', 'no'=> 'nb', 'simple'=> 'en',], 'DummyLanguageCodes'=>[], 'AllUnicodeFixes'=> false, 'LegacyEncoding'=> false, 'AmericanDates'=> false, 'TranslateNumerals'=> true, 'UseDatabaseMessages'=> true, 'MaxMsgCacheEntrySize'=> 10000, 'DisableLangConversion'=> false, 'DisableTitleConversion'=> false, 'DefaultLanguageVariant'=> false, 'UsePigLatinVariant'=> false, 'DisabledVariants'=>[], 'VariantArticlePath'=> false, 'UseXssLanguage'=> false, 'LoginLanguageSelector'=> false, 'ForceUIMsgAsContentMsg'=>[], 'RawHtmlMessages'=>[], 'Localtimezone'=> null, 'LocalTZoffset'=> null, 'OverrideUcfirstCharacters'=>[], 'MimeType'=> 'text/html', 'Html5Version'=> null, 'EditSubmitButtonLabelPublish'=> false, 'XhtmlNamespaces'=>[], 'SiteNotice'=> '', 'BrowserFormatDetection'=> 'telephone=no', 'SkinMetaTags'=>[], 'DefaultSkin'=> 'vector-2022', 'FallbackSkin'=> 'fallback', 'SkipSkins'=>[], 'DisableOutputCompression'=> false, 'FragmentMode'=>['html5', 'legacy',], 'ExternalInterwikiFragmentMode'=> 'legacy', 'FooterIcons'=>['copyright'=>['copyright'=>[],], 'poweredby'=>['mediawiki'=>['src'=> null, 'url'=> 'https:'alt'=> 'Powered by MediaWiki', 'lang'=> 'en',],],], 'UseCombinedLoginLink'=> false, 'Edititis'=> false, 'Send404Code'=> true, 'ShowRollbackEditCount'=> 10, 'EnableCanonicalServerLink'=> false, 'InterwikiLogoOverride'=>[], 'ResourceModules'=>[], 'ResourceModuleSkinStyles'=>[], 'ResourceLoaderSources'=>[], 'ResourceBasePath'=> null, 'ResourceLoaderMaxage'=>[], 'ResourceLoaderDebug'=> false, 'ResourceLoaderMaxQueryLength'=> false, 'ResourceLoaderValidateJS'=> true, 'ResourceLoaderEnableJSProfiler'=> false, 'ResourceLoaderStorageEnabled'=> true, 'ResourceLoaderStorageVersion'=> 1, 'ResourceLoaderEnableSourceMapLinks'=> true, 'AllowSiteCSSOnRestrictedPages'=> false, 'VueDevelopmentMode'=> false, 'CodexDevelopmentDir'=> null, 'MetaNamespace'=> false, 'MetaNamespaceTalk'=> false, 'CanonicalNamespaceNames'=>[-2=> 'Media', -1=> 'Special', 0=> '', 1=> 'Talk', 2=> 'User', 3=> 'User_talk', 4=> 'Project', 5=> 'Project_talk', 6=> 'File', 7=> 'File_talk', 8=> 'MediaWiki', 9=> 'MediaWiki_talk', 10=> 'Template', 11=> 'Template_talk', 12=> 'Help', 13=> 'Help_talk', 14=> 'Category', 15=> 'Category_talk',], 'ExtraNamespaces'=>[], 'ExtraGenderNamespaces'=>[], 'NamespaceAliases'=>[], 'LegalTitleChars'=> ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', 'CapitalLinks' => true, 'CapitalLinkOverrides' => [ ], 'NamespacesWithSubpages' => [ 1 => true, 2 => true, 3 => true, 4 => true, 5 => true, 7 => true, 8 => true, 9 => true, 10 => true, 11 => true, 12 => true, 13 => true, 15 => true, ], 'NamespacesWithoutAutoSummaries' => [ ], '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, ], 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider', 'services' => [ 'ConnectionProvider', 'UserFactory', ], 'sort' => 0, ], ], 'primaryauth' => [ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', 'UserOptionsLookup', ], 'args' => [ [ 'authoritative' => false, ], ], 'sort' => 0, ], 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'args' => [ [ 'authoritative' => true, ], ], 'sort' => 100, ], ], 'secondaryauth' => [ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider', 'sort' => 100, ], 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'sort' => 200, ], ], ], 'RememberMe' => 'choose', 'ReauthenticateTime' => [ 'default' => 3600, ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'default' => true, ], 'ChangeCredentialsBlacklist' => [ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest', ], 'RemoveCredentialsBlacklist' => [ 'MediaWiki\\Auth\\PasswordAuthenticationRequest', ], 'InvalidPasswordReset' => true, 'PasswordDefault' => 'pbkdf2', 'PasswordConfig' => [ 'A' => [ 'class' => 'MediaWiki\\Password\\MWOldPassword', ], 'B' => [ 'class' => 'MediaWiki\\Password\\MWSaltedPassword', ], 'pbkdf2-legacyA' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'A', 'pbkdf2', ], ], 'pbkdf2-legacyB' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'B', 'pbkdf2', ], ], 'bcrypt' => [ 'class' => 'MediaWiki\\Password\\BcryptPassword', 'cost' => 9, ], 'pbkdf2' => [ 'class' => 'MediaWiki\\Password\\Pbkdf2PasswordUsingOpenSSL', 'algo' => 'sha512', 'cost' => '30000', 'length' => '64', ], 'argon2' => [ 'class' => 'MediaWiki\\Password\\Argon2Password', 'algo' => 'auto', ], ], 'PasswordResetRoutes' => [ 'username' => true, 'email' => true, ], 'MaxSigChars' => 255, 'SignatureValidation' => 'warning', 'SignatureAllowedLintErrors' => [ 'obsolete-tag', ], 'MaxNameChars' => 255, 'ReservedUsernames' => [ 'MediaWiki default', 'Conversion script', 'Maintenance script', 'Template namespace initialisation script', 'ScriptImporter', 'Delete page script', 'Move page script', 'Command line script', 'Unknown user', 'msg:double-redirect-fixer', 'msg:usermessage-editor', 'msg:proxyblocker', 'msg:sorbs', 'msg:spambot_username', 'msg:autochange-username', ], 'DefaultUserOptions' => [ 'ccmeonemails' => 0, 'date' => 'default', 'diffonly' => 0, 'diff-type' => 'table', 'disablemail' => 0, 'editfont' => 'monospace', 'editondblclick' => 0, 'editrecovery' => 0, 'editsectiononrightclick' => 0, 'email-allow-new-users' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'enotifusertalkpages' => 1, 'enotifwatchlistpages' => 1, 'extendwatchlist' => 1, 'fancysig' => 0, 'forceeditsummary' => 0, 'forcesafemode' => 0, 'gender' => 'unknown', 'hidecategorization' => 1, 'hideminor' => 0, 'hidepatrolled' => 0, 'imagesize' => 2, 'minordefault' => 0, 'newpageshidepatrolled' => 0, 'nickname' => '', 'norollbackdiff' => 0, 'prefershttps' => 1, 'previewonfirst' => 0, 'previewontop' => 1, 'pst-cssjs' => 1, 'rcdays' => 7, 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'requireemail' => 0, 'search-match-redirect' => true, 'search-special-page' => 'Search', 'search-thumbnail-extra-namespaces' => true, 'searchlimit' => 20, 'showhiddencats' => 0, 'shownumberswatching' => 1, 'showrollbackconfirmation' => 0, 'skin' => false, 'skin-responsive' => 1, 'thumbsize' => 5, 'underline' => 2, 'useeditwarning' => 1, 'uselivepreview' => 0, 'usenewrc' => 1, 'watchcreations' => 1, 'watchcreations-expiry' => 'infinite', 'watchdefault' => 1, 'watchdefault-expiry' => 'infinite', 'watchdeletion' => 0, 'watchlistdays' => 7, 'watchlisthideanons' => 0, 'watchlisthidebots' => 0, 'watchlisthidecategorization' => 1, 'watchlisthideliu' => 0, 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, 'watchlistreloadautomatically' => 0, 'watchlistunwatchlinks' => 0, 'watchmoves' => 0, 'watchrollback' => 0, 'watchuploads' => 1, 'watchrollback-expiry' => 'infinite', 'watchstar-expiry' => 'infinite', 'wlenhancedfilters-disable' => 0, 'wllimit' => 250, ], 'ConditionalUserOptions' => [ ], 'HiddenPrefs' => [ ], 'UserJsPrefLimit' => 100, 'InvalidUsernameCharacters' => '@:>=', 'UserrightsInterwikiDelimiter' => '@', 'SecureLogin' => false, 'AuthenticationTokenVersion' => null, 'SessionProviders' => [ 'MediaWiki\\Session\\CookieSessionProvider' => [ 'class' => 'MediaWiki\\Session\\CookieSessionProvider', 'args' => [ [ 'priority' => 30, ], ], 'services' => [ 'JwtCodec', 'UrlUtils', ], ], 'MediaWiki\\Session\\BotPasswordSessionProvider' => [ 'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => [ [ 'priority' => 75, ], ], 'services' => [ 'GrantsInfo', ], ], ], 'AutoCreateTempUser' => [ 'known' => false, 'enabled' => false, 'actions' => [ 'edit', ], 'genPattern' => '~$1', 'matchPattern' => null, 'reservedPattern' => '~$1', 'serialProvider' => [ 'type' => 'local', 'useYear' => true, ], 'serialMapping' => [ 'type' => 'readable-numeric', ], 'expireAfterDays' => 90, 'notifyBeforeExpirationDays' => 10, ], 'AutoblockExemptions' => [ ], 'AutoblockExpiry' => 86400, 'BlockAllowsUTEdit' => true, 'BlockCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 19, ], 'BlockDisablesLogin' => false, 'EnableMultiBlocks' => false, 'WhitelistRead' => false, 'WhitelistReadRegexp' => false, 'EmailConfirmToEdit' => false, 'HideIdentifiableRedirects' => true, 'GroupPermissions' => [ '*' => [ 'createaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'viewmyprivateinfo' => true, 'editmyprivateinfo' => true, 'editmyoptions' => true, ], 'user' => [ 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'movefile' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'minoredit' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, 'editmyuserjsredirect' => true, 'sendemail' => true, 'applychangetags' => true, 'changetags' => true, 'viewmywatchlist' => true, 'editmywatchlist' => true, 'createwithcontentmodel' => true, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'createpreviouslyrenamedaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], 'UserRequirementsPrivateConditions' => [ ], 'RestrictionTypes' => [ 'create', 'edit', 'move', 'upload', ], 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop', ], 'CascadingRestrictionLevels' => [ 'sysop', ], 'SemiprotectedRestrictionLevels' => [ 'autoconfirmed', ], 'NamespaceProtection' => [ ], 'NonincludableNamespaces' => [ ], 'AutoConfirmAge' => 0, 'AutoConfirmCount' => 0, 'Autopromote' => [ 'autoconfirmed' => [ '&', [ 1, null, ], [ 2, null, ], ], ], 'AutopromoteOnce' => [ 'onEdit' => [ ], ], 'AutopromoteOnceLogInRC' => true, 'AutopromoteOnceRCExcludedGroups' => [ ], 'AddGroups' => [ ], 'RemoveGroups' => [ ], 'AvailableRights' => [ ], 'ImplicitRights' => [ ], 'DeleteRevisionsLimit' => 0, 'DeleteRevisionsBatchSize' => 1000, 'HideUserContribLimit' => 1000, 'AccountCreationThrottle' => [ [ 'count' => 0, 'seconds' => 86400, ], ], 'TempAccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 600, ], [ 'count' => 6, 'seconds' => 86400, ], ], 'TempAccountNameAcquisitionThrottle' => [ [ 'count' => 60, 'seconds' => 86400, ], ], 'SpamRegex' => [ ], 'SummarySpamRegex' => [ ], 'EnableDnsBlacklist' => false, 'DnsBlacklistUrls' => [ ], 'ProxyList' => [ ], 'ProxyWhitelist' => [ ], 'SoftBlockRanges' => [ ], 'ApplyIpBlocksToXff' => false, 'RateLimits' => [ 'edit' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], 'user' => [ 90, 60, ], ], 'move' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], 'upload' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'rollback' => [ 'user' => [ 10, 60, ], 'newbie' => [ 5, 120, ], ], 'mailpassword' => [ 'ip' => [ 5, 3600, ], ], 'sendemail' => [ 'ip' => [ 5, 86400, ], 'newbie' => [ 5, 86400, ], 'user' => [ 20, 86400, ], ], 'changeemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'confirmemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'purge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'linkpurge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'renderfile' => [ 'ip' => [ 700, 30, ], 'user' => [ 700, 30, ], ], 'renderfile-nonstandard' => [ 'ip' => [ 70, 30, ], 'user' => [ 70, 30, ], ], 'stashedit' => [ 'ip' => [ 30, 60, ], 'newbie' => [ 30, 60, ], ], 'stashbasehtml' => [ 'ip' => [ 5, 60, ], 'newbie' => [ 5, 60, ], ], 'changetags' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'editcontentmodel' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], ], 'RateLimitsExcludedIPs' => [ ], 'PutIPinRC' => true, 'QueryPageDefaultLimit' => 50, 'ExternalQuerySources' => [ ], 'PasswordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300, ], [ 'count' => 150, 'seconds' => 172800, ], ], 'GrantPermissions' => [ 'basic' => [ 'autocreateaccount' => true, 'autoconfirmed' => true, 'autopatrol' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'nominornewtalk' => true, 'patrolmarks' => true, 'read' => true, 'unwatchedpages' => true, ], 'highvolume' => [ 'bot' => true, 'apihighlimits' => true, 'noratelimit' => true, 'markbotedits' => true, ], 'import' => [ 'import' => true, 'importupload' => true, ], 'editpage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, 'editusercss' => true, 'edituserjs' => true, 'editsitecss' => true, 'editsitejs' => true, ], 'createeditmovepage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'createpage' => true, 'createtalk' => true, 'delete-redirect' => true, 'move' => true, 'move-rootuserpages' => true, 'move-subpages' => true, 'move-categorypages' => true, 'suppressredirect' => true, ], 'uploadfile' => [ 'upload' => true, 'reupload-own' => true, ], 'uploadeditmovefile' => [ 'upload' => true, 'reupload-own' => true, 'reupload' => true, 'reupload-shared' => true, 'upload_by_url' => true, 'movefile' => true, 'suppressredirect' => true, ], 'patrol' => [ 'patrol' => true, ], 'rollback' => [ 'rollback' => true, ], 'blockusers' => [ 'block' => true, 'blockemail' => true, ], 'viewdeleted' => [ 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, ], 'viewrestrictedlogs' => [ 'suppressionlog' => true, ], 'delete' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, 'delete' => true, 'bigdelete' => true, 'deletelogentry' => true, 'deleterevision' => true, 'undelete' => true, ], 'oversight' => [ 'suppressrevision' => true, 'viewsuppressed' => true, ], 'protect' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], ], 'GrantPermissionGroups' => [ 'basic' => 'hidden', 'editpage' => 'page-interaction', 'createeditmovepage' => 'page-interaction', 'editprotected' => 'page-interaction', 'patrol' => 'page-interaction', 'uploadfile' => 'file-interaction', 'uploadeditmovefile' => 'file-interaction', 'sendemail' => 'email', 'viewmywatchlist' => 'watchlist-interaction', 'editviewmywatchlist' => 'watchlist-interaction', 'editmycssjs' => 'customization', 'editmyoptions' => 'customization', 'editinterface' => 'administration', 'editsiteconfig' => 'administration', 'rollback' => 'administration', 'blockusers' => 'administration', 'delete' => 'administration', 'viewdeleted' => 'administration', 'viewrestrictedlogs' => 'administration', 'protect' => 'administration', 'oversight' => 'administration', 'createaccount' => 'administration', 'mergehistory' => 'administration', 'import' => 'administration', 'highvolume' => 'high-volume', 'privateinfo' => 'private-information', ], 'GrantRiskGroups' => [ 'basic' => 'low', 'editpage' => 'low', 'createeditmovepage' => 'low', 'editprotected' => 'vandalism', 'patrol' => 'low', 'uploadfile' => 'low', 'uploadeditmovefile' => 'low', 'sendemail' => 'security', 'viewmywatchlist' => 'low', 'editviewmywatchlist' => 'low', 'editmycssjs' => 'security', 'editmyoptions' => 'security', 'editinterface' => 'vandalism', 'editsiteconfig' => 'security', 'rollback' => 'low', 'blockusers' => 'vandalism', 'delete' => 'vandalism', 'viewdeleted' => 'vandalism', 'viewrestrictedlogs' => 'security', 'protect' => 'vandalism', 'oversight' => 'security', 'createaccount' => 'low', 'mergehistory' => 'vandalism', 'import' => 'security', 'highvolume' => 'low', 'privateinfo' => 'low', ], 'EnableBotPasswords' => true, 'BotPasswordsCluster' => false, 'BotPasswordsDatabase' => false, 'BotPasswordsLimit' => 100, 'SecretKey' => false, 'JwtPrivateKey' => false, 'JwtPublicKey' => false, 'AllowUserJs' => false, 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, 'CSPUseReportURIDirective' => false, 'CSPFalsePositiveUrls' => [ 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'chrome-extension' => true, ], 'AllowCrossOrigin' => false, 'RestAllowCrossOriginCookieAuth' => false, 'SessionSecret' => false, 'CookieExpiration' => 2592000, 'ExtendedLoginCookieExpiration' => 15552000, 'SessionCookieJwtExpiration' => 14400, 'CookieDomain' => '', 'CookiePath' => '/', 'CookieSecure' => 'detect', 'CookiePrefix' => false, 'CookieHttpOnly' => true, 'CookieSameSite' => null, 'CacheVaryCookies' => [ ], 'SessionName' => false, 'CookieSetOnAutoblock' => true, 'CookieSetOnIpBlock' => true, 'DebugLogFile' => '', 'DebugLogPrefix' => '', 'DebugRedirects' => false, 'DebugRawPage' => false, 'DebugComments' => false, 'DebugDumpSql' => false, 'TrxProfilerLimits' => [ 'GET' => [ 'masterConns' => 0, 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'POST-nonwrite' => [ 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'PostSend-GET' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 10000, 'maxAffected' => 1000, 'masterConns' => 0, 'writes' => 0, ], 'PostSend-POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'JobRunner' => [ 'readQueryTime' => 30, 'writeQueryTime' => 5, 'readQueryRows' => 100000, 'maxAffected' => 500, ], 'Maintenance' => [ 'writeQueryTime' => 5, 'maxAffected' => 1000, ], ], 'DebugLogGroups' => [ ], 'MWLoggerDefaultSpi' => [ 'class' => 'MediaWiki\\Logger\\LegacySpi', ], 'ShowDebug' => false, 'SpecialVersionShowHooks' => false, 'ShowExceptionDetails' => false, 'LogExceptionBacktrace' => true, 'PropagateErrors' => true, 'ShowHostnames' => false, 'OverrideHostname' => false, 'DevelopmentWarnings' => false, 'DeprecationReleaseLimit' => false, 'Profiler' => [ ], 'StatsdServer' => false, 'StatsdMetricPrefix' => 'MediaWiki', 'StatsTarget' => null, 'StatsFormat' => null, 'StatsPrefix' => 'mediawiki', 'OpenTelemetryConfig' => null, 'PageInfoTransclusionLimit' => 50, 'EnableJavaScriptTest' => false, 'CachePrefix' => false, 'DebugToolbar' => false, 'ApiClientErrorSampleRate' => 1.0, 'DisableTextSearch' => false, 'AdvancedSearchHighlighting' => false, 'SearchHighlightBoundaries' => '[\\p{Z}\\p{P}\\p{C}]', 'OpenSearchTemplates' => [ 'application/x-suggestions+json' => false, 'application/x-suggestions+xml' => false, ], 'OpenSearchDefaultLimit' => 10, 'OpenSearchDescriptionLength' => 100, 'SearchSuggestCacheExpiry' => 1200, 'DisableSearchUpdate' => false, 'NamespacesToBeSearchedDefault' => [ true, ], 'DisableInternalSearch' => false, 'SearchForwardUrl' => null, 'SitemapNamespaces' => false, 'SitemapNamespacesPriorities' => false, 'SitemapApiConfig' => [ ], 'SpecialSearchFormOptions' => [ ], 'SearchMatchRedirectPreference' => false, 'SearchRunSuggestedQuery' => true, 'Diff3' => '/usr/bin/diff3', 'Diff' => '/usr/bin/diff', 'PreviewOnOpenNamespaces' => [ 14 => true, ], 'UniversalEditButton' => true, 'UseAutomaticEditSummaries' => true, 'CommandLineDarkBg' => false, 'ReadOnly' => null, 'ReadOnlyWatchedItemStore' => false, 'ReadOnlyFile' => false, 'UpgradeKey' => false, 'GitBin' => '/usr/bin/git', 'GitRepositoryViewers' => [ 'https: 'ssh: ], 'InstallerInitialPages' => [ [ 'titlemsg' => 'mainpage', 'text' => '{{subst:int:mainpagetext}}{{subst:int:mainpagedocfooter}}', ], ], 'RCMaxAge' => 7776000, 'WatchersMaxAge' => 15552000, 'UnwatchedPageSecret' => 1, 'RCFilterByAge' => false, 'RCLinkLimits' => [ 50, 100, 250, 500, ], 'RCLinkDays' => [ 1, 3, 7, 14, 30, ], 'RCFeeds' => [ ], 'RCWatchCategoryMembership' => false, 'UseRCPatrol' => true, 'StructuredChangeFiltersLiveUpdatePollingRate' => 3, 'UseNPPatrol' => true, 'UseFilePatrol' => true, 'Feed' => true, 'FeedLimit' => 50, 'FeedCacheTimeout' => 60, 'FeedDiffCutoff' => 32768, 'OverrideSiteFeed' => [ ], 'FeedClasses' => [ 'rss' => 'MediaWiki\\Feed\\RSSFeed', 'atom' => 'MediaWiki\\Feed\\AtomFeed', ], 'AdvertisedFeedTypes' => [ 'atom', ], 'RCShowWatchingUsers' => false, 'RCShowChangedSize' => true, 'RCChangedSizeThreshold' => 500, 'ShowUpdatedMarker' => true, 'DisableAnonTalk' => false, 'UseTagFilter' => true, 'SoftwareTags' => [ 'mw-contentmodelchange' => true, 'mw-new-redirect' => true, 'mw-removed-redirect' => true, 'mw-changed-redirect-target' => true, 'mw-blank' => true, 'mw-replace' => true, 'mw-recreated' => true, 'mw-rollback' => true, 'mw-undo' => true, 'mw-manual-revert' => true, 'mw-reverted' => true, 'mw-server-side-upload' => true, 'mw-ipblock-appeal' => true, 'mw-edited-other-users-js' => 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, 'EnableWatchstarPopover' => 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\\RecentChanges\\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', 'Promise-Non-Write-API-Action', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestSandboxSpecs' => [ ], 'MaxShellMemory' => 307200, 'MaxShellFileSize' => 102400, 'MaxShellTime' => 180, 'MaxShellWallClockTime' => 180, 'ShellCgroup' => false, 'PhpCli' => '/usr/bin/php', 'ShellRestrictionMethod' => 'autodetect', 'ShellboxUrls' => [ 'default' => null, ], 'ShellboxSecretKey' => null, 'ShellboxShell' => '/bin/sh', 'HTTPTimeout' => 25, 'HTTPConnectTimeout' => 5.0, 'HTTPMaxTimeout' => 0, 'HTTPMaxConnectTimeout' => 0, 'HTTPImportTimeout' => 25, 'AsyncHTTPTimeout' => 25, 'HTTPProxy' => '', 'LocalVirtualHosts' => [ ], 'LocalHTTPProxy' => false, 'AllowExternalReqID' => false, 'GenerateReqIDFormat' => 'rand24', 'JobRunRate' => 1, 'RunJobsAsync' => false, 'UpdateRowsPerJob' => 300, 'UpdateRowsPerQuery' => 100, 'RedirectOnLogin' => null, 'VirtualRestConfig' => [ 'paths' => [ ], 'modules' => [ ], 'global' => [ 'timeout' => 360, 'forwardCookies' => false, 'HTTPProxy' => null, ], ], 'EventRelayerConfig' => [ 'default' => [ 'class' => 'Wikimedia\\EventRelayer\\EventRelayerNull', ], ], 'Pingback' => false, 'OriginTrials' => [ ], 'ReportToExpiry' => 86400, 'ReportToEndpoints' => [ ], 'FeaturePolicyReportOnly' => [ ], 'SkinsPreferred' => [ 'vector-2022', 'vector', ], 'SpecialContributeSkinsEnabled' => [ ], 'SpecialContributeNewPageTarget' => null, 'EnableEditRecovery' => false, 'EditRecoveryExpiry' => 2592000, 'UseCodexSpecialBlock' => false, 'ShowLogoutConfirmation' => false, 'EnableProtectionIndicators' => true, 'OutputPipelineStages' => [ ], 'FeatureShutdown' => [ ], 'CloneArticleParserOutput' => true, 'UseLeximorph' => false, 'UsePostprocCacheLegacy' => false, 'UsePostprocCacheParsoid' => true, 'ParserOptionsLogUnsafeSampleRate' => 0, ], 'type' => [ 'ConfigRegistry' => 'object', 'AssumeProxiesUseDefaultProtocolPorts' => 'boolean', 'ForceHTTPS' => 'boolean', 'ExtensionDirectory' => [ 'string', 'null', ], 'StyleDirectory' => [ 'string', 'null', ], 'UploadDirectory' => [ 'string', 'boolean', 'null', ], 'Logos' => [ 'object', 'boolean', ], 'ReferrerPolicy' => [ 'array', 'string', 'boolean', ], 'ActionPaths' => 'object', 'MainPageIsDomainRoot' => 'boolean', 'ImgAuthUrlPathMap' => 'object', 'LocalFileRepo' => 'object', 'ForeignFileRepos' => 'array', 'UseSharedUploads' => 'boolean', 'SharedUploadDirectory' => [ 'string', 'null', ], 'SharedUploadPath' => [ 'string', 'null', ], 'HashedSharedUploadDirectory' => 'boolean', 'FetchCommonsDescriptions' => 'boolean', 'SharedUploadDBname' => [ 'boolean', 'string', ], 'SharedUploadDBprefix' => 'string', 'CacheSharedUploads' => 'boolean', 'ForeignUploadTargets' => 'array', 'UploadDialog' => 'object', 'FileBackends' => 'object', 'LockManagers' => 'array', 'CopyUploadsDomains' => 'array', 'CopyUploadTimeout' => [ 'boolean', 'integer', ], 'SharedThumbnailScriptPath' => [ 'string', 'boolean', ], 'HashedUploadDirectory' => 'boolean', 'CSPUploadEntryPoint' => 'boolean', 'FileExtensions' => 'array', 'ProhibitedFileExtensions' => 'array', 'MimeTypeExclusions' => 'array', 'TrustedMediaFormats' => 'array', 'MediaHandlers' => 'object', 'NativeImageLazyLoading' => 'boolean', 'ParserTestMediaHandlers' => 'object', 'MaxInterlacingAreas' => 'object', 'SVGConverters' => 'object', 'SVGNativeRendering' => [ 'string', 'boolean', ], 'MaxImageArea' => [ 'string', 'integer', 'boolean', ], 'TiffThumbnailType' => 'array', 'GenerateThumbnailOnParse' => 'boolean', 'EnableAutoRotation' => [ 'boolean', 'null', ], 'Antivirus' => [ 'string', 'null', ], 'AntivirusSetup' => 'object', 'MimeDetectorCommand' => [ 'string', 'null', ], 'XMLMimeTypes' => 'object', 'ImageLimits' => 'array', 'ThumbLimits' => 'array', 'ThumbnailNamespaces' => 'array', 'ThumbnailSteps' => [ 'array', 'null', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EmailConfirmationBanner' => 'boolean', 'EnotifRevealEditorAddress' => 'boolean', 'UsersNotifiedOnAllChanges' => 'object', 'DBmwschema' => [ 'string', 'null', ], 'SharedTables' => 'array', 'DBservers' => [ 'boolean', 'array', ], 'LBFactoryConf' => 'object', 'LocalDatabases' => 'array', 'VirtualDomainsMapping' => 'object', 'FileSchemaMigrationStage' => 'integer', 'ExternalLinksDomainGaps' => 'object', 'ContentHandlers' => 'object', 'NamespaceContentModels' => 'object', 'TextModelsToParse' => 'array', 'ExternalStores' => 'array', 'ExternalServers' => 'object', 'DefaultExternalStore' => [ 'array', 'boolean', ], 'RevisionCacheExpiry' => 'integer', 'PageLanguageUseDB' => 'boolean', 'DiffEngine' => [ 'string', 'null', ], 'ExternalDiffEngine' => [ 'string', 'boolean', ], 'Wikidiff2Options' => 'object', 'RequestTimeLimit' => [ 'integer', 'null', ], 'CriticalSectionTimeLimit' => 'number', 'PoolCounterConf' => [ 'object', 'null', ], 'PoolCountClientConf' => 'object', 'MaxUserDBWriteDuration' => [ 'integer', 'boolean', ], 'MaxJobDBWriteDuration' => [ 'integer', 'boolean', ], 'MultiShardSiteStats' => 'boolean', 'ObjectCaches' => 'object', 'WANObjectCache' => 'object', 'MicroStashType' => [ 'string', 'integer', ], 'ParsoidCacheConfig' => 'object', 'ParsoidSelectiveUpdateSampleRate' => 'integer', 'ParserCacheFilterConfig' => 'object', 'ChronologyProtectorSecret' => 'string', 'PHPSessionHandling' => 'string', 'SuspiciousIpExpiry' => [ 'integer', 'boolean', ], 'MemCachedServers' => 'array', 'LocalisationCacheConf' => 'object', 'ExtensionInfoMTime' => [ 'integer', 'boolean', ], 'CdnServers' => 'object', 'CdnServersNoPurge' => 'object', 'HTCPRouting' => 'object', 'GrammarForms' => 'object', 'ExtraInterlanguageLinkPrefixes' => 'array', 'InterlanguageLinkCodeMap' => 'object', 'ExtraLanguageNames' => 'object', 'ExtraLanguageCodes' => 'object', 'DummyLanguageCodes' => 'object', 'DisabledVariants' => 'object', 'ForceUIMsgAsContentMsg' => 'object', 'RawHtmlMessages' => 'array', 'OverrideUcfirstCharacters' => 'object', 'XhtmlNamespaces' => 'object', 'BrowserFormatDetection' => 'string', 'SkinMetaTags' => 'object', 'SkipSkins' => 'object', 'FragmentMode' => 'array', 'FooterIcons' => 'object', 'InterwikiLogoOverride' => 'array', 'ResourceModules' => 'object', 'ResourceModuleSkinStyles' => 'object', 'ResourceLoaderSources' => 'object', 'ResourceLoaderMaxage' => 'object', 'ResourceLoaderMaxQueryLength' => [ 'integer', 'boolean', ], 'CanonicalNamespaceNames' => 'object', 'ExtraNamespaces' => 'object', 'ExtraGenderNamespaces' => 'object', 'NamespaceAliases' => 'object', 'CapitalLinkOverrides' => 'object', 'NamespacesWithSubpages' => 'object', 'NamespacesWithoutAutoSummaries' => 'array', 'ContentNamespaces' => 'array', 'ShortPagesNamespaceExclusions' => 'array', 'ExtraSignatureNamespaces' => 'array', 'InvalidRedirectTargets' => 'array', 'LocalInterwikis' => 'array', 'InterwikiCache' => [ 'boolean', 'object', ], 'SiteTypes' => 'object', 'UrlProtocols' => 'array', 'TidyConfig' => 'object', 'ParsoidSettings' => 'object', 'ParsoidExperimentalParserFunctionOutput' => 'boolean', 'NoFollowNsExceptions' => 'array', 'NoFollowDomainExceptions' => 'array', 'ExternalLinksIgnoreDomains' => 'array', 'EnableMagicLinks' => 'object', 'ManualRevertSearchRadius' => 'integer', 'RevertedTagMaxDepth' => 'integer', 'CentralIdLookupProviders' => 'object', 'CentralIdLookupProvider' => 'string', 'UserRegistrationProviders' => 'object', 'PasswordPolicy' => 'object', 'AuthManagerConfig' => [ 'object', 'null', ], 'AuthManagerAutoConfig' => 'object', 'RememberMe' => 'string', 'ReauthenticateTime' => 'object', 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => 'object', 'ChangeCredentialsBlacklist' => 'array', 'RemoveCredentialsBlacklist' => 'array', 'PasswordConfig' => 'object', 'PasswordResetRoutes' => 'object', 'SignatureAllowedLintErrors' => 'array', 'ReservedUsernames' => 'array', 'DefaultUserOptions' => 'object', 'ConditionalUserOptions' => 'object', 'HiddenPrefs' => 'array', 'UserJsPrefLimit' => 'integer', 'AuthenticationTokenVersion' => [ 'string', 'null', ], 'SessionProviders' => 'object', 'AutoCreateTempUser' => 'object', 'AutoblockExemptions' => 'array', 'BlockCIDRLimit' => 'object', 'EnableMultiBlocks' => 'boolean', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', 'UserRequirementsPrivateConditions' => 'array', 'RestrictionTypes' => 'array', 'RestrictionLevels' => 'array', 'CascadingRestrictionLevels' => 'array', 'SemiprotectedRestrictionLevels' => 'array', 'NamespaceProtection' => 'object', 'NonincludableNamespaces' => 'object', 'Autopromote' => 'object', 'AutopromoteOnce' => 'object', 'AutopromoteOnceRCExcludedGroups' => 'array', 'AddGroups' => 'object', 'RemoveGroups' => 'object', 'AvailableRights' => 'array', 'ImplicitRights' => 'array', 'AccountCreationThrottle' => [ 'integer', 'array', ], 'TempAccountCreationThrottle' => 'array', 'TempAccountNameAcquisitionThrottle' => 'array', 'SpamRegex' => 'array', 'SummarySpamRegex' => 'array', 'DnsBlacklistUrls' => 'array', 'ProxyList' => [ 'string', 'array', ], 'ProxyWhitelist' => 'array', 'SoftBlockRanges' => 'array', 'RateLimits' => 'object', 'RateLimitsExcludedIPs' => 'array', 'ExternalQuerySources' => 'object', 'PasswordAttemptThrottle' => 'array', 'GrantPermissions' => 'object', 'GrantPermissionGroups' => 'object', 'GrantRiskGroups' => 'object', 'EnableBotPasswords' => 'boolean', 'BotPasswordsCluster' => [ 'string', 'boolean', ], 'BotPasswordsDatabase' => [ 'string', 'boolean', ], 'BotPasswordsLimit' => 'integer', 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPUseReportURIDirective' => [ 'boolean', 'object', ], 'CSPFalsePositiveUrls' => 'object', 'AllowCrossOrigin' => 'boolean', 'RestAllowCrossOriginCookieAuth' => 'boolean', 'CookieSameSite' => [ 'string', 'null', ], 'CacheVaryCookies' => 'array', 'TrxProfilerLimits' => 'object', 'DebugLogGroups' => 'object', 'MWLoggerDefaultSpi' => 'object', 'Profiler' => 'object', 'StatsTarget' => [ 'string', 'null', ], 'StatsFormat' => [ 'string', 'null', ], 'StatsPrefix' => 'string', 'OpenTelemetryConfig' => [ 'object', 'null', ], 'OpenSearchTemplates' => 'object', 'NamespacesToBeSearchedDefault' => 'object', 'SitemapNamespaces' => [ 'boolean', 'array', ], 'SitemapNamespacesPriorities' => [ 'boolean', 'object', ], 'SitemapApiConfig' => 'object', 'SpecialSearchFormOptions' => 'object', 'SearchMatchRedirectPreference' => 'boolean', 'SearchRunSuggestedQuery' => 'boolean', 'PreviewOnOpenNamespaces' => 'object', 'ReadOnlyWatchedItemStore' => 'boolean', 'GitRepositoryViewers' => 'object', 'InstallerInitialPages' => 'array', 'RCLinkLimits' => 'array', 'RCLinkDays' => 'array', 'RCFeeds' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchstarPopover' => 'boolean', 'EnableWatchlistLabels' => 'boolean', 'WatchlistLabelsMaxPerUser' => 'integer', 'WatchlistPurgeRate' => 'number', 'WatchlistExpiryMaxDuration' => [ 'string', 'null', ], 'EnableChangesListQueryPartitioning' => 'boolean', 'ImportSources' => 'object', 'ExtensionFunctions' => 'array', 'ExtensionMessagesFiles' => 'object', 'MessagesDirs' => 'object', 'TranslationAliasesDirs' => 'object', 'ExtensionEntryPointListFiles' => 'object', 'ValidSkinNames' => 'object', 'SpecialPages' => 'object', 'ExtensionCredits' => 'object', 'Hooks' => 'object', 'ServiceWiringFiles' => 'array', 'JobClasses' => 'object', 'JobTypesExcludedFromDefaultQueue' => 'array', 'JobBackoffThrottling' => 'object', 'JobTypeConf' => 'object', 'SpecialPageCacheUpdates' => 'object', 'PagePropLinkInvalidations' => 'object', 'TempCategoryCollations' => 'array', 'SortedCategories' => 'boolean', 'TrackingCategories' => 'array', 'LogTypes' => 'array', 'LogRestrictions' => 'object', 'FilterLogTypes' => 'object', 'LogNames' => 'object', 'LogHeaders' => 'object', 'LogActions' => 'object', 'LogActionsHandlers' => 'object', 'ActionFilteredLogs' => 'object', 'RangeContributionsCIDRLimit' => 'object', 'Actions' => 'object', 'NamespaceRobotPolicies' => 'object', 'ArticleRobotPolicies' => 'object', 'ExemptFromUserRobotsControl' => [ 'array', 'null', ], 'APIModules' => 'object', 'APIFormatModules' => 'object', 'APIMetaModules' => 'object', 'APIPropModules' => 'object', 'APIListModules' => 'object', 'APIUselessQueryPages' => 'array', 'CrossSiteAJAXdomains' => 'object', 'CrossSiteAJAXdomainExceptions' => 'object', 'AllowedCorsHeaders' => 'array', 'RestAPIAdditionalRouteFiles' => 'array', 'RestSandboxSpecs' => 'object', 'ShellRestrictionMethod' => [ 'string', 'boolean', ], 'ShellboxUrls' => 'object', 'ShellboxSecretKey' => [ 'string', 'null', ], 'ShellboxShell' => [ 'string', 'null', ], 'HTTPTimeout' => 'number', 'HTTPConnectTimeout' => 'number', 'HTTPMaxTimeout' => 'number', 'HTTPMaxConnectTimeout' => 'number', 'LocalVirtualHosts' => 'object', 'LocalHTTPProxy' => [ 'string', 'boolean', ], 'GenerateReqIDFormat' => 'string', 'VirtualRestConfig' => 'object', 'EventRelayerConfig' => 'object', 'Pingback' => 'boolean', 'OriginTrials' => 'array', 'ReportToExpiry' => 'integer', 'ReportToEndpoints' => 'array', 'FeaturePolicyReportOnly' => 'array', 'SkinsPreferred' => 'array', 'SpecialContributeSkinsEnabled' => 'array', 'SpecialContributeNewPageTarget' => [ 'string', 'null', ], 'EnableEditRecovery' => 'boolean', 'EditRecoveryExpiry' => 'integer', 'UseCodexSpecialBlock' => 'boolean', 'ShowLogoutConfirmation' => 'boolean', 'EnableProtectionIndicators' => 'boolean', 'OutputPipelineStages' => 'object', 'FeatureShutdown' => 'array', 'CloneArticleParserOutput' => 'boolean', 'UseLeximorph' => 'boolean', 'UsePostprocCacheLegacy' => 'boolean', 'UsePostprocCacheParsoid' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', ], 'mergeStrategy' => [ 'TiffThumbnailType' => 'replace', 'LBFactoryConf' => 'replace', 'InterwikiCache' => 'replace', 'PasswordPolicy' => 'array_replace_recursive', 'AuthManagerAutoConfig' => 'array_plus_2d', 'GroupPermissions' => 'array_plus_2d', 'RevokePermissions' => 'array_plus_2d', 'AddGroups' => 'array_merge_recursive', 'RemoveGroups' => 'array_merge_recursive', 'RateLimits' => 'array_plus_2d', 'GrantPermissions' => 'array_plus_2d', 'MWLoggerDefaultSpi' => 'replace', 'Profiler' => 'replace', 'Hooks' => 'array_merge_recursive', 'VirtualRestConfig' => 'array_plus_2d', ], 'dynamicDefault' => [ 'UsePathInfo' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUsePathInfo', ], ], 'Script' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultScript', ], ], 'LoadScript' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLoadScript', ], ], 'RestPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultRestPath', ], ], 'StylePath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultStylePath', ], ], 'LocalStylePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalStylePath', ], ], 'ExtensionAssetsPath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultExtensionAssetsPath', ], ], 'ArticlePath' => [ 'use' => [ 'Script', 'UsePathInfo', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultArticlePath', ], ], 'UploadPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUploadPath', ], ], 'FileCacheDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultFileCacheDirectory', ], ], 'Logo' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLogo', ], ], 'DeletedDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDeletedDirectory', ], ], 'ShowEXIF' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultShowEXIF', ], ], 'SharedPrefix' => [ 'use' => [ 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedPrefix', ], ], 'SharedSchema' => [ 'use' => [ 'DBmwschema', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedSchema', ], ], 'DBerrorLogTZ' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDBerrorLogTZ', ], ], 'Localtimezone' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocaltimezone', ], ], 'LocalTZoffset' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalTZoffset', ], ], 'ResourceBasePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultResourceBasePath', ], ], 'MetaNamespace' => [ 'use' => [ 'Sitename', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultMetaNamespace', ], ], 'CookieSecure' => [ 'use' => [ 'ForceHTTPS', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookieSecure', ], ], 'CookiePrefix' => [ 'use' => [ 'SharedDB', 'SharedPrefix', 'SharedTables', 'DBname', 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookiePrefix', ], ], 'ReadOnlyFile' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultReadOnlyFile', ], ], ], ], 'config-schema' => [ 'UploadStashScalerBaseUrl' => [ 'deprecated' => 'since 1.36 Use thumbProxyUrl in $wgLocalFileRepo', ], 'IllegalFileChars' => [ 'deprecated' => 'since 1.41; no longer customizable', ], 'ThumbnailNamespaces' => [ 'items' => [ 'type' => 'integer', ], ], 'LocalDatabases' => [ 'items' => [ 'type' => 'string', ], ], 'ParserCacheFilterConfig' => [ 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of namespace IDs to filter definitions.', 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of filter names to values.', 'properties' => [ 'minCpuTime' => [ 'type' => 'number', ], ], ], ], ], 'PHPSessionHandling' => [ 'deprecated' => 'since 1.45 Integration with PHP session handling will be removed in the future', ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'ChangeCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'RemoveCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'GroupPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GroupInheritsPermissions' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'AvailableRights' => [ 'items' => [ 'type' => 'string', ], ], 'ImplicitRights' => [ 'items' => [ 'type' => 'string', ], ], 'SoftBlockRanges' => [ 'items' => [ 'type' => 'string', ], ], 'ExternalQuerySources' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'enabled' => [ 'type' => 'boolean', 'default' => false, ], 'url' => [ 'type' => 'string', 'format' => 'uri', ], 'timeout' => [ 'type' => 'integer', 'default' => 10, ], ], 'required' => [ 'enabled', 'url', ], 'additionalProperties' => false, ], ], 'GrantPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GrantPermissionGroups' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'SitemapNamespacesPriorities' => [ 'deprecated' => 'since 1.45 and ignored', ], 'SitemapApiConfig' => [ 'additionalProperties' => [ 'enabled' => [ 'type' => 'bool', ], 'sitemapsPerIndex' => [ 'type' => 'int', ], 'pagesPerSitemap' => [ 'type' => 'int', ], 'expiry' => [ 'type' => 'int', ], ], ], 'SoftwareTags' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'JobBackoffThrottling' => [ 'additionalProperties' => [ 'type' => 'number', ], ], 'JobTypeConf' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'class' => [ 'type' => 'string', ], 'order' => [ 'type' => 'string', ], 'claimTTL' => [ 'type' => 'integer', ], ], ], ], 'TrackingCategories' => [ 'deprecated' => 'since 1.25 Extensions should now register tracking categories using the new extension registration system.', ], 'RangeContributionsCIDRLimit' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'RestSandboxSpecs' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'url' => [ 'type' => 'string', 'format' => 'url', ], 'name' => [ 'type' => 'string', ], 'file' => [ 'type' => 'string', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], ], ], 'ShellboxUrls' => [ 'additionalProperties' => [ 'type' => [ 'string', 'boolean', 'null', ], ], ], ], 'obsolete-config' => [ 'MangleFlashPolicy' => 'Since 1.39; no longer has any effect.', 'EnableOpenSearchSuggest' => 'Since 1.35, no longer used', 'AutoloadAttemptLowercase' => 'Since 1.40; no longer has any effect.', ],]
This interface represents the authority associated with the current execution context,...
Definition Authority.php:23
array $params
The job parameters.
msg( $key,... $params)