Manual:Hooks/GetPreferences

GetPreferences
Available from version 1.16.0
Modify user preferences.
Define function:
public static function onGetPreferences( User $user, array &$preferences ) { ... }
Attach hook: In extension.json:
{
	"Hooks": {
		"GetPreferences": "MediaWiki\\Extension\\MyExtension\\Hooks::onGetPreferences"
	}
}
Called from: File(s): preferences/DefaultPreferencesFactory.php
Interface: GetPreferencesHook.php

For more information about attaching hooks, see Manual:Hooks .
For examples of extensions using this hook, see Category:GetPreferences extensions/en.


Since REL1_35:

Define function:
public function onGetPreferences( $user, &$preferences ) { ... }
Attach hook: In extension.json:
{
	"Hooks": {
		"GetPreferences": "example_tag"
	},
	"HookHandlers": {
		"example_tag": {
			"class": "MediaWiki\\Extension\\ExampleExtension\\Hooks",
			"services": [
				"MainConfig",
				"UserOptionsLookup"
			]
		}
	}
}
Interface: GetPreferencesHook.php

Usage

Parameters

Parameter/Option Description
$user User whose preferences are being modified
&$preferences Preferences description array, to be fed to an HTMLForm object

Tabs and sections

The section array key specifies which tab and section of Preferences contains your preferences. If your section value is foo/bar, this means your preference will appear on the foo tab (named by system message prefs-foo) within the bar section (named by system message prefs-bar). If no such tab or section exists, it is created automatically.

List of default tabs

Identifier Displays as
personal User profile
rendering Appearance
editing Editing
rc Recent changes
watchlist Watchlist
misc Misc

Supported types

Visible types

The type can take on various values found in the HTMLForm::$typeMappings array in the file includes/htmlform/HTMLForm.php, including info, multiselect, radio, etc.

Most preferences are stored in the same format as is used by the HTMLFormField, but in the case of 'type' => 'usersmultiselect' a transformation should be carried out from a newline-separated list of usernames (which is what the form widget works with) and a newline-separated list of user IDs (which is what gets stored in the database). See the treatment of email-blacklist (in core) or echo-notifications-blacklist (in Echo ) for examples of this.

Floats

For float types, you can set min and max, which will be validated on save.

API preferences

API preferences use type api. They are not displayed in Special:Preferences. They are usually set via custom front-end interfaces that call the API.

Note that you should not use 'type' => 'hidden' for API preferences (that type exists for HTML forms, not preferences).

Default preferences

