70use Psr\Log\LoggerAwareTrait;
71use Psr\Log\NullLogger;
73use UnexpectedValueException;
103 private $languageConverter;
112 private $languageConverterFactory;
115 private $parserFactory;
118 private $skinFactory;
121 private $userGroupManager;
124 private $signatureValidatorFactory;
209 $this->logger =
new NullLogger();
210 $this->languageConverter = $languageConverter;
212 $this->hookRunner =
new HookRunner( $hookContainer );
216 $services =
static function () {
222 : $services()->getUserOptionsManager();
223 $this->languageConverterFactory = $languageConverterFactory ?? $services()->getLanguageConverterFactory();
225 $this->parserFactory = $parserFactory ?? $services()->getParserFactory();
226 $this->skinFactory = $skinFactory ?? $services()->getSkinFactory();
227 $this->userGroupManager = $userGroupManager ?? $services()->getUserGroupManager();
228 $this->signatureValidatorFactory = $signatureValidatorFactory
229 ?? $services()->getSignatureValidatorFactory();
250 OutputPage::setupOOUI(
251 strtolower( $context->
getSkin()->getSkinName() ),
265 $this->hookRunner->onGetPreferences( $user, $preferences );
267 $this->loadPreferenceValues( $user, $context, $preferences );
268 $this->logger->debug(
"Created form descriptor for user '{$user->getName()}'" );
279 foreach ( $descriptor as $name => &
$params ) {
282 if ( ( isset(
$params[
'type'] ) &&
$params[
'type'] ===
'info' ) ||
284 ( isset(
$params[
'class'] ) &&
$params[
'class'] === \HTMLInfoField::class ) ||
285 ( isset(
$params[
'class'] ) &&
$params[
'class'] === HTMLInfoField::class )
287 unset( $descriptor[$name] );
292 foreach (
$params as $key => $value ) {
295 case 'options-message':
298 case 'options-messages':
303 if ( preg_match(
'/-messages?$/', $key ) ) {
320 private function loadPreferenceValues(
User $user,
IContextSource $context, &$defaultPreferences ) {
323 unset( $defaultPreferences[$pref] );
328 $form =
new HTMLForm( $simplified, $context );
330 $disable = !$user->
isAllowed(
'editmyoptions' );
332 $defaultOptions = $this->userOptionsManager->getDefaultOptions( $user );
333 $userOptions = $this->userOptionsManager->getOptions( $user );
334 $this->
applyFilters( $userOptions, $defaultPreferences,
'filterForForm' );
336 foreach ( $simplified as $name => $_ ) {
337 $info = &$defaultPreferences[$name];
339 $info[
'disabled'] =
'disabled';
341 if ( isset( $info[
'default'] ) ) {
345 $field = $form->getField( $name );
346 $globalDefault = $defaultOptions[$name] ??
null;
347 $prefFromUser = static::getPreferenceForField( $name, $field, $userOptions );
352 if ( $prefFromUser !==
null &&
353 $field->validate( $prefFromUser, $this->userOptionsManager->getOptions( $user ) ) ===
true ) {
354 $info[
'default'] = $prefFromUser;
355 } elseif ( $field->validate( $globalDefault, $this->userOptionsManager->getOptions( $user ) ) ===
true ) {
356 $info[
'default'] = $globalDefault;
358 $globalDefault = json_encode( $globalDefault );
359 throw new UnexpectedValueException(
360 "Default '$globalDefault' is invalid for preference $name of user " . $user->
getName()
365 return $defaultPreferences;
379 $val = $userOptions[$name] ??
null;
383 $prefix = $field->mParams[
'prefix'] ?? $name;
385 $keys = array_keys( $field->filterDataForSubmit( [] ) );
386 foreach ( $keys as $key ) {
387 if ( $userOptions[$prefix . $key] ??
false ) {
406 $val = $userOptions[$name] ??
null;
409 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'multiselect' ) ||
411 ( isset( $info[
'class'] ) && $info[
'class'] === \HTMLMultiSelectField::class ) ||
412 ( isset( $info[
'class'] ) && $info[
'class'] === HTMLMultiSelectField::class )
414 $options = HTMLFormField::flattenOptions( $info[
'options-messages'] ?? $info[
'options'] );
415 $prefix = $info[
'prefix'] ?? $name;
419 if ( $userOptions[
"$prefix$value"] ??
false ) {
426 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'checkmatrix' ) ||
428 ( isset( $info[
'class'] ) && $info[
'class'] === \HTMLCheckMatrix::class ) ||
429 ( isset( $info[
'class'] ) && $info[
'class'] === HTMLCheckMatrix::class )
431 $columns = HTMLFormField::flattenOptions( $info[
'columns'] );
432 $rows = HTMLFormField::flattenOptions( $info[
'rows'] );
433 $prefix = $info[
'prefix'] ?? $name;
436 foreach ( $columns as $column ) {
437 foreach ( $rows as $row ) {
438 if ( $userOptions[
"$prefix$column-$row"] ??
false ) {
439 $val[] =
"$column-$row";
462 $defaultPreferences[
'username'] = [
464 'label-message' => [
'username', $userName ],
465 'default' => $userName,
466 'section' =>
'personal/info',
472 $userEffectiveGroups = array_diff(
473 $this->userGroupManager->getUserEffectiveGroups( $user ),
476 $defaultPreferences[
'usergroups'] = [
478 'label-message' => [
'prefs-memberingroups',
480 'default' =>
function () use ( $user, $userEffectiveGroups, $context, $lang, $userName ) {
481 $userGroupMemberships = $this->userGroupManager->getUserGroupMemberships( $user );
482 $userGroups = $userMembers = $userTempGroups = $userTempMembers = [];
483 foreach ( $userEffectiveGroups as $ueg ) {
484 $groupStringOrObject = $userGroupMemberships[$ueg] ?? $ueg;
486 $userG = UserGroupMembership::getLinkHTML( $groupStringOrObject, $context );
487 $userM = UserGroupMembership::getLinkHTML( $groupStringOrObject, $context, $userName );
496 $userTempGroups[] = $userG;
497 $userTempMembers[] = $userM;
499 $userGroups[] = $userG;
500 $userMembers[] = $userM;
504 sort( $userMembers );
505 sort( $userTempGroups );
506 sort( $userTempMembers );
507 $userGroups = array_merge( $userTempGroups, $userGroups );
508 $userMembers = array_merge( $userTempMembers, $userMembers );
509 return $context->
msg(
'prefs-memberingroups-type' )
510 ->rawParams( $lang->commaList( $userGroups ), $lang->commaList( $userMembers ) )
514 'section' =>
'personal/info',
518 $formattedEditCount = $lang->formatNum( $user->
getEditCount() );
519 $editCount = $this->linkRenderer->makeLink( $contribTitle, $formattedEditCount );
521 $defaultPreferences[
'editcount'] = [
524 'label-message' =>
'prefs-edits',
525 'default' => $editCount,
526 'section' =>
'personal/info',
530 $displayUser = $context->
getUser();
532 $defaultPreferences[
'registrationdate'] = [
534 'label-message' =>
'prefs-registration',
535 'default' => $context->
msg(
536 'prefs-registration-date-time',
537 $lang->userTimeAndDate( $userRegistration, $displayUser ),
538 $lang->userDate( $userRegistration, $displayUser ),
539 $lang->userTime( $userRegistration, $displayUser )
541 'section' =>
'personal/info',
545 $canViewPrivateInfo = $user->
isAllowed(
'viewmyprivateinfo' );
546 $canEditPrivateInfo = $user->
isAllowed(
'editmyprivateinfo' );
549 $defaultPreferences[
'realname'] = [
551 'type' => $canEditPrivateInfo && $this->authManager->allowsPropertyChange(
'realname' )
554 'section' =>
'personal/info',
555 'label-message' =>
'yourrealname',
556 'help-message' =>
'prefs-help-realname',
559 if ( $canEditPrivateInfo && $this->authManager->allowsAuthenticationDataChange(
562 $defaultPreferences[
'password'] = [
565 'default' => (string)
new ButtonWidget( [
569 'label' => $context->
msg(
'prefs-resetpass' )->text(),
571 'label-message' =>
'yourpassword',
574 ? $context->
msg(
'prefs-help-yourpassword',
575 '[[#mw-prefsection-personal-email|{{int:prefs-email}}]]' )->parse()
577 'section' =>
'personal/info',
584 $defaultPreferences[
'prefershttps'] = [
586 'label-message' =>
'tog-prefershttps',
587 'help-message' =>
'prefs-help-prefershttps',
588 'section' =>
'personal/info'
592 $defaultPreferences[
'downloaduserdata'] = [
595 'label-message' =>
'prefs-user-downloaddata-label',
600 '/api.php?action=query&meta=userinfo&uiprop=*&formatversion=2',
602 $context->
msg(
'prefs-user-downloaddata-info' )->text()
604 'help-message' => [
'prefs-user-downloaddata-help-message', urlencode( $user->
getTitleKey() ) ],
605 'section' =>
'personal/info',
608 $defaultPreferences[
'restoreprefs'] = [
611 'label-message' =>
'prefs-user-restoreprefs-label',
616 ->getSubpage(
'reset' )->getLocalURL()
618 $context->
msg(
'prefs-user-restoreprefs-info' )->text()
620 'section' =>
'personal/info',
623 $languages = $this->languageNameUtils->getLanguageNames(
624 LanguageNameUtils::AUTONYMS,
625 LanguageNameUtils::SUPPORTED
628 if ( !array_key_exists( $languageCode, $languages ) ) {
629 $languages[$languageCode] = $languageCode;
635 foreach ( $languages as $code => $name ) {
636 $display = LanguageCode::bcp47( $code ) .
' - ' . $name;
639 $defaultPreferences[
'language'] = [
641 'section' =>
'personal/i18n',
643 'label-message' =>
'yourlanguage',
646 $neutralGenderMessage = $context->
msg(
'gender-notknown' )->escaped() . (
647 !$context->
msg(
'gender-unknown' )->isDisabled()
648 ?
"<br>" . $context->
msg(
'parentheses' )
649 ->params( $context->
msg(
'gender-unknown' )->plain() )
654 $defaultPreferences[
'gender'] = [
656 'section' =>
'personal/i18n',
658 $neutralGenderMessage =>
'unknown',
659 $context->
msg(
'gender-female' )->escaped() =>
'female',
660 $context->
msg(
'gender-male' )->escaped() =>
'male',
662 'label-message' =>
'yourgender',
663 'help-message' =>
'prefs-help-gender',
667 if ( !$this->languageConverterFactory->isConversionDisabled() ) {
669 foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
670 if ( $langCode == $this->contLang->getCode() ) {
671 if ( !$this->languageConverter->hasVariants() ) {
675 $variants = $this->languageConverter->getVariants();
677 foreach ( $variants as $v ) {
678 $v = str_replace(
'_',
'-', strtolower( $v ) );
679 $variantArray[$v] = $lang->getVariantname( $v,
false );
683 foreach ( $variantArray as $code => $name ) {
684 $display = LanguageCode::bcp47( $code ) .
' - ' . $name;
688 $defaultPreferences[
'variant'] = [
689 'label-message' =>
'yourvariant',
692 'section' =>
'personal/i18n',
693 'help-message' =>
'prefs-help-variant',
696 $defaultPreferences[
"variant-$langCode"] = [
704 $oldsigWikiText = $this->parserFactory->getInstance()->preSaveTransform(
708 ParserOptions::newFromContext( $context )
710 $oldsigHTML = Parser::stripOuterParagraph(
711 $context->
getOutput()->parseAsContent( $oldsigWikiText )
713 $signatureFieldConfig = [];
715 $signature = $this->userOptionsManager->getOption( $user,
'nickname' );
716 $useFancySig = $this->userOptionsManager->getBoolOption( $user,
'fancysig' );
717 if ( $useFancySig && $signature !==
'' ) {
718 $parserOpts = ParserOptions::newFromContext( $context );
719 $validator = $this->signatureValidatorFactory
720 ->newSignatureValidator( $user, $context, $parserOpts );
721 $signatureErrors = $validator->validateSignature( $signature );
722 if ( $signatureErrors ) {
724 $oldsigHTML .=
'<p><strong>' .
729 $context->
msg(
"prefs-signature-invalid-$sigValidation" )->parse() .
734 foreach ( $signatureErrors as &$sigError ) {
735 $sigError =
new HtmlSnippet( $sigError );
738 $signatureFieldConfig = [
739 'warnings' => $sigValidation !==
'disallow' ? $signatureErrors :
null,
740 'errors' => $sigValidation ===
'disallow' ? $signatureErrors :
null,
745 $defaultPreferences[
'oldsig'] = [
750 'default' =>
new FieldLayout(
752 'label' =>
new HtmlSnippet( $oldsigHTML ),
756 'label' =>
new HtmlSnippet( $context->
msg(
'tog-oldsig' )->parse() )
757 ] + $signatureFieldConfig
759 'section' =>
'personal/signature',
761 $defaultPreferences[
'nickname'] = [
762 'type' => $this->authManager->allowsPropertyChange(
'nickname' ) ?
'text' :
'info',
764 'label-message' =>
'yournick',
765 'validation-callback' =>
function ( $signature, $alldata,
HTMLForm $form ) {
768 'section' =>
'personal/signature',
769 'filter-callback' =>
function ( $signature, array $alldata,
HTMLForm $form ) {
773 $defaultPreferences[
'fancysig'] = [
775 'label-message' =>
'tog-fancysig',
777 'help-message' =>
'prefs-help-signature',
778 'section' =>
'personal/signature'
783 if ( $canViewPrivateInfo ) {
786 ?
'prefs-help-email-required'
787 :
'prefs-help-email';
791 $helpMessages[] =
'prefs-help-email-others';
794 $emailAddress = $user->
getEmail() ? htmlspecialchars( $user->
getEmail() ) :
'';
795 if ( $canEditPrivateInfo && $this->authManager->allowsPropertyChange(
'emailaddress' ) ) {
796 $button =
new ButtonWidget( [
801 $context->
msg( $user->
getEmail() ?
'prefs-changeemail' :
'prefs-setemail' )->text(),
804 $emailAddress .= $emailAddress ==
'' ? $button : (
'<br />' . $button );
807 $defaultPreferences[
'emailaddress'] = [
810 'default' => $emailAddress,
811 'label-message' =>
'youremail',
812 'section' =>
'personal/email',
813 'help-messages' => $helpMessages,
818 $disableEmailPrefs =
false;
820 $defaultPreferences[
'requireemail'] = [
822 'label-message' =>
'tog-requireemail',
823 'help-message' =>
'prefs-help-requireemail',
824 'section' =>
'personal/email',
834 $displayUser = $context->
getUser();
836 $time = $lang->userTimeAndDate( $emailTimestamp, $displayUser );
837 $d = $lang->userDate( $emailTimestamp, $displayUser );
838 $t = $lang->userTime( $emailTimestamp, $displayUser );
839 $emailauthenticated = $context->
msg(
'emailauthenticated',
840 $time, $d, $t )->parse() .
'<br />';
841 $emailauthenticationclass =
'mw-email-authenticated';
843 $disableEmailPrefs =
true;
844 $emailauthenticated = $context->
msg(
'emailnotauthenticated' )->parse() .
'<br />' .
847 'label' => $context->
msg(
'emailconfirmlink' )->text(),
849 $emailauthenticationclass =
"mw-email-not-authenticated";
852 $disableEmailPrefs =
true;
853 $emailauthenticated = $context->
msg(
'noemailprefs' )->escaped();
854 $emailauthenticationclass =
'mw-email-none';
857 if ( $canViewPrivateInfo ) {
858 $defaultPreferences[
'emailauthentication'] = [
861 'section' =>
'personal/email',
862 'label-message' =>
'prefs-emailconfirm-label',
863 'default' => $emailauthenticated,
865 'cssclass' => $emailauthenticationclass,
873 $defaultPreferences[
'disablemail'] = [
874 'id' =>
'wpAllowEmail',
877 'section' =>
'personal/email',
878 'label-message' =>
'allowemail',
879 'disabled' => $disableEmailPrefs,
882 $defaultPreferences[
'email-allow-new-users'] = [
883 'id' =>
'wpAllowEmailFromNewUsers',
885 'section' =>
'personal/email',
886 'label-message' =>
'email-allow-new-users-label',
887 'disabled' => $disableEmailPrefs,
888 'disable-if' => [
'!==',
'disablemail',
'1' ],
891 $defaultPreferences[
'ccmeonemails'] = [
893 'section' =>
'personal/email',
894 'label-message' =>
'tog-ccmeonemails',
895 'disabled' => $disableEmailPrefs,
899 $defaultPreferences[
'email-blacklist'] = [
900 'type' =>
'usersmultiselect',
901 'label-message' =>
'email-mutelist-label',
902 'section' =>
'personal/email',
903 'disabled' => $disableEmailPrefs,
904 'filter' => MultiUsernameFilter::class,
910 $defaultPreferences[
'enotifwatchlistpages'] = [
912 'section' =>
'personal/email',
913 'label-message' =>
'tog-enotifwatchlistpages',
914 'disabled' => $disableEmailPrefs,
918 $defaultPreferences[
'enotifusertalkpages'] = [
920 'section' =>
'personal/email',
921 'label-message' =>
'tog-enotifusertalkpages',
922 'disabled' => $disableEmailPrefs,
928 $defaultPreferences[
'enotifminoredits'] = [
930 'section' =>
'personal/email',
931 'label-message' =>
'tog-enotifminoredits',
932 'disabled' => $disableEmailPrefs,
937 $defaultPreferences[
'enotifrevealaddr'] = [
939 'section' =>
'personal/email',
940 'label-message' =>
'tog-enotifrevealaddr',
941 'disabled' => $disableEmailPrefs,
956 $validSkinNames = $this->getValidSkinNames( $user, $context );
957 if ( $validSkinNames ) {
958 $defaultPreferences[
'skin'] = [
962 'section' =>
'rendering/skin',
964 $hideCond = [
'AND' ];
965 foreach ( $validSkinNames as $skinName => $_ ) {
966 $options = $this->skinFactory->getSkinOptions( $skinName );
967 if (
$options[
'responsive'] ??
false ) {
968 $hideCond[] = [
'!==',
'skin', $skinName ];
971 if ( $hideCond === [
'AND' ] ) {
974 $defaultPreferences[
'skin-responsive'] = [
976 'label-message' =>
'prefs-skin-responsive',
977 'section' =>
'rendering/skin/skin-prefs',
978 'help-message' =>
'prefs-help-skin-responsive',
979 'hide-if' => $hideCond,
985 $safeMode = $this->userOptionsManager->getOption( $user,
'forcesafemode' );
989 if ( $allowUserCss || $allowUserJs ) {
991 $defaultPreferences[
'customcssjs-safemode'] = [
994 'default' => Html::warningBox( $context->
msg(
'prefs-custom-cssjs-safemode' )->parse() ),
995 'section' =>
'rendering/skin',
1001 if ( $allowUserCss ) {
1002 $cssPage = Title::makeTitleSafe(
NS_USER, $userName .
'/common.css' );
1003 $cssLinkText = $context->
msg(
'prefs-custom-css' )->text();
1004 $linkTools[] = $this->linkRenderer->makeLink( $cssPage, $cssLinkText );
1007 if ( $allowUserJs ) {
1008 $jsPage = Title::makeTitleSafe(
NS_USER, $userName .
'/common.js' );
1009 $jsLinkText = $context->
msg(
'prefs-custom-js' )->text();
1010 $linkTools[] = $this->linkRenderer->makeLink( $jsPage, $jsLinkText );
1013 $defaultPreferences[
'commoncssjs'] = [
1016 'default' => $context->
getLanguage()->pipeList( $linkTools ),
1017 'label-message' =>
'prefs-common-config',
1018 'section' =>
'rendering/skin',
1029 $defaultPreferences[
'imagesize'] = [
1032 'label-message' =>
'imagemaxsize',
1033 'section' =>
'rendering/files',
1035 $defaultPreferences[
'thumbsize'] = [
1038 'label-message' =>
'thumbsize',
1039 'section' =>
'rendering/files',
1053 if ( $dateOptions ) {
1054 $defaultPreferences[
'date'] = [
1056 'options' => $dateOptions,
1057 'section' =>
'rendering/dateformat',
1064 $nowlocal =
Xml::element(
'span', [
'id' =>
'wpLocalTime' ],
1065 $lang->userTime( $now, $user ) );
1066 $nowserver = $lang->userTime( $now, $user,
1067 [
'format' =>
false,
'timecorrection' =>
false ] ) .
1068 Html::hidden(
'wpServerTime', (
int)substr( $now, 8, 2 ) * 60 + (
int)substr( $now, 10, 2 ) );
1070 $defaultPreferences[
'nowserver'] = [
1073 'label-message' =>
'servertime',
1074 'default' => $nowserver,
1075 'section' =>
'rendering/timeoffset',
1078 $defaultPreferences[
'nowlocal'] = [
1081 'label-message' =>
'localtime',
1082 'default' => $nowlocal,
1083 'section' =>
'rendering/timeoffset',
1086 $userTimeCorrection = (string)$this->userOptionsManager->getOption( $user,
'timecorrection' );
1091 $userTimeCorrection,
1096 if ( $userTimeCorrectionObj->getCorrectionType() === UserTimeCorrection::OFFSET ) {
1097 $tzDefault = UserTimeCorrection::formatTimezoneOffset( $userTimeCorrectionObj->getTimeOffset() );
1099 $tzDefault = $userTimeCorrectionObj->toString();
1102 $defaultPreferences[
'timecorrection'] = [
1103 'type' =>
'timezone',
1104 'label-message' =>
'timezonelegend',
1105 'default' => $tzDefault,
1107 'section' =>
'rendering/timeoffset',
1108 'id' =>
'wpTimeCorrection',
1109 'filter' => TimezoneFilter::class,
1121 &$defaultPreferences
1124 $defaultPreferences[
'diffonly'] = [
1126 'section' =>
'rendering/diffs',
1127 'label-message' =>
'tog-diffonly',
1129 $defaultPreferences[
'norollbackdiff'] = [
1131 'section' =>
'rendering/diffs',
1132 'label-message' =>
'tog-norollbackdiff',
1134 $defaultPreferences[
'diff-type'] = [
1140 $defaultPreferences[
'underline'] = [
1143 $l10n->
msg(
'underline-never' )->text() => 0,
1144 $l10n->
msg(
'underline-always' )->text() => 1,
1145 $l10n->
msg(
'underline-default' )->text() => 2,
1147 'label-message' =>
'tog-underline',
1148 'section' =>
'rendering/advancedrendering',
1152 $defaultPreferences[
'showhiddencats'] = [
1154 'section' =>
'rendering/advancedrendering',
1155 'label-message' =>
'tog-showhiddencats'
1159 $defaultPreferences[
'showrollbackconfirmation'] = [
1161 'section' =>
'rendering/advancedrendering',
1162 'label-message' =>
'tog-showrollbackconfirmation',
1166 $defaultPreferences[
'forcesafemode'] = [
1168 'section' =>
'rendering/advancedrendering',
1169 'label-message' =>
'tog-forcesafemode',
1170 'help-message' =>
'prefs-help-forcesafemode'
1180 $defaultPreferences[
'editsectiononrightclick'] = [
1182 'section' =>
'editing/advancedediting',
1183 'label-message' =>
'tog-editsectiononrightclick',
1185 $defaultPreferences[
'editondblclick'] = [
1187 'section' =>
'editing/advancedediting',
1188 'label-message' =>
'tog-editondblclick',
1192 $defaultPreferences[
'editfont'] = [
1194 'section' =>
'editing/editor',
1195 'label-message' =>
'editfont-style',
1197 $l10n->
msg(
'editfont-monospace' )->text() =>
'monospace',
1198 $l10n->
msg(
'editfont-sansserif' )->text() =>
'sans-serif',
1199 $l10n->
msg(
'editfont-serif' )->text() =>
'serif',
1204 if ( $user->
isAllowed(
'minoredit' ) ) {
1205 $defaultPreferences[
'minordefault'] = [
1207 'section' =>
'editing/editor',
1208 'label-message' =>
'tog-minordefault',
1212 $defaultPreferences[
'forceeditsummary'] = [
1214 'section' =>
'editing/editor',
1215 'label-message' =>
'tog-forceeditsummary',
1220 $defaultPreferences[
'editrecovery'] = [
1222 'section' =>
'editing/editor',
1223 'label-message' =>
'tog-editrecovery',
1225 'tog-editrecovery-help',
1226 'https://meta.wikimedia.org/wiki/Talk:Community_Wishlist_Survey_2023/Edit-recovery_feature',
1231 $defaultPreferences[
'useeditwarning'] = [
1233 'section' =>
'editing/editor',
1234 'label-message' =>
'tog-useeditwarning',
1237 $defaultPreferences[
'previewonfirst'] = [
1239 'section' =>
'editing/preview',
1240 'label-message' =>
'tog-previewonfirst',
1242 $defaultPreferences[
'previewontop'] = [
1244 'section' =>
'editing/preview',
1245 'label-message' =>
'tog-previewontop',
1247 $defaultPreferences[
'uselivepreview'] = [
1249 'section' =>
'editing/preview',
1250 'label-message' =>
'tog-uselivepreview',
1261 $rcMax = ceil( $rcMaxAge / ( 3600 * 24 ) );
1262 $defaultPreferences[
'rcdays'] = [
1264 'label-message' =>
'recentchangesdays',
1265 'section' =>
'rc/displayrc',
1270 $defaultPreferences[
'rclimit'] = [
1274 'label-message' =>
'recentchangescount',
1275 'help-message' =>
'prefs-help-recentchangescount',
1276 'section' =>
'rc/displayrc',
1277 'filter' => IntvalFilter::class,
1279 $defaultPreferences[
'usenewrc'] = [
1281 'label-message' =>
'tog-usenewrc',
1282 'section' =>
'rc/advancedrc',
1284 $defaultPreferences[
'hideminor'] = [
1286 'label-message' =>
'tog-hideminor',
1287 'section' =>
'rc/changesrc',
1289 $defaultPreferences[
'pst-cssjs'] = [
1292 $defaultPreferences[
'rcfilters-rc-collapsed'] = [
1295 $defaultPreferences[
'rcfilters-wl-collapsed'] = [
1298 $defaultPreferences[
'rcfilters-saved-queries'] = [
1301 $defaultPreferences[
'rcfilters-wl-saved-queries'] = [
1305 $defaultPreferences[
'rcfilters-limit'] = [
1308 $defaultPreferences[
'rcfilters-saved-queries-versionbackup'] = [
1311 $defaultPreferences[
'rcfilters-wl-saved-queries-versionbackup'] = [
1316 $defaultPreferences[
'hidecategorization'] = [
1318 'label-message' =>
'tog-hidecategorization',
1319 'section' =>
'rc/changesrc',
1324 $defaultPreferences[
'hidepatrolled'] = [
1326 'section' =>
'rc/changesrc',
1327 'label-message' =>
'tog-hidepatrolled',
1332 $defaultPreferences[
'newpageshidepatrolled'] = [
1334 'section' =>
'rc/changesrc',
1335 'label-message' =>
'tog-newpageshidepatrolled',
1340 $defaultPreferences[
'shownumberswatching'] = [
1342 'section' =>
'rc/advancedrc',
1343 'label-message' =>
'tog-shownumberswatching',
1347 $defaultPreferences[
'rcenhancedfilters-disable'] = [
1349 'section' =>
'rc/advancedrc',
1350 'label-message' =>
'rcfilters-preference-label',
1351 'help-message' =>
'rcfilters-preference-help',
1365 if ( $user->
isAllowed(
'editmywatchlist' ) ) {
1366 $editWatchlistLinks =
'';
1367 $editWatchlistModes = [
1368 'edit' => [
'subpage' =>
false,
'flags' => [] ],
1369 'raw' => [
'subpage' =>
'raw',
'flags' => [] ],
1370 'clear' => [
'subpage' =>
'clear',
'flags' => [
'destructive' ] ],
1372 foreach ( $editWatchlistModes as $mode =>
$options ) {
1374 $editWatchlistLinks .=
1378 'label' =>
new HtmlSnippet(
1379 $context->
msg(
"prefs-editwatchlist-{$mode}" )->parse()
1384 $defaultPreferences[
'editwatchlist'] = [
1387 'default' => $editWatchlistLinks,
1388 'label-message' =>
'prefs-editwatchlist-label',
1389 'section' =>
'watchlist/editwatchlist',
1393 $defaultPreferences[
'watchlistdays'] = [
1396 'max' => $watchlistdaysMax,
1397 'section' =>
'watchlist/displaywatchlist',
1398 'help-message' => [
'prefs-watchlist-days-max',
Message::numParam( $watchlistdaysMax ) ],
1399 'label-message' =>
'prefs-watchlist-days',
1401 $defaultPreferences[
'wllimit'] = [
1405 'label-message' =>
'prefs-watchlist-edits',
1406 'help-message' =>
'prefs-watchlist-edits-max',
1407 'section' =>
'watchlist/displaywatchlist',
1408 'filter' => IntvalFilter::class,
1410 $defaultPreferences[
'extendwatchlist'] = [
1412 'section' =>
'watchlist/advancedwatchlist',
1413 'label-message' =>
'tog-extendwatchlist',
1415 $defaultPreferences[
'watchlisthideminor'] = [
1417 'section' =>
'watchlist/changeswatchlist',
1418 'label-message' =>
'tog-watchlisthideminor',
1420 $defaultPreferences[
'watchlisthidebots'] = [
1422 'section' =>
'watchlist/changeswatchlist',
1423 'label-message' =>
'tog-watchlisthidebots',
1425 $defaultPreferences[
'watchlisthideown'] = [
1427 'section' =>
'watchlist/changeswatchlist',
1428 'label-message' =>
'tog-watchlisthideown',
1430 $defaultPreferences[
'watchlisthideanons'] = [
1432 'section' =>
'watchlist/changeswatchlist',
1433 'label-message' =>
'tog-watchlisthideanons',
1435 $defaultPreferences[
'watchlisthideliu'] = [
1437 'section' =>
'watchlist/changeswatchlist',
1438 'label-message' =>
'tog-watchlisthideliu',
1442 $defaultPreferences[
'watchlistreloadautomatically'] = [
1444 'section' =>
'watchlist/advancedwatchlist',
1445 'label-message' =>
'tog-watchlistreloadautomatically',
1449 $defaultPreferences[
'watchlistunwatchlinks'] = [
1451 'section' =>
'watchlist/advancedwatchlist',
1452 'label-message' =>
'tog-watchlistunwatchlinks',
1456 $defaultPreferences[
'watchlisthidecategorization'] = [
1458 'section' =>
'watchlist/changeswatchlist',
1459 'label-message' =>
'tog-watchlisthidecategorization',
1464 $defaultPreferences[
'watchlisthidepatrolled'] = [
1466 'section' =>
'watchlist/changeswatchlist',
1467 'label-message' =>
'tog-watchlisthidepatrolled',
1472 'edit' =>
'watchdefault',
1473 'move' =>
'watchmoves',
1477 if ( $user->
isAllowedAny(
'createpage',
'createtalk' ) ) {
1478 $watchTypes[
'read'] =
'watchcreations';
1483 'rollback' =>
'watchrollback',
1484 'upload' =>
'watchuploads',
1485 'delete' =>
'watchdeletion',
1488 foreach ( $watchTypes as $action => $pref ) {
1493 $defaultPreferences[$pref] = [
1495 'section' =>
'watchlist/pageswatchlist',
1496 'label-message' =>
"tog-$pref",
1501 $defaultPreferences[
'watchlisttoken'] = [
1505 $tokenButton =
new ButtonWidget( [
1509 'label' => $context->
msg(
'prefs-watchlist-managetokens' )->text(),
1511 $defaultPreferences[
'watchlisttoken-info'] = [
1513 'section' =>
'watchlist/tokenwatchlist',
1514 'label-message' =>
'prefs-watchlist-token',
1515 'help-message' =>
'prefs-help-tokenmanagement',
1517 'default' => (string)$tokenButton,
1520 $defaultPreferences[
'wlenhancedfilters-disable'] = [
1522 'section' =>
'watchlist/advancedwatchlist',
1523 'label-message' =>
'rcfilters-watchlist-preference-label',
1524 'help-message' =>
'rcfilters-watchlist-preference-help',
1533 $defaultPreferences[
'search-special-page'] = [
1537 foreach ( $this->nsInfo->getValidNamespaces() as $n ) {
1538 $defaultPreferences[
'searchNs' . $n] = [
1544 $defaultPreferences[
'search-match-redirect'] = [
1546 'section' =>
'searchoptions/searchmisc',
1547 'label-message' =>
'search-match-redirect-label',
1548 'help-message' =>
'search-match-redirect-help',
1551 $defaultPreferences[
'search-match-redirect'] = [
1556 $defaultPreferences[
'searchlimit'] = [
1560 'section' =>
'searchoptions/searchmisc',
1561 'label-message' =>
'searchlimit-label',
1562 'help-message' => $context->
msg(
'searchlimit-help', 500 ),
1563 'filter' => IntvalFilter::class,
1569 $thumbNamespacesFormatted = array_combine(
1572 static function ( $namespaceId ) use ( $context ) {
1573 return $namespaceId ===
NS_MAIN
1574 ? $context->
msg(
'blanknamespace' )->escaped()
1575 : $context->
getLanguage()->getFormattedNsText( $namespaceId );
1580 $defaultThumbNamespacesFormatted =
1581 array_intersect_key( $thumbNamespacesFormatted, [
NS_FILE => 1 ] ) ?? [];
1582 $extraThumbNamespacesFormatted =
1583 array_diff_key( $thumbNamespacesFormatted, [
NS_FILE => 1 ] );
1584 if ( $extraThumbNamespacesFormatted ) {
1585 $defaultPreferences[
'search-thumbnail-extra-namespaces'] = [
1587 'section' =>
'searchoptions/searchmisc',
1588 'label-message' =>
'search-thumbnail-extra-namespaces-label',
1589 'help-message' => $context->
msg(
1590 'search-thumbnail-extra-namespaces-message',
1591 $context->
getLanguage()->listToText( $extraThumbNamespacesFormatted ),
1592 count( $extraThumbNamespacesFormatted ),
1593 $context->
getLanguage()->listToText( $defaultThumbNamespacesFormatted ),
1594 count( $defaultThumbNamespacesFormatted )
1609 private static function sortSkinNames( $a, $b, $currentSkin, $preferredSkins ) {
1611 if ( strcasecmp( $a, $currentSkin ) === 0 ) {
1614 if ( strcasecmp( $b, $currentSkin ) === 0 ) {
1618 if ( count( $preferredSkins ) ) {
1619 $aPreferred = array_search( $a, $preferredSkins );
1620 $bPreferred = array_search( $b, $preferredSkins );
1623 if ( $aPreferred !==
false && $bPreferred ===
false ) {
1626 if ( $aPreferred ===
false && $bPreferred !==
false ) {
1631 if ( $aPreferred !==
false && $bPreferred !==
false ) {
1632 return strcasecmp( $aPreferred, $bPreferred );
1636 return strcasecmp( $a, $b );
1647 private function getValidSkinNames( User $user, IContextSource $context ) {
1649 $validSkinNames = $this->skinFactory->getAllowedSkins();
1650 $allInstalledSkins = $this->skinFactory->getInstalledSkins();
1653 $useSkin = $context->getRequest()->getRawVal(
'useskin' );
1654 if ( isset( $allInstalledSkins[$useSkin] )
1655 && $context->msg(
"skinname-$useSkin" )->exists()
1657 $validSkinNames[$useSkin] = $useSkin;
1661 $currentUserSkin = $this->userOptionsManager->getOption( $user,
'skin' );
1662 if ( isset( $allInstalledSkins[$currentUserSkin] )
1663 && $context->msg(
"skinname-$currentUserSkin" )->exists()
1665 $validSkinNames[$currentUserSkin] = $currentUserSkin;
1668 foreach ( $validSkinNames as $skinkey => &$skinname ) {
1669 $msg = $context->msg(
"skinname-{$skinkey}" );
1670 if ( $msg->exists() ) {
1671 $skinname = htmlspecialchars( $msg->text() );
1678 uksort( $validSkinNames,
function ( $a, $b ) use ( $currentUserSkin, $preferredSkins ) {
1679 return $this->sortSkinNames( $a, $b, $currentUserSkin, $preferredSkins );
1682 return $validSkinNames;
1694 $mptitle = Title::newMainPage();
1695 $previewtext = $context->
msg(
'skin-preview' )->escaped();
1699 $safeMode = $this->userOptionsManager->getOption( $user,
'forcesafemode' );
1700 $foundDefault =
false;
1701 foreach ( $validSkinNames as $skinkey => $sn ) {
1705 if ( strcasecmp( $skinkey, $defaultSkin ) === 0 ) {
1706 $linkTools[] = $context->
msg(
'default' )->escaped();
1707 $foundDefault =
true;
1711 $talkPageMsg = $context->
msg(
"$skinkey-prefs-talkpage" );
1712 if ( $talkPageMsg->exists() ) {
1713 $linkTools[] = $talkPageMsg->parse();
1717 $mplink = htmlspecialchars( $mptitle->getLocalURL( [
'useskin' => $skinkey ] ) );
1718 $linkTools[] =
"<a target='_blank' href=\"$mplink\">$previewtext</a>";
1723 if ( $allowUserCss ) {
1724 $cssPage = Title::makeTitleSafe(
NS_USER, $user->
getName() .
'/' . $skinkey .
'.css' );
1725 $cssLinkText = $context->
msg(
'prefs-custom-css' )->text();
1726 $linkTools[] = $this->linkRenderer->makeLink( $cssPage, $cssLinkText );
1729 if ( $allowUserJs ) {
1730 $jsPage = Title::makeTitleSafe(
NS_USER, $user->
getName() .
'/' . $skinkey .
'.js' );
1731 $jsLinkText = $context->
msg(
'prefs-custom-js' )->text();
1732 $linkTools[] = $this->linkRenderer->makeLink( $jsPage, $jsLinkText );
1736 $display = $sn .
' ' . $context->
msg(
'parentheses' )
1737 ->rawParams( $context->
getLanguage()->pipeList( $linkTools ) )
1739 $ret[$display] = $skinkey;
1742 if ( !$foundDefault ) {
1757 $dateopts = $lang->getDatePreferences();
1762 if ( !in_array(
'default', $dateopts ) ) {
1763 $dateopts[] =
'default';
1773 foreach ( $dateopts as $key ) {
1774 if ( $key ==
'default' ) {
1775 $formatted = $context->
msg(
'datedefault' )->escaped();
1777 $formatted = htmlspecialchars( $lang->timeanddate( $epoch,
false, $key ) );
1779 $ret[$formatted] = $key;
1791 $pixels = $l10n->
msg(
'unit-pixel' )->text();
1795 $display =
"{$limits[0]}\u{200E}×{$limits[1]}$pixels";
1796 $ret[$display] = $index;
1808 $pixels = $l10n->
msg(
'unit-pixel' )->text();
1811 $display = $size . $pixels;
1812 $ret[$display] = $index;
1827 if ( is_string( $signature ) && mb_strlen( $signature ) > $maxSigChars ) {
1828 return $form->
msg(
'badsiglength' )->numParams( $maxSigChars )->escaped();
1831 if ( $signature ===
null || $signature ===
'' ) {
1838 if ( !( isset( $alldata[
'fancysig'] ) && $alldata[
'fancysig'] ) ) {
1855 $signature === $this->userOptionsManager->getOption( $user,
'nickname' ) &&
1856 (
bool)$alldata[
'fancysig'] === $this->userOptionsManager->getBoolOption( $user,
'fancysig' )
1861 if ( $sigValidation ===
'new' || $sigValidation ===
'disallow' ) {
1863 $parserOpts = ParserOptions::newFromContext( $form->
getContext() );
1864 $validator = $this->signatureValidatorFactory
1865 ->newSignatureValidator( $user, $form->
getContext(), $parserOpts );
1866 $errors = $validator->validateSignature( $signature );
1875 if ( $this->parserFactory->getInstance()->validateSig( $signature ) ===
false ) {
1876 return $form->
msg(
'badsig' )->escaped();
1889 if ( isset( $alldata[
'fancysig'] ) && $alldata[
'fancysig'] ) {
1890 $signature = $this->parserFactory->getInstance()->cleanSig( $signature );
1893 $signature = Parser::cleanSigInSig( $signature );
1909 $formClass = PreferencesFormOOUI::class,
1917 if ( count( $remove ) ) {
1918 $removeKeys = array_fill_keys( $remove,
true );
1919 $formDescriptor = array_diff_key( $formDescriptor, $removeKeys );
1923 foreach ( $formDescriptor as $name => $info ) {
1924 if ( isset( $info[
'type'] ) && $info[
'type'] ===
'api' ) {
1925 unset( $formDescriptor[$name] );
1932 $htmlForm =
new $formClass( $formDescriptor, $context,
'prefs' );
1938 $htmlForm->setAction( $context->
getTitle()->getLocalURL( [
1939 'useskin' => $context->
getRequest()->getRawVal(
'useskin' )
1942 $htmlForm->setModifiedUser( $user );
1943 $htmlForm->setOptionsEditable( $user->
isAllowed(
'editmyoptions' ) );
1944 $htmlForm->setPrivateInfoEditable( $user->
isAllowed(
'editmyprivateinfo' ) );
1945 $htmlForm->setId(
'mw-prefs-form' );
1946 $htmlForm->setAutocomplete(
'off' );
1947 $htmlForm->setSubmitTextMsg(
'saveprefs' );
1949 $htmlForm->setSubmitTooltip(
'preferences-save' );
1950 $htmlForm->setSubmitID(
'prefcontrol' );
1951 $htmlForm->setSubmitCallback(
1953 return $this->
submitForm( $formData, $form, $formDescriptor );
1973 if ( !$user->isAllowedAny(
'editmyprivateinfo',
'editmyoptions' ) ) {
1974 return Status::newFatal(
'mypreferencesprotected' );
1978 $this->
applyFilters( $formData, $formDescriptor,
'filterFromForm' );
1983 if ( !in_array(
'realname', $hiddenPrefs )
1984 && $user->isAllowed(
'editmyprivateinfo' )
1985 && array_key_exists(
'realname', $formData )
1987 $realName = $formData[
'realname'];
1988 $user->setRealName( $realName );
1991 if ( $user->isAllowed(
'editmyoptions' ) ) {
1992 $oldUserOptions = $this->userOptionsManager->getOptions( $user );
1995 unset( $formData[$b] );
2001 foreach ( $hiddenPrefs as $pref ) {
2004 $formData[$pref] = $this->userOptionsManager->getOption( $user, $pref,
null,
true );
2009 isset( $formData[
'rclimit'] ) &&
2010 intval( $formData[
'rclimit' ] ) !== $this->userOptionsManager->getIntOption( $user,
'rclimit' )
2012 $formData[
'rcfilters-limit'] = $formData[
'rclimit'];
2017 $this->userOptionsManager->resetOptionsByName( $user, $optionsToReset );
2019 foreach ( $formData as $key => $value ) {
2023 $except = !empty( $formData[$key . UserOptionsLookup::LOCAL_EXCEPTION_SUFFIX] );
2024 $this->userOptionsManager->setOption( $user, $key, $value,
2025 $except ? UserOptionsManager::GLOBAL_OVERRIDE : UserOptionsManager::GLOBAL_IGNORE );
2028 $this->hookRunner->onPreferencesFormPreSave(
2029 $formData, $form, $user, $result, $oldUserOptions );
2032 $user->saveSettings();
2045 protected function applyFilters( array &$preferences, array $formDescriptor, $verb ) {
2046 foreach ( $formDescriptor as $preference => $desc ) {
2047 if ( !isset( $desc[
'filter'] ) || !isset( $preferences[$preference] ) ) {
2050 $filterDesc = $desc[
'filter'];
2051 if ( $filterDesc instanceof
Filter ) {
2052 $filter = $filterDesc;
2053 } elseif ( class_exists( $filterDesc ) ) {
2054 $filter =
new $filterDesc();
2055 } elseif ( is_callable( $filterDesc ) ) {
2056 $filter = $filterDesc();
2058 throw new UnexpectedValueException(
2059 "Unrecognized filter type for preference '$preference'"
2062 $preferences[$preference] = $filter->$verb( $preferences[$preference] );
2077 array $formDescriptor
2079 $res = $this->
saveFormData( $formData, $form, $formDescriptor );
2081 if ( $res ===
true ) {
2090 $context->getRequest()->getSession()->set(
'specialPreferencesSaveSuccess', 1 );
2092 $context->getOutput()->redirect(
$url );
2095 return ( $res ===
true ? Status::newGood() : $res );
2101 $options ??= $this->userOptionsManager->loadUserOptions( $user );
2109 foreach ( $specialOptions as $name => $value ) {
2110 unset( $prefs[$name] );
2115 $multiselectOptions = [];
2116 foreach ( $prefs as $name => $info ) {
2117 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'multiselect' ) ||
2119 ( isset( $info[
'class'] ) && $info[
'class'] === \HTMLMultiSelectField::class ) ||
2120 ( isset( $info[
'class'] ) && $info[
'class'] === HTMLMultiSelectField::class )
2122 $opts = HTMLFormField::flattenOptions( $info[
'options'] ?? $info[
'options-messages'] );
2123 $prefix = $info[
'prefix'] ?? $name;
2125 foreach ( $opts as $value ) {
2126 $multiselectOptions[
"$prefix$value"] =
true;
2129 unset( $prefs[$name] );
2132 $checkmatrixOptions = [];
2133 foreach ( $prefs as $name => $info ) {
2134 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'checkmatrix' ) ||
2136 ( isset( $info[
'class'] ) && $info[
'class'] === \HTMLCheckMatrix::class ) ||
2137 ( isset( $info[
'class'] ) && $info[
'class'] === HTMLCheckMatrix::class )
2139 $columns = HTMLFormField::flattenOptions( $info[
'columns'] );
2140 $rows = HTMLFormField::flattenOptions( $info[
'rows'] );
2141 $prefix = $info[
'prefix'] ?? $name;
2143 foreach ( $columns as $column ) {
2144 foreach ( $rows as $row ) {
2145 $checkmatrixOptions[
"$prefix$column-$row"] =
true;
2149 unset( $prefs[$name] );
2154 foreach (
$options as $key => $value ) {
2155 if ( isset( $prefs[$key] ) ) {
2156 $mapping[$key] =
'registered';
2157 } elseif ( isset( $multiselectOptions[$key] ) ) {
2158 $mapping[$key] =
'registered-multiselect';
2159 } elseif ( isset( $checkmatrixOptions[$key] ) ) {
2160 $mapping[$key] =
'registered-checkmatrix';
2161 } elseif ( isset( $specialOptions[$key] ) ) {
2162 $mapping[$key] =
'special';
2163 } elseif ( str_starts_with( $key,
'userjs-' ) ) {
2164 $mapping[$key] =
'userjs';
2165 } elseif ( str_starts_with( $key, UserOptionsLookup::LOCAL_EXCEPTION_SUFFIX ) ) {
2166 $mapping[$key] =
'local-exception';
2168 $mapping[$key] =
'unused';
2178 'registered-multiselect',
2179 'registered-checkmatrix',
2187 $oldOptions = $this->userOptionsManager->loadUserOptions( $user, IDBAccessObject::READ_LATEST );
2189 if ( !is_array( $kinds ) ) {
2190 $kinds = [ $kinds ];
2193 if ( in_array(
'all', $kinds ) ) {
2194 return array_keys( $oldOptions );
2196 $optionKinds = $this->getResetKinds( $user, $context );
2197 $kinds = array_intersect( $kinds, $this->listResetKinds() );
2200 foreach ( $oldOptions as $key => $value ) {
2201 if ( in_array( $optionKinds[$key], $kinds ) ) {
2202 $optionNames[] = $key;
2205 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,...
Set options of the Parser.
Factory class to create Skin objects.
$wgDefaultUserOptions
Config variable stub for the DefaultUserOptions setting, for use by phpdoc and IDEs.
Interface for database access objects.
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.