68use OOUI\MessageWidget;
70use Psr\Log\LoggerAwareTrait;
71use Psr\Log\NullLogger;
73use UnexpectedValueException;
104 private $languageConverter;
113 private $languageConverterFactory;
116 private $parserFactory;
119 private $skinFactory;
122 private $userGroupManager;
125 private $signatureValidatorFactory;
210 $this->logger =
new NullLogger();
211 $this->languageConverter = $languageConverter;
213 $this->hookRunner =
new HookRunner( $hookContainer );
217 $services =
static function () {
223 : $services()->getUserOptionsManager();
224 $this->languageConverterFactory = $languageConverterFactory ?? $services()->getLanguageConverterFactory();
226 $this->parserFactory = $parserFactory ?? $services()->getParserFactory();
227 $this->skinFactory = $skinFactory ?? $services()->getSkinFactory();
228 $this->userGroupManager = $userGroupManager ?? $services()->getUserGroupManager();
229 $this->signatureValidatorFactory = $signatureValidatorFactory
230 ?? $services()->getSignatureValidatorFactory();
251 OutputPage::setupOOUI(
252 strtolower( $context->
getSkin()->getSkinName() ),
266 $this->hookRunner->onGetPreferences( $user, $preferences );
268 $this->loadPreferenceValues( $user, $context, $preferences );
269 $this->logger->debug(
"Created form descriptor for user '{$user->getName()}'" );
280 foreach ( $descriptor as $name => &
$params ) {
283 if ( ( isset(
$params[
'type'] ) &&
$params[
'type'] ===
'info' ) ||
285 ( isset(
$params[
'class'] ) &&
$params[
'class'] === \HTMLInfoField::class ) ||
286 ( isset(
$params[
'class'] ) &&
$params[
'class'] === HTMLInfoField::class )
288 unset( $descriptor[$name] );
293 foreach (
$params as $key => $value ) {
296 case 'options-message':
299 case 'options-messages':
304 if ( preg_match(
'/-messages?$/', $key ) ) {
321 private function loadPreferenceValues(
User $user,
IContextSource $context, &$defaultPreferences ) {
324 unset( $defaultPreferences[$pref] );
329 $form =
new HTMLForm( $simplified, $context );
331 $disable = !$user->
isAllowed(
'editmyoptions' );
333 $defaultOptions = $this->userOptionsManager->getDefaultOptions( $user );
334 $userOptions = $this->userOptionsManager->getOptions( $user );
335 $this->
applyFilters( $userOptions, $defaultPreferences,
'filterForForm' );
337 foreach ( $simplified as $name => $_ ) {
338 $info = &$defaultPreferences[$name];
340 $info[
'disabled'] =
'disabled';
342 if ( isset( $info[
'default'] ) ) {
346 $field = $form->getField( $name );
347 $globalDefault = $defaultOptions[$name] ??
null;
348 $prefFromUser = static::getPreferenceForField( $name, $field, $userOptions );
353 if ( $prefFromUser !==
null &&
354 $field->validate( $prefFromUser, $this->userOptionsManager->getOptions( $user ) ) ===
true ) {
355 $info[
'default'] = $prefFromUser;
356 } elseif ( $field->validate( $globalDefault, $this->userOptionsManager->getOptions( $user ) ) ===
true ) {
357 $info[
'default'] = $globalDefault;
359 $globalDefault = json_encode( $globalDefault );
360 throw new UnexpectedValueException(
361 "Default '$globalDefault' is invalid for preference $name of user " . $user->
getName()
366 return $defaultPreferences;
380 $val = $userOptions[$name] ??
null;
384 $prefix = $field->mParams[
'prefix'] ?? $name;
386 $keys = array_keys( $field->filterDataForSubmit( [] ) );
387 foreach ( $keys as $key ) {
388 if ( $userOptions[$prefix . $key] ??
false ) {
407 $val = $userOptions[$name] ??
null;
410 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'multiselect' ) ||
412 ( isset( $info[
'class'] ) && $info[
'class'] === \HTMLMultiSelectField::class ) ||
413 ( isset( $info[
'class'] ) && $info[
'class'] === HTMLMultiSelectField::class )
415 $options = HTMLFormField::flattenOptions( $info[
'options-messages'] ?? $info[
'options'] );
416 $prefix = $info[
'prefix'] ?? $name;
420 if ( $userOptions[
"$prefix$value"] ??
false ) {
427 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'checkmatrix' ) ||
429 ( isset( $info[
'class'] ) && $info[
'class'] === \HTMLCheckMatrix::class ) ||
430 ( isset( $info[
'class'] ) && $info[
'class'] === HTMLCheckMatrix::class )
432 $columns = HTMLFormField::flattenOptions( $info[
'columns'] );
433 $rows = HTMLFormField::flattenOptions( $info[
'rows'] );
434 $prefix = $info[
'prefix'] ?? $name;
437 foreach ( $columns as $column ) {
438 foreach ( $rows as $row ) {
439 if ( $userOptions[
"$prefix$column-$row"] ??
false ) {
440 $val[] =
"$column-$row";
463 $defaultPreferences[
'username'] = [
465 'label-message' => [
'username', $userName ],
466 'default' => $userName,
467 'section' =>
'personal/info',
473 $userEffectiveGroups = array_diff(
474 $this->userGroupManager->getUserEffectiveGroups( $user ),
477 $defaultPreferences[
'usergroups'] = [
479 'label-message' => [
'prefs-memberingroups',
481 'default' =>
function () use ( $user, $userEffectiveGroups, $context, $lang, $userName ) {
482 $userGroupMemberships = $this->userGroupManager->getUserGroupMemberships( $user );
483 $userGroups = $userMembers = $userTempGroups = $userTempMembers = [];
484 foreach ( $userEffectiveGroups as $ueg ) {
485 $groupStringOrObject = $userGroupMemberships[$ueg] ?? $ueg;
487 $userG = UserGroupMembership::getLinkHTML( $groupStringOrObject, $context );
488 $userM = UserGroupMembership::getLinkHTML( $groupStringOrObject, $context, $userName );
497 $userTempGroups[] = $userG;
498 $userTempMembers[] = $userM;
500 $userGroups[] = $userG;
501 $userMembers[] = $userM;
505 sort( $userMembers );
506 sort( $userTempGroups );
507 sort( $userTempMembers );
508 $userGroups = array_merge( $userTempGroups, $userGroups );
509 $userMembers = array_merge( $userTempMembers, $userMembers );
510 return $context->
msg(
'prefs-memberingroups-type' )
511 ->rawParams( $lang->commaList( $userGroups ), $lang->commaList( $userMembers ) )
515 'section' =>
'personal/info',
519 $formattedEditCount = $lang->formatNum( $user->
getEditCount() );
520 $editCount = $this->linkRenderer->makeLink( $contribTitle, $formattedEditCount );
522 $defaultPreferences[
'editcount'] = [
525 'label-message' =>
'prefs-edits',
526 'default' => $editCount,
527 'section' =>
'personal/info',
531 $displayUser = $context->
getUser();
533 $defaultPreferences[
'registrationdate'] = [
535 'label-message' =>
'prefs-registration',
536 'default' => $context->
msg(
537 'prefs-registration-date-time',
538 $lang->userTimeAndDate( $userRegistration, $displayUser ),
539 $lang->userDate( $userRegistration, $displayUser ),
540 $lang->userTime( $userRegistration, $displayUser )
542 'section' =>
'personal/info',
546 $canViewPrivateInfo = $user->
isAllowed(
'viewmyprivateinfo' );
547 $canEditPrivateInfo = $user->
isAllowed(
'editmyprivateinfo' );
550 $defaultPreferences[
'realname'] = [
552 'type' => $canEditPrivateInfo && $this->authManager->allowsPropertyChange(
'realname' )
555 'section' =>
'personal/info',
556 'label-message' =>
'yourrealname',
557 'help-message' =>
'prefs-help-realname',
560 if ( $canEditPrivateInfo && $this->authManager->allowsAuthenticationDataChange(
563 $defaultPreferences[
'password'] = [
566 'default' => (string)
new ButtonWidget( [
570 'label' => $context->
msg(
'prefs-resetpass' )->text(),
572 'label-message' =>
'yourpassword',
575 ? $context->
msg(
'prefs-help-yourpassword',
576 '[[#mw-prefsection-personal-email|{{int:prefs-email}}]]' )->parse()
578 'section' =>
'personal/info',
585 $defaultPreferences[
'prefershttps'] = [
587 'label-message' =>
'tog-prefershttps',
588 'help-message' =>
'prefs-help-prefershttps',
589 'section' =>
'personal/info'
593 $defaultPreferences[
'downloaduserdata'] = [
596 'label-message' =>
'prefs-user-downloaddata-label',
601 '/api.php?action=query&meta=userinfo&uiprop=*&formatversion=2',
603 $context->
msg(
'prefs-user-downloaddata-info' )->text()
605 'help-message' => [
'prefs-user-downloaddata-help-message', urlencode( $user->
getTitleKey() ) ],
606 'section' =>
'personal/info',
609 $defaultPreferences[
'restoreprefs'] = [
612 'label-message' =>
'prefs-user-restoreprefs-label',
617 ->getSubpage(
'reset' )->getLocalURL()
619 $context->
msg(
'prefs-user-restoreprefs-info' )->text()
621 'section' =>
'personal/info',
624 $languages = $this->languageNameUtils->getLanguageNames(
625 LanguageNameUtils::AUTONYMS,
626 LanguageNameUtils::SUPPORTED
629 if ( !array_key_exists( $languageCode, $languages ) ) {
630 $languages[$languageCode] = $languageCode;
636 foreach ( $languages as $code => $name ) {
637 $display = LanguageCode::bcp47( $code ) .
' - ' . $name;
640 $defaultPreferences[
'language'] = [
642 'section' =>
'personal/i18n',
644 'label-message' =>
'yourlanguage',
647 $neutralGenderMessage = $context->
msg(
'gender-notknown' )->escaped() . (
648 !$context->
msg(
'gender-unknown' )->isDisabled()
649 ?
"<br>" . $context->
msg(
'parentheses' )
650 ->params( $context->
msg(
'gender-unknown' )->plain() )
655 $defaultPreferences[
'gender'] = [
657 'section' =>
'personal/i18n',
659 $neutralGenderMessage =>
'unknown',
660 $context->
msg(
'gender-female' )->escaped() =>
'female',
661 $context->
msg(
'gender-male' )->escaped() =>
'male',
663 'label-message' =>
'yourgender',
664 'help-message' =>
'prefs-help-gender',
668 if ( !$this->languageConverterFactory->isConversionDisabled() ) {
670 foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
671 if ( $langCode == $this->contLang->getCode() ) {
672 if ( !$this->languageConverter->hasVariants() ) {
676 $variants = $this->languageConverter->getVariants();
678 foreach ( $variants as $v ) {
679 $v = str_replace(
'_',
'-', strtolower( $v ) );
680 $variantArray[$v] = $lang->getVariantname( $v,
false );
684 foreach ( $variantArray as $code => $name ) {
685 $display = LanguageCode::bcp47( $code ) .
' - ' . $name;
689 $defaultPreferences[
'variant'] = [
690 'label-message' =>
'yourvariant',
693 'section' =>
'personal/i18n',
694 'help-message' =>
'prefs-help-variant',
697 $defaultPreferences[
"variant-$langCode"] = [
705 $oldsigWikiText = $this->parserFactory->getInstance()->preSaveTransform(
709 ParserOptions::newFromContext( $context )
711 $oldsigHTML = Parser::stripOuterParagraph(
712 $context->
getOutput()->parseAsContent( $oldsigWikiText )
714 $signatureFieldConfig = [];
716 $signature = $this->userOptionsManager->getOption( $user,
'nickname' );
717 $useFancySig = $this->userOptionsManager->getBoolOption( $user,
'fancysig' );
718 if ( $useFancySig && $signature !==
'' ) {
719 $parserOpts = ParserOptions::newFromContext( $context );
720 $validator = $this->signatureValidatorFactory
721 ->newSignatureValidator( $user, $context, $parserOpts );
722 $signatureErrors = $validator->validateSignature( $signature );
723 if ( $signatureErrors ) {
725 $oldsigHTML .=
'<p><strong>' .
730 $context->
msg(
"prefs-signature-invalid-$sigValidation" )->parse() .
735 foreach ( $signatureErrors as &$sigError ) {
736 $sigError =
new HtmlSnippet( $sigError );
739 $signatureFieldConfig = [
740 'warnings' => $sigValidation !==
'disallow' ? $signatureErrors :
null,
741 'errors' => $sigValidation ===
'disallow' ? $signatureErrors :
null,
746 $defaultPreferences[
'oldsig'] = [
751 'default' =>
new FieldLayout(
753 'label' =>
new HtmlSnippet( $oldsigHTML ),
757 'label' =>
new HtmlSnippet( $context->
msg(
'tog-oldsig' )->parse() )
758 ] + $signatureFieldConfig
760 'section' =>
'personal/signature',
762 $defaultPreferences[
'nickname'] = [
763 'type' => $this->authManager->allowsPropertyChange(
'nickname' ) ?
'text' :
'info',
765 'label-message' =>
'yournick',
766 'validation-callback' =>
function ( $signature, $alldata,
HTMLForm $form ) {
769 'section' =>
'personal/signature',
770 'filter-callback' =>
function ( $signature, array $alldata,
HTMLForm $form ) {
774 $defaultPreferences[
'fancysig'] = [
776 'label-message' =>
'tog-fancysig',
778 'help-message' =>
'prefs-help-signature',
779 'section' =>
'personal/signature'
784 if ( $canViewPrivateInfo ) {
787 ?
'prefs-help-email-required'
788 :
'prefs-help-email';
792 $helpMessages[] =
'prefs-help-email-others';
795 $emailAddress = $user->
getEmail() ? htmlspecialchars( $user->
getEmail() ) :
'';
796 if ( $canEditPrivateInfo && $this->authManager->allowsPropertyChange(
'emailaddress' ) ) {
797 $button =
new ButtonWidget( [
802 $context->
msg( $user->
getEmail() ?
'prefs-changeemail' :
'prefs-setemail' )->text(),
805 $emailAddress .= $emailAddress ==
'' ? $button : (
'<br />' . $button );
808 $defaultPreferences[
'emailaddress'] = [
811 'default' => $emailAddress,
812 'label-message' =>
'youremail',
813 'section' =>
'personal/email',
814 'help-messages' => $helpMessages,
819 $disableEmailPrefs =
false;
821 $defaultPreferences[
'requireemail'] = [
823 'label-message' =>
'tog-requireemail',
824 'help-message' =>
'prefs-help-requireemail',
825 'section' =>
'personal/email',
835 $displayUser = $context->
getUser();
837 $time = $lang->userTimeAndDate( $emailTimestamp, $displayUser );
838 $d = $lang->userDate( $emailTimestamp, $displayUser );
839 $t = $lang->userTime( $emailTimestamp, $displayUser );
840 $emailauthenticated = $context->
msg(
'emailauthenticated',
841 $time, $d, $t )->parse() .
'<br />';
842 $emailauthenticationclass =
'mw-email-authenticated';
844 $disableEmailPrefs =
true;
845 $emailauthenticated = $context->
msg(
'emailnotauthenticated' )->parse() .
'<br />' .
848 'label' => $context->
msg(
'emailconfirmlink' )->text(),
850 $emailauthenticationclass =
"mw-email-not-authenticated";
853 $disableEmailPrefs =
true;
854 $emailauthenticated = $context->
msg(
'noemailprefs' )->escaped();
855 $emailauthenticationclass =
'mw-email-none';
858 if ( $canViewPrivateInfo ) {
859 $defaultPreferences[
'emailauthentication'] = [
862 'section' =>
'personal/email',
863 'label-message' =>
'prefs-emailconfirm-label',
864 'default' => $emailauthenticated,
866 'cssclass' => $emailauthenticationclass,
874 $defaultPreferences[
'disablemail'] = [
875 'id' =>
'wpAllowEmail',
878 'section' =>
'personal/email',
879 'label-message' =>
'allowemail',
880 'disabled' => $disableEmailPrefs,
883 $defaultPreferences[
'email-allow-new-users'] = [
884 'id' =>
'wpAllowEmailFromNewUsers',
886 'section' =>
'personal/email',
887 'label-message' =>
'email-allow-new-users-label',
888 'disabled' => $disableEmailPrefs,
889 'disable-if' => [
'!==',
'disablemail',
'1' ],
892 $defaultPreferences[
'ccmeonemails'] = [
894 'section' =>
'personal/email',
895 'label-message' =>
'tog-ccmeonemails',
896 'disabled' => $disableEmailPrefs,
900 $defaultPreferences[
'email-blacklist'] = [
901 'type' =>
'usersmultiselect',
902 'label-message' =>
'email-mutelist-label',
903 'section' =>
'personal/email',
904 'disabled' => $disableEmailPrefs,
905 'filter' => MultiUsernameFilter::class,
906 'excludetemp' =>
true,
912 $defaultPreferences[
'enotifwatchlistpages'] = [
914 'section' =>
'personal/email',
915 'label-message' =>
'tog-enotifwatchlistpages',
916 'disabled' => $disableEmailPrefs,
920 $defaultPreferences[
'enotifusertalkpages'] = [
922 'section' =>
'personal/email',
923 'label-message' =>
'tog-enotifusertalkpages',
924 'disabled' => $disableEmailPrefs,
930 $defaultPreferences[
'enotifminoredits'] = [
932 'section' =>
'personal/email',
933 'label-message' =>
'tog-enotifminoredits',
934 'disabled' => $disableEmailPrefs,
939 $defaultPreferences[
'enotifrevealaddr'] = [
941 'section' =>
'personal/email',
942 'label-message' =>
'tog-enotifrevealaddr',
943 'disabled' => $disableEmailPrefs,
958 $validSkinNames = $this->getValidSkinNames( $user, $context );
959 if ( $validSkinNames ) {
960 $defaultPreferences[
'skin'] = [
964 'section' =>
'rendering/skin',
966 $hideCond = [
'AND' ];
967 foreach ( $validSkinNames as $skinName => $_ ) {
968 $options = $this->skinFactory->getSkinOptions( $skinName );
969 if (
$options[
'responsive'] ??
false ) {
970 $hideCond[] = [
'!==',
'skin', $skinName ];
973 if ( $hideCond === [
'AND' ] ) {
976 $defaultPreferences[
'skin-responsive'] = [
978 'label-message' =>
'prefs-skin-responsive',
979 'section' =>
'rendering/skin/skin-prefs',
980 'help-message' =>
'prefs-help-skin-responsive',
981 'hide-if' => $hideCond,
987 $safeMode = $this->userOptionsManager->getOption( $user,
'forcesafemode' );
991 if ( $allowUserCss || $allowUserJs ) {
993 $defaultPreferences[
'customcssjs-safemode'] = [
997 'section' =>
'rendering/skin',
998 'default' =>
new FieldLayout(
1000 'label' =>
new HtmlSnippet( $context->
msg(
'prefs-custom-cssjs-safemode' )->parse() ),
1001 'type' =>
'warning',
1009 if ( $allowUserCss ) {
1010 $cssPage = Title::makeTitleSafe(
NS_USER, $userName .
'/common.css' );
1011 $cssLinkText = $context->
msg(
'prefs-custom-css' )->text();
1012 $linkTools[] = $this->linkRenderer->makeLink( $cssPage, $cssLinkText );
1015 if ( $allowUserJs ) {
1016 $jsPage = Title::makeTitleSafe(
NS_USER, $userName .
'/common.js' );
1017 $jsLinkText = $context->
msg(
'prefs-custom-js' )->text();
1018 $linkTools[] = $this->linkRenderer->makeLink( $jsPage, $jsLinkText );
1021 $defaultPreferences[
'commoncssjs'] = [
1024 'default' => $context->
getLanguage()->pipeList( $linkTools ),
1025 'label-message' =>
'prefs-common-config',
1026 'section' =>
'rendering/skin',
1037 $defaultPreferences[
'imagesize'] = [
1040 'label-message' =>
'imagemaxsize',
1041 'section' =>
'rendering/files',
1043 $defaultPreferences[
'thumbsize'] = [
1046 'label-message' =>
'thumbsize',
1047 'section' =>
'rendering/files',
1061 if ( $dateOptions ) {
1062 $defaultPreferences[
'date'] = [
1064 'options' => $dateOptions,
1065 'section' =>
'rendering/dateformat',
1072 $nowlocal =
Xml::element(
'span', [
'id' =>
'wpLocalTime' ],
1073 $lang->userTime( $now, $user ) );
1074 $nowserver = $lang->userTime( $now, $user,
1075 [
'format' =>
false,
'timecorrection' =>
false ] ) .
1076 Html::hidden(
'wpServerTime', (
int)substr( $now, 8, 2 ) * 60 + (
int)substr( $now, 10, 2 ) );
1078 $defaultPreferences[
'nowserver'] = [
1081 'label-message' =>
'servertime',
1082 'default' => $nowserver,
1083 'section' =>
'rendering/timeoffset',
1086 $defaultPreferences[
'nowlocal'] = [
1089 'label-message' =>
'localtime',
1090 'default' => $nowlocal,
1091 'section' =>
'rendering/timeoffset',
1094 $userTimeCorrection = (string)$this->userOptionsManager->getOption( $user,
'timecorrection' );
1099 $userTimeCorrection,
1104 if ( $userTimeCorrectionObj->getCorrectionType() === UserTimeCorrection::OFFSET ) {
1105 $tzDefault = UserTimeCorrection::formatTimezoneOffset( $userTimeCorrectionObj->getTimeOffset() );
1107 $tzDefault = $userTimeCorrectionObj->toString();
1110 $defaultPreferences[
'timecorrection'] = [
1111 'type' =>
'timezone',
1112 'label-message' =>
'timezonelegend',
1113 'default' => $tzDefault,
1115 'section' =>
'rendering/timeoffset',
1116 'id' =>
'wpTimeCorrection',
1117 'filter' => TimezoneFilter::class,
1129 &$defaultPreferences
1132 $defaultPreferences[
'diffonly'] = [
1134 'section' =>
'rendering/diffs',
1135 'label-message' =>
'tog-diffonly',
1137 $defaultPreferences[
'norollbackdiff'] = [
1139 'section' =>
'rendering/diffs',
1140 'label-message' =>
'tog-norollbackdiff',
1142 $defaultPreferences[
'diff-type'] = [
1148 $defaultPreferences[
'underline'] = [
1151 $l10n->
msg(
'underline-never' )->text() => 0,
1152 $l10n->
msg(
'underline-always' )->text() => 1,
1153 $l10n->
msg(
'underline-default' )->text() => 2,
1155 'label-message' =>
'tog-underline',
1156 'section' =>
'rendering/advancedrendering',
1160 $defaultPreferences[
'showhiddencats'] = [
1162 'section' =>
'rendering/advancedrendering',
1163 'label-message' =>
'tog-showhiddencats'
1167 $defaultPreferences[
'showrollbackconfirmation'] = [
1169 'section' =>
'rendering/advancedrendering',
1170 'label-message' =>
'tog-showrollbackconfirmation',
1174 $defaultPreferences[
'forcesafemode'] = [
1176 'section' =>
'rendering/advancedrendering',
1177 'label-message' =>
'tog-forcesafemode',
1178 'help-message' =>
'prefs-help-forcesafemode'
1188 $defaultPreferences[
'editsectiononrightclick'] = [
1190 'section' =>
'editing/advancedediting',
1191 'label-message' =>
'tog-editsectiononrightclick',
1193 $defaultPreferences[
'editondblclick'] = [
1195 'section' =>
'editing/advancedediting',
1196 'label-message' =>
'tog-editondblclick',
1200 $defaultPreferences[
'editfont'] = [
1202 'section' =>
'editing/editor',
1203 'label-message' =>
'editfont-style',
1205 $l10n->
msg(
'editfont-monospace' )->text() =>
'monospace',
1206 $l10n->
msg(
'editfont-sansserif' )->text() =>
'sans-serif',
1207 $l10n->
msg(
'editfont-serif' )->text() =>
'serif',
1212 if ( $user->
isAllowed(
'minoredit' ) ) {
1213 $defaultPreferences[
'minordefault'] = [
1215 'section' =>
'editing/editor',
1216 'label-message' =>
'tog-minordefault',
1220 $defaultPreferences[
'forceeditsummary'] = [
1222 'section' =>
'editing/editor',
1223 'label-message' =>
'tog-forceeditsummary',
1228 $defaultPreferences[
'editrecovery'] = [
1230 'section' =>
'editing/editor',
1231 'label-message' =>
'tog-editrecovery',
1233 'tog-editrecovery-help',
1234 'https://meta.wikimedia.org/wiki/Talk:Community_Wishlist_Survey_2023/Edit-recovery_feature',
1239 $defaultPreferences[
'useeditwarning'] = [
1241 'section' =>
'editing/editor',
1242 'label-message' =>
'tog-useeditwarning',
1245 $defaultPreferences[
'previewonfirst'] = [
1247 'section' =>
'editing/preview',
1248 'label-message' =>
'tog-previewonfirst',
1250 $defaultPreferences[
'previewontop'] = [
1252 'section' =>
'editing/preview',
1253 'label-message' =>
'tog-previewontop',
1255 $defaultPreferences[
'uselivepreview'] = [
1257 'section' =>
'editing/preview',
1258 'label-message' =>
'tog-uselivepreview',
1269 $rcMax = ceil( $rcMaxAge / ( 3600 * 24 ) );
1270 $defaultPreferences[
'rcdays'] = [
1272 'label-message' =>
'recentchangesdays',
1273 'section' =>
'rc/displayrc',
1278 $defaultPreferences[
'rclimit'] = [
1282 'label-message' =>
'recentchangescount',
1283 'help-message' =>
'prefs-help-recentchangescount',
1284 'section' =>
'rc/displayrc',
1285 'filter' => IntvalFilter::class,
1287 $defaultPreferences[
'usenewrc'] = [
1289 'label-message' =>
'tog-usenewrc',
1290 'section' =>
'rc/advancedrc',
1292 $defaultPreferences[
'hideminor'] = [
1294 'label-message' =>
'tog-hideminor',
1295 'section' =>
'rc/changesrc',
1297 $defaultPreferences[
'pst-cssjs'] = [
1300 $defaultPreferences[
'rcfilters-rc-collapsed'] = [
1303 $defaultPreferences[
'rcfilters-wl-collapsed'] = [
1306 $defaultPreferences[
'rcfilters-saved-queries'] = [
1309 $defaultPreferences[
'rcfilters-wl-saved-queries'] = [
1313 $defaultPreferences[
'rcfilters-limit'] = [
1316 $defaultPreferences[
'rcfilters-saved-queries-versionbackup'] = [
1319 $defaultPreferences[
'rcfilters-wl-saved-queries-versionbackup'] = [
1324 $defaultPreferences[
'hidecategorization'] = [
1326 'label-message' =>
'tog-hidecategorization',
1327 'section' =>
'rc/changesrc',
1332 $defaultPreferences[
'hidepatrolled'] = [
1334 'section' =>
'rc/changesrc',
1335 'label-message' =>
'tog-hidepatrolled',
1340 $defaultPreferences[
'newpageshidepatrolled'] = [
1342 'section' =>
'rc/changesrc',
1343 'label-message' =>
'tog-newpageshidepatrolled',
1348 $defaultPreferences[
'shownumberswatching'] = [
1350 'section' =>
'rc/advancedrc',
1351 'label-message' =>
'tog-shownumberswatching',
1355 $defaultPreferences[
'rcenhancedfilters-disable'] = [
1357 'section' =>
'rc/advancedrc',
1358 'label-message' =>
'rcfilters-preference-label',
1359 'help-message' =>
'rcfilters-preference-help',
1373 if ( $user->
isAllowed(
'editmywatchlist' ) ) {
1374 $editWatchlistLinks =
'';
1375 $editWatchlistModes = [
1376 'edit' => [
'subpage' =>
false,
'flags' => [] ],
1377 'raw' => [
'subpage' =>
'raw',
'flags' => [] ],
1378 'clear' => [
'subpage' =>
'clear',
'flags' => [
'destructive' ] ],
1380 foreach ( $editWatchlistModes as $mode =>
$options ) {
1382 $editWatchlistLinks .=
1386 'label' =>
new HtmlSnippet(
1387 $context->
msg(
"prefs-editwatchlist-{$mode}" )->parse()
1392 $defaultPreferences[
'editwatchlist'] = [
1395 'default' => $editWatchlistLinks,
1396 'label-message' =>
'prefs-editwatchlist-label',
1397 'section' =>
'watchlist/editwatchlist',
1401 $defaultPreferences[
'watchlistdays'] = [
1404 'max' => $watchlistdaysMax,
1405 'section' =>
'watchlist/displaywatchlist',
1406 'help-message' => [
'prefs-watchlist-days-max',
Message::numParam( $watchlistdaysMax ) ],
1407 'label-message' =>
'prefs-watchlist-days',
1409 $defaultPreferences[
'wllimit'] = [
1413 'label-message' =>
'prefs-watchlist-edits',
1414 'help-message' =>
'prefs-watchlist-edits-max',
1415 'section' =>
'watchlist/displaywatchlist',
1416 'filter' => IntvalFilter::class,
1418 $defaultPreferences[
'extendwatchlist'] = [
1420 'section' =>
'watchlist/advancedwatchlist',
1421 'label-message' =>
'tog-extendwatchlist',
1423 $defaultPreferences[
'watchlisthideminor'] = [
1425 'section' =>
'watchlist/changeswatchlist',
1426 'label-message' =>
'tog-watchlisthideminor',
1428 $defaultPreferences[
'watchlisthidebots'] = [
1430 'section' =>
'watchlist/changeswatchlist',
1431 'label-message' =>
'tog-watchlisthidebots',
1433 $defaultPreferences[
'watchlisthideown'] = [
1435 'section' =>
'watchlist/changeswatchlist',
1436 'label-message' =>
'tog-watchlisthideown',
1438 $defaultPreferences[
'watchlisthideanons'] = [
1440 'section' =>
'watchlist/changeswatchlist',
1441 'label-message' =>
'tog-watchlisthideanons',
1443 $defaultPreferences[
'watchlisthideliu'] = [
1445 'section' =>
'watchlist/changeswatchlist',
1446 'label-message' =>
'tog-watchlisthideliu',
1450 $defaultPreferences[
'watchlistreloadautomatically'] = [
1452 'section' =>
'watchlist/advancedwatchlist',
1453 'label-message' =>
'tog-watchlistreloadautomatically',
1457 $defaultPreferences[
'watchlistunwatchlinks'] = [
1459 'section' =>
'watchlist/advancedwatchlist',
1460 'label-message' =>
'tog-watchlistunwatchlinks',
1464 $defaultPreferences[
'watchlisthidecategorization'] = [
1466 'section' =>
'watchlist/changeswatchlist',
1467 'label-message' =>
'tog-watchlisthidecategorization',
1472 $defaultPreferences[
'watchlisthidepatrolled'] = [
1474 'section' =>
'watchlist/changeswatchlist',
1475 'label-message' =>
'tog-watchlisthidepatrolled',
1480 'edit' =>
'watchdefault',
1481 'move' =>
'watchmoves',
1485 if ( $user->
isAllowedAny(
'createpage',
'createtalk' ) ) {
1486 $watchTypes[
'read'] =
'watchcreations';
1491 'rollback' =>
'watchrollback',
1492 'upload' =>
'watchuploads',
1493 'delete' =>
'watchdeletion',
1496 foreach ( $watchTypes as $action => $pref ) {
1501 $defaultPreferences[$pref] = [
1503 'section' =>
'watchlist/pageswatchlist',
1504 'label-message' =>
"tog-$pref",
1509 $defaultPreferences[
'watchlisttoken'] = [
1513 $tokenButton =
new ButtonWidget( [
1517 'label' => $context->
msg(
'prefs-watchlist-managetokens' )->text(),
1519 $defaultPreferences[
'watchlisttoken-info'] = [
1521 'section' =>
'watchlist/tokenwatchlist',
1522 'label-message' =>
'prefs-watchlist-token',
1523 'help-message' =>
'prefs-help-tokenmanagement',
1525 'default' => (string)$tokenButton,
1528 $defaultPreferences[
'wlenhancedfilters-disable'] = [
1530 'section' =>
'watchlist/advancedwatchlist',
1531 'label-message' =>
'rcfilters-watchlist-preference-label',
1532 'help-message' =>
'rcfilters-watchlist-preference-help',
1541 $defaultPreferences[
'search-special-page'] = [
1545 foreach ( $this->nsInfo->getValidNamespaces() as $n ) {
1546 $defaultPreferences[
'searchNs' . $n] = [
1552 $defaultPreferences[
'search-match-redirect'] = [
1554 'section' =>
'searchoptions/searchmisc',
1555 'label-message' =>
'search-match-redirect-label',
1556 'help-message' =>
'search-match-redirect-help',
1559 $defaultPreferences[
'search-match-redirect'] = [
1564 $defaultPreferences[
'searchlimit'] = [
1568 'section' =>
'searchoptions/searchmisc',
1569 'label-message' =>
'searchlimit-label',
1570 'help-message' => $context->
msg(
'searchlimit-help', 500 ),
1571 'filter' => IntvalFilter::class,
1577 $thumbNamespacesFormatted = array_combine(
1580 static function ( $namespaceId ) use ( $context ) {
1581 return $namespaceId ===
NS_MAIN
1582 ? $context->
msg(
'blanknamespace' )->escaped()
1583 : $context->
getLanguage()->getFormattedNsText( $namespaceId );
1588 $defaultThumbNamespacesFormatted =
1589 array_intersect_key( $thumbNamespacesFormatted, [
NS_FILE => 1 ] ) ?? [];
1590 $extraThumbNamespacesFormatted =
1591 array_diff_key( $thumbNamespacesFormatted, [
NS_FILE => 1 ] );
1592 if ( $extraThumbNamespacesFormatted ) {
1593 $defaultPreferences[
'search-thumbnail-extra-namespaces'] = [
1595 'section' =>
'searchoptions/searchmisc',
1596 'label-message' =>
'search-thumbnail-extra-namespaces-label',
1597 'help-message' => $context->
msg(
1598 'search-thumbnail-extra-namespaces-message',
1599 $context->
getLanguage()->listToText( $extraThumbNamespacesFormatted ),
1600 count( $extraThumbNamespacesFormatted ),
1601 $context->
getLanguage()->listToText( $defaultThumbNamespacesFormatted ),
1602 count( $defaultThumbNamespacesFormatted )
1617 private static function sortSkinNames( $a, $b, $currentSkin, $preferredSkins ) {
1619 if ( strcasecmp( $a, $currentSkin ) === 0 ) {
1622 if ( strcasecmp( $b, $currentSkin ) === 0 ) {
1626 if ( count( $preferredSkins ) ) {
1627 $aPreferred = array_search( $a, $preferredSkins );
1628 $bPreferred = array_search( $b, $preferredSkins );
1631 if ( $aPreferred !==
false && $bPreferred ===
false ) {
1634 if ( $aPreferred ===
false && $bPreferred !==
false ) {
1639 if ( $aPreferred !==
false && $bPreferred !==
false ) {
1640 return strcasecmp( $aPreferred, $bPreferred );
1644 return strcasecmp( $a, $b );
1655 private function getValidSkinNames( User $user, IContextSource $context ) {
1657 $validSkinNames = $this->skinFactory->getAllowedSkins();
1658 $allInstalledSkins = $this->skinFactory->getInstalledSkins();
1661 $useSkin = $context->getRequest()->getRawVal(
'useskin' );
1662 if ( $useSkin !==
null && isset( $allInstalledSkins[$useSkin] )
1663 && $context->msg(
"skinname-$useSkin" )->exists()
1665 $validSkinNames[$useSkin] = $useSkin;
1669 $currentUserSkin = $this->userOptionsManager->getOption( $user,
'skin' );
1670 if ( isset( $allInstalledSkins[$currentUserSkin] )
1671 && $context->msg(
"skinname-$currentUserSkin" )->exists()
1673 $validSkinNames[$currentUserSkin] = $currentUserSkin;
1676 foreach ( $validSkinNames as $skinkey => &$skinname ) {
1677 $msg = $context->msg(
"skinname-{$skinkey}" );
1678 if ( $msg->exists() ) {
1679 $skinname = htmlspecialchars( $msg->text() );
1686 uksort( $validSkinNames,
function ( $a, $b ) use ( $currentUserSkin, $preferredSkins ) {
1687 return $this->sortSkinNames( $a, $b, $currentUserSkin, $preferredSkins );
1690 return $validSkinNames;
1702 $mptitle = Title::newMainPage();
1703 $previewtext = $context->
msg(
'skin-preview' )->escaped();
1707 $safeMode = $this->userOptionsManager->getOption( $user,
'forcesafemode' );
1708 $foundDefault =
false;
1709 foreach ( $validSkinNames as $skinkey => $sn ) {
1713 if ( strcasecmp( $skinkey, $defaultSkin ) === 0 ) {
1714 $linkTools[] = $context->
msg(
'default' )->escaped();
1715 $foundDefault =
true;
1719 $talkPageMsg = $context->
msg(
"$skinkey-prefs-talkpage" );
1720 if ( $talkPageMsg->exists() ) {
1721 $linkTools[] = $talkPageMsg->parse();
1725 $mplink = htmlspecialchars( $mptitle->getLocalURL( [
'useskin' => $skinkey ] ) );
1726 $linkTools[] =
"<a target='_blank' href=\"$mplink\">$previewtext</a>";
1731 if ( $allowUserCss ) {
1732 $cssPage = Title::makeTitleSafe(
NS_USER, $user->
getName() .
'/' . $skinkey .
'.css' );
1733 $cssLinkText = $context->
msg(
'prefs-custom-css' )->text();
1734 $linkTools[] = $this->linkRenderer->makeLink( $cssPage, $cssLinkText );
1737 if ( $allowUserJs ) {
1738 $jsPage = Title::makeTitleSafe(
NS_USER, $user->
getName() .
'/' . $skinkey .
'.js' );
1739 $jsLinkText = $context->
msg(
'prefs-custom-js' )->text();
1740 $linkTools[] = $this->linkRenderer->makeLink( $jsPage, $jsLinkText );
1744 $display = $sn .
' ' . $context->
msg(
'parentheses' )
1745 ->rawParams( $context->
getLanguage()->pipeList( $linkTools ) )
1747 $ret[$display] = $skinkey;
1750 if ( !$foundDefault ) {
1765 $dateopts = $lang->getDatePreferences();
1770 if ( !in_array(
'default', $dateopts ) ) {
1771 $dateopts[] =
'default';
1781 foreach ( $dateopts as $key ) {
1782 if ( $key ==
'default' ) {
1783 $formatted = $context->
msg(
'datedefault' )->escaped();
1785 $formatted = htmlspecialchars( $lang->timeanddate( $epoch,
false, $key ) );
1787 $ret[$formatted] = $key;
1799 $pixels = $l10n->
msg(
'unit-pixel' )->text();
1803 $display =
"{$limits[0]}\u{200E}×{$limits[1]}$pixels";
1804 $ret[$display] = $index;
1816 $pixels = $l10n->
msg(
'unit-pixel' )->text();
1819 $display = $size . $pixels;
1820 $ret[$display] = $index;
1835 if ( is_string( $signature ) && mb_strlen( $signature ) > $maxSigChars ) {
1836 return $form->
msg(
'badsiglength' )->numParams( $maxSigChars )->escaped();
1839 if ( $signature ===
null || $signature ===
'' ) {
1846 if ( !( isset( $alldata[
'fancysig'] ) && $alldata[
'fancysig'] ) ) {
1863 $signature === $this->userOptionsManager->getOption( $user,
'nickname' ) &&
1864 (
bool)$alldata[
'fancysig'] === $this->userOptionsManager->getBoolOption( $user,
'fancysig' )
1869 if ( $sigValidation ===
'new' || $sigValidation ===
'disallow' ) {
1871 $parserOpts = ParserOptions::newFromContext( $form->
getContext() );
1872 $validator = $this->signatureValidatorFactory
1873 ->newSignatureValidator( $user, $form->
getContext(), $parserOpts );
1874 $errors = $validator->validateSignature( $signature );
1883 if ( $this->parserFactory->getInstance()->validateSig( $signature ) ===
false ) {
1884 return $form->
msg(
'badsig' )->escaped();
1897 if ( isset( $alldata[
'fancysig'] ) && $alldata[
'fancysig'] ) {
1898 $signature = $this->parserFactory->getInstance()->cleanSig( $signature );
1901 $signature = Parser::cleanSigInSig( $signature );
1917 $formClass = PreferencesFormOOUI::class,
1925 if ( count( $remove ) ) {
1926 $removeKeys = array_fill_keys( $remove,
true );
1927 $formDescriptor = array_diff_key( $formDescriptor, $removeKeys );
1931 foreach ( $formDescriptor as $name => $info ) {
1932 if ( isset( $info[
'type'] ) && $info[
'type'] ===
'api' ) {
1933 unset( $formDescriptor[$name] );
1940 $htmlForm =
new $formClass( $formDescriptor, $context,
'prefs' );
1946 $htmlForm->setAction( $context->
getTitle()->getLocalURL( [
1947 'useskin' => $context->
getRequest()->getRawVal(
'useskin' )
1950 $htmlForm->setModifiedUser( $user );
1951 $htmlForm->setOptionsEditable( $user->
isAllowed(
'editmyoptions' ) );
1952 $htmlForm->setPrivateInfoEditable( $user->
isAllowed(
'editmyprivateinfo' ) );
1953 $htmlForm->setId(
'mw-prefs-form' );
1954 $htmlForm->setAutocomplete(
'off' );
1955 $htmlForm->setSubmitTextMsg(
'saveprefs' );
1957 $htmlForm->setSubmitTooltip(
'preferences-save' );
1958 $htmlForm->setSubmitID(
'prefcontrol' );
1959 $htmlForm->setSubmitCallback(
1961 return $this->
submitForm( $formData, $form, $formDescriptor );
1981 if ( !$user->isAllowedAny(
'editmyprivateinfo',
'editmyoptions' ) ) {
1982 return Status::newFatal(
'mypreferencesprotected' );
1986 $this->
applyFilters( $formData, $formDescriptor,
'filterFromForm' );
1991 if ( !in_array(
'realname', $hiddenPrefs )
1992 && $user->isAllowed(
'editmyprivateinfo' )
1993 && array_key_exists(
'realname', $formData )
1995 $realName = $formData[
'realname'];
1996 $user->setRealName( $realName );
1999 if ( $user->isAllowed(
'editmyoptions' ) ) {
2000 $oldUserOptions = $this->userOptionsManager->getOptions( $user );
2003 unset( $formData[$b] );
2009 foreach ( $hiddenPrefs as $pref ) {
2012 $formData[$pref] = $this->userOptionsManager->getOption( $user, $pref,
null,
true );
2017 isset( $formData[
'rclimit'] ) &&
2018 intval( $formData[
'rclimit' ] ) !== $this->userOptionsManager->getIntOption( $user,
'rclimit' )
2020 $formData[
'rcfilters-limit'] = $formData[
'rclimit'];
2025 $this->userOptionsManager->resetOptionsByName( $user, $optionsToReset );
2027 foreach ( $formData as $key => $value ) {
2031 $except = !empty( $formData[$key . UserOptionsLookup::LOCAL_EXCEPTION_SUFFIX] );
2032 $this->userOptionsManager->setOption( $user, $key, $value,
2033 $except ? UserOptionsManager::GLOBAL_OVERRIDE : UserOptionsManager::GLOBAL_IGNORE );
2036 $this->hookRunner->onPreferencesFormPreSave(
2037 $formData, $form, $user, $result, $oldUserOptions );
2040 $user->saveSettings();
2053 protected function applyFilters( array &$preferences, array $formDescriptor, $verb ) {
2054 foreach ( $formDescriptor as $preference => $desc ) {
2055 if ( !isset( $desc[
'filter'] ) || !isset( $preferences[$preference] ) ) {
2058 $filterDesc = $desc[
'filter'];
2059 if ( $filterDesc instanceof
Filter ) {
2060 $filter = $filterDesc;
2061 } elseif ( class_exists( $filterDesc ) ) {
2062 $filter =
new $filterDesc();
2063 } elseif ( is_callable( $filterDesc ) ) {
2064 $filter = $filterDesc();
2066 throw new UnexpectedValueException(
2067 "Unrecognized filter type for preference '$preference'"
2070 $preferences[$preference] = $filter->$verb( $preferences[$preference] );
2085 array $formDescriptor
2087 $res = $this->
saveFormData( $formData, $form, $formDescriptor );
2089 if ( $res ===
true ) {
2098 $context->getRequest()->getSession()->set(
'specialPreferencesSaveSuccess', 1 );
2100 $context->getOutput()->redirect(
$url );
2103 return ( $res ===
true ? Status::newGood() : $res );
2109 $options ??= $this->userOptionsManager->loadUserOptions( $user );
2117 foreach ( $specialOptions as $name => $value ) {
2118 unset( $prefs[$name] );
2123 $multiselectOptions = [];
2124 foreach ( $prefs as $name => $info ) {
2125 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'multiselect' ) ||
2127 ( isset( $info[
'class'] ) && $info[
'class'] === \HTMLMultiSelectField::class ) ||
2128 ( isset( $info[
'class'] ) && $info[
'class'] === HTMLMultiSelectField::class )
2130 $opts = HTMLFormField::flattenOptions( $info[
'options'] ?? $info[
'options-messages'] );
2131 $prefix = $info[
'prefix'] ?? $name;
2133 foreach ( $opts as $value ) {
2134 $multiselectOptions[
"$prefix$value"] =
true;
2137 unset( $prefs[$name] );
2140 $checkmatrixOptions = [];
2141 foreach ( $prefs as $name => $info ) {
2142 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'checkmatrix' ) ||
2144 ( isset( $info[
'class'] ) && $info[
'class'] === \HTMLCheckMatrix::class ) ||
2145 ( isset( $info[
'class'] ) && $info[
'class'] === HTMLCheckMatrix::class )
2147 $columns = HTMLFormField::flattenOptions( $info[
'columns'] );
2148 $rows = HTMLFormField::flattenOptions( $info[
'rows'] );
2149 $prefix = $info[
'prefix'] ?? $name;
2151 foreach ( $columns as $column ) {
2152 foreach ( $rows as $row ) {
2153 $checkmatrixOptions[
"$prefix$column-$row"] =
true;
2157 unset( $prefs[$name] );
2162 foreach (
$options as $key => $value ) {
2163 if ( isset( $prefs[$key] ) ) {
2164 $mapping[$key] =
'registered';
2165 } elseif ( isset( $multiselectOptions[$key] ) ) {
2166 $mapping[$key] =
'registered-multiselect';
2167 } elseif ( isset( $checkmatrixOptions[$key] ) ) {
2168 $mapping[$key] =
'registered-checkmatrix';
2169 } elseif ( isset( $specialOptions[$key] ) ) {
2170 $mapping[$key] =
'special';
2171 } elseif ( str_starts_with( $key,
'userjs-' ) ) {
2172 $mapping[$key] =
'userjs';
2173 } elseif ( str_starts_with( $key, UserOptionsLookup::LOCAL_EXCEPTION_SUFFIX ) ) {
2174 $mapping[$key] =
'local-exception';
2176 $mapping[$key] =
'unused';
2186 'registered-multiselect',
2187 'registered-checkmatrix',
2195 $oldOptions = $this->userOptionsManager->loadUserOptions( $user, IDBAccessObject::READ_LATEST );
2197 if ( !is_array( $kinds ) ) {
2198 $kinds = [ $kinds ];
2201 if ( in_array(
'all', $kinds ) ) {
2202 return array_keys( $oldOptions );
2204 $optionKinds = $this->getResetKinds( $user, $context );
2205 $kinds = array_intersect( $kinds, $this->listResetKinds() );
2208 foreach ( $oldOptions as $key => $value ) {
2209 if ( in_array( $optionKinds[$key], $kinds ) ) {
2210 $optionNames[] = $key;
2213 return $optionNames;
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
array $params
The job parameters.
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
getContext()
Get the base IContextSource object.
A class containing constants representing the names of configuration variables.
const HiddenPrefs
Name constant for the HiddenPrefs setting, for use with Config::get()
const ForceHTTPS
Name constant for the ForceHTTPS setting, for use with Config::get()
const EnotifWatchlist
Name constant for the EnotifWatchlist setting, for use with Config::get()
const MaxSigChars
Name constant for the MaxSigChars setting, for use with Config::get()
const RCMaxAge
Name constant for the RCMaxAge setting, for use with Config::get()
const DefaultSkin
Name constant for the DefaultSkin setting, for use with Config::get()
const EnableUserEmailMuteList
Name constant for the EnableUserEmailMuteList setting, for use with Config::get()
const EnotifRevealEditorAddress
Name constant for the EnotifRevealEditorAddress setting, for use with Config::get()
const EnableUserEmail
Name constant for the EnableUserEmail setting, for use with Config::get()
const SkinsPreferred
Name constant for the SkinsPreferred setting, for use with Config::get()
const EnableEditRecovery
Name constant for the EnableEditRecovery setting, for use with Config::get()
const EmailConfirmToEdit
Name constant for the EmailConfirmToEdit setting, for use with Config::get()
const EnableEmail
Name constant for the EnableEmail setting, for use with Config::get()
const LocalTZoffset
Name constant for the LocalTZoffset setting, for use with Config::get()
const RCShowWatchingUsers
Name constant for the RCShowWatchingUsers setting, for use with Config::get()
const EnotifUserTalk
Name constant for the EnotifUserTalk setting, for use with Config::get()
const AllowUserJs
Name constant for the AllowUserJs setting, for use with Config::get()
const ImageLimits
Name constant for the ImageLimits setting, for use with Config::get()
const SearchMatchRedirectPreference
Name constant for the SearchMatchRedirectPreference setting, for use with Config::get()
const EnotifMinorEdits
Name constant for the EnotifMinorEdits setting, for use with Config::get()
const ScriptPath
Name constant for the ScriptPath setting, for use with Config::get()
const AllowUserCss
Name constant for the AllowUserCss setting, for use with Config::get()
const ThumbLimits
Name constant for the ThumbLimits setting, for use with Config::get()
const SecureLogin
Name constant for the SecureLogin setting, for use with Config::get()
const LanguageCode
Name constant for the LanguageCode setting, for use with Config::get()
const SignatureValidation
Name constant for the SignatureValidation setting, for use with Config::get()
const AllowUserCssPrefs
Name constant for the AllowUserCssPrefs setting, for use with Config::get()
const RCWatchCategoryMembership
Name constant for the RCWatchCategoryMembership setting, for use with Config::get()
const ThumbnailNamespaces
Name constant for the ThumbnailNamespaces setting, for use with Config::get()
const EmailAuthentication
Name constant for the EmailAuthentication setting, for use with Config::get()
This is one of the Core classes and should be read at least once by any new developers.
Parent class for all special pages.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
Factory class to create Skin objects.
$wgDefaultUserOptions
Config variable stub for the DefaultUserOptions setting, for use by phpdoc and IDEs.
Interface for objects which can provide a MediaWiki context on request.
Interface for localizing messages in MediaWiki.
msg( $key,... $params)
This is the method for getting translated interface messages.