To set the default value for a preference (i.e. the value that is set for a new user that hasn't customized their preferences yet), add the setting to the $wgDefaultUserOptions global variable. Use the same key name as you use for $preferences in the hook.

Alternatively, if you're writing an extension, you can add to the DefaultUserOptions section of the file extensions.json.

Example since REL1_35

See: Handling hooks in MediaWiki 1.35 and later

extension.json

In extension.json:

	"Hooks": {
		"GetPreferences": "main"
	},
	"HookHandlers": {
		"main": {
			"class": "MediaWiki\\Extension\\ExampleExtension\\Hooks",
			"services": [
				"MainConfig",
				"UserOptionsLookup"
			]
		}
	},
	"AutoloadClasses": {
		"MediaWiki\\Extension\\ExampleExtension\\Hooks": "includes/Hooks.php",
	},
	"config": {
		"PersonalSettingsEnabledPageId": {
			"type": "boolean",
			"value": false
		},
		"PersonalSettingsNumberOfMostViewedPages": {
			"type": "int",
			"value": 50
		},
		"PersonalSettingsPeriodForLastViewedPages": {
			"type": "string",
			"value": "year"
		}
	},
	"manifest_version": 2

Hooks.json

In includes/Hooks.php:

namespace MediaWiki\Extension\ExampleExtension;

use MediaWiki\Preferences\Hook\GetPreferencesHook;

use GlobalVarConfig;
use MediaWiki\MediaWikiServices;
use MediaWiki\User\UserOptionsLookup;

class Hooks implements GetPreferencesHook {
	private GlobalVarConfig $config;
	private UserOptionsLookup $userOptionsLookup;

	public function __construct(
		GlobalVarConfig $config,
		UserOptionsLookup $userOptionsLookup
	) {
		$this->config = $config;
		$this->userOptionsLookup = $userOptionsLookup;
	}

	public function onGetPreferences( $user, &$preferences ) {

		$your_new_extensions_section = 'exampleextension';

		// A checkbox
		$preferences_key = 'hitcounters-pageid';
		$preferences_default = $this->userOptionsLookup->getOption(
						$user,
						$preferences_key,
						$this->config->get( 'PersonalSettingsEnabledPageId' ) );
		$preferences[$preferences_key] = [
			'type' => 'toggle',
			'label-message' => 'hitcounters-pageid-label',
			'default' => $preferences_default,
			'section' => $your_new_extensions_section
		];

		// An int input box
		$preferences_key = 'hitcounters-numberofmostviewedpages';
		$preferences_default = $this->userOptionsLookup->getOption(
						$user,
						$preferences_key,
						$this->config->get( 'PersonalSettingsNumberOfMostViewedPages' ) );
		$preferences[$preferences_key] = [
			'type' => 'int',
			'help-message' => 'hitcounters-numberofmostviewedpages-help',
			'label-message' => 'hitcounters-numberofmostviewedpages-label',
			'maxLength' => 4,
			'default' => $preferences_default,
			'section' => $your_new_extensions_section
		];

		// A select box
		$ctx = RequestContext::getMain();
		$preferences_key = 'hitcounters-periodforlastviewedpages';
		$key_base = 'hitcounters-statistics-mostpopular';

		// Ensure that 'default' is always the 1st array item
		$preferences_default = $period = $this->config->get( 'PersonalSettingsPeriodForLastViewedPages' );
		$itemDisplayName = $ctx->msg( "$key_base-$period" )->text();
		$itemArray = [ $itemDisplayName => $period ];

		$period = 'week';
		$itemDisplayName = $ctx->msg( "$key_base-$period" )->text();
		$itemArray[$itemDisplayName] = $period;

		$period = 'month';
		$itemDisplayName = $ctx->msg( "$key_base-$period" )->text();
		$itemArray[$itemDisplayName] = $period;

		$period = 'year';
		$itemDisplayName = $ctx->msg( "$key_base-$period" )->text();
		$itemArray[$itemDisplayName] = $period;

		$usersItem = $this->userOptionsLookup->getOption(
						$user,
						$preferences_key,
						$preferences_default );

		$preferences[$preferences_key] = [
			'type' => 'select',
			'options' => $itemArray,
			'default' => $usersItem,
			'label-message' => "$preferences_key-label",
			'section' => $your_new_extensions_section
		];

		// A set of radio buttons. Notice that in the 'options' array,
		// the keys are the text (not system messages), and the values are the HTML values.
		// They keys/values might be the opposite of what you expect. PHP's array_flip()
		// can be helpful here.
		$preferences_key = 'exampleextension-exampleselect';
		$key_base = 'exampleextension-select';
		$itemKey1 = 'choice1';
		$itemName1 = $ctx->msg( "$key_base-$itemKey1" )->text();
		$itemKey2 = 'choice2';
		$itemName2 = $ctx->msg( "$key_base-$itemKey2" )->text();
		$itemKey3 = 'choice3';
		$itemName3 = $ctx->msg( "$key_base-$itemKey3" )->text();

		// A 'default' key is required, ...
		$preferences_default = $itemKey1;
		// ..., but respect user's choice!
		$usersItem = $this->userOptionsLookup->getOption(
						$user,
						$preferences_key,
						$preferences_default );

		$preferences[$preferences_key] = [
			'type' => 'radio',
			'help-message' => 'exampleextension-exampleselect-help', // a system message (optional)
			'label-message' => 'exampleextension-exampleselect-label', // a system message
			// Array of options. Key = text to display. Value = HTML <option> value.
			'options' => [
				$itemName1 => $itemKey1,
				$itemName2 => $itemKey2,
				$itemName3 => $itemKey3
			],
			'default' => $usersItem,  // A 'default' key is required!
			'section' => $your_new_extensions_section
		];
	}
<!-- [...] -->
}

i18n

In i18n/en.json:

{
	"exampleextension-select-help": "Put a help message here!",
	"exampleextension-select-label": "Select an item:",
	"exampleextension-select-choice1": "Pick me please",
	"exampleextension-select-choice2": "No, pick me!",
	"exampleextension-select-choice3": "Seriously, pick me right now",
	"hitcounters-pageid-label": "Show page ID",
	"hitcounters-numberofmostviewedpages-label": "Number of most viewed pages",
	"hitcounters-periodforlastviewedpages-label": "Period for last viewed pages:",
	"hitcounters-statistics-mostpopular-week": "Most viewed pages in the current week",
	"hitcounters-statistics-mostpopular-month": "Most viewed pages in the current month",
	"hitcounters-statistics-mostpopular-year": "Most viewed pages in the current year",
}

Example Old School

extension.json

In extension.json:

	"Hooks": {
		"GetPreferences": "ExampleExtensionHooks::onGetPreferences",
	},
	"AutoloadClasses": {
		"ExampleExtensionHooks": "includes/Hooks.php",
	},
	"config": {
		"PersonalSettingsEnabledPageId": false,
		"PersonalSettingsNumberOfMostViewedPages": 50,
		"PersonalSettingsPeriodForLastViewedPages": "year"
	},
	"manifest_version": 1

Hooks.json

In includes/Hooks.php:

class ExampleExtensionHooks extends Hooks {

	public static function onGetPreferences( $user, &$preferences ) {

		global $wgPersonalSettingsEnabledPageId, $PersonalSettingsNumberOfMostViewedPages, $PersonalSettingsPeriodForLastViewedPages;

		$your_new_extensions_section = 'exampleextension';

		// A checkbox
		$preferences_key = 'hitcounters-pageid';
		$preferences_default = $this->userOptionsLookup->getOption(
						$user,
						$preferences_key,
						$wgPersonalSettingsEnabledPageId );
		$preferences[$preferences_key] = [
			'type' => 'toggle',
			'label-message' => 'hitcounters-pageid-label',
			'default' => $preferences_default,
			'section' => $your_new_extensions_section
		];

		// An int input box
		$preferences_key = 'hitcounters-numberofmostviewedpages';
		$preferences_default = $this->userOptionsLookup->getOption(
						$user,
						$preferences_key,
						$PersonalSettingsNumberOfMostViewedPages );
		$preferences[$preferences_key] = [
			'type' => 'int',
			'help-message' => 'hitcounters-numberofmostviewedpages-help',
			'label-message' => 'hitcounters-numberofmostviewedpages-label',
			'maxLength' => 4,
			'default' => $preferences_default,
			'section' => $your_new_extensions_section
		];

		// A select box
		$ctx = RequestContext::getMain();
		$preferences_key = 'hitcounters-periodforlastviewedpages';
		$key_base = 'hitcounters-statistics-mostpopular';

		// Ensure that 'default' is always the 1st array item
		$preferences_default = $period = $PersonalSettingsPeriodForLastViewedPages;
		$itemDisplayName = $ctx->msg( "$key_base-$period" )->text();
		$itemArray = [ $itemDisplayName => $period ];

		$period = 'week';
		$itemDisplayName = $ctx->msg( "$key_base-$period" )->text();
		$itemArray[$itemDisplayName] = $period;

		$period = 'month';
		$itemDisplayName = $ctx->msg( "$key_base-$period" )->text();
		$itemArray[$itemDisplayName] = $period;

		$period = 'year';
		$itemDisplayName = $ctx->msg( "$key_base-$period" )->text();
		$itemArray[$itemDisplayName] = $period;

		$usersItem = $this->userOptionsLookup->getOption(
						$user,
						$preferences_key,
						$preferences_default );

		$preferences[$preferences_key] = [
			'type' => 'select',
			'options' => $itemArray,
			'default' => $usersItem,
			'label-message' => "$preferences_key-label",
			'section' => $your_new_extensions_section
		];

		// A set of radio buttons. Notice that in the 'options' array,
		// the keys are the text (not system messages), and the values are the HTML values.
		// They keys/values might be the opposite of what you expect. PHP's array_flip()
		// can be helpful here.
		$preferences_key = 'exampleextension-exampleselect';
		$key_base = 'exampleextension-select';
		$itemKey1 = 'choice1';
		$itemName1 = $ctx->msg( "$key_base-$itemKey1" )->text();
		$itemKey2 = 'choice2';
		$itemName2 = $ctx->msg( "$key_base-$itemKey2" )->text();
		$itemKey3 = 'choice3';
		$itemName3 = $ctx->msg( "$key_base-$itemKey3" )->text();

		// A 'default' key is required, ...
		$preferences_default = $itemKey1;
		// ..., but respect user's choice!
		$usersItem = $this->userOptionsLookup->getOption(
						$user,
						$preferences_key,
						$preferences_default );

		$preferences[$preferences_key] = [
			'type' => 'radio',
			'help-message' => 'exampleextension-exampleselect-help', // a system message (optional)
			'label-message' => 'exampleextension-exampleselect-label', // a system message
			// Array of options. Key = text to display. Value = HTML <option> value.
			'options' => [
				$itemName1 => $itemKey1,
				$itemName2 => $itemKey2,
				$itemName3 => $itemKey3
			],
			'default' => $usersItem,  // A 'default' key is required!
			'section' => $your_new_extensions_section
		];
	}
<!-- [...] -->
}

i18n

In i18n/en.json:

{
	"exampleextension-select-help": "Put a help message here!",
	"exampleextension-select-label": "Select an item:",
	"exampleextension-select-choice1": "Pick me please",
	"exampleextension-select-choice2": "No, pick me!",
	"exampleextension-select-choice3": "Seriously, pick me right now",
	"hitcounters-pageid-label": "Show page ID",
	"hitcounters-numberofmostviewedpages-label": "Number of most viewed pages",
	"hitcounters-periodforlastviewedpages-label": "Period for last viewed pages:",
	"hitcounters-statistics-mostpopular-week": "Most viewed pages in the current week",
	"hitcounters-statistics-mostpopular-month": "Most viewed pages in the current month",
	"hitcounters-statistics-mostpopular-year": "Most viewed pages in the current year",
}