Screenshot taken on the Citizen skin while using IntegratedProfiles v0.5.0.
Warning
IntegratedProfiles is currently in BETA.
IntegratedProfiles implements modern and extensible user profiles with the added focus of integration, meaning any other extension can add onto it.
- MediaWiki 1.45 or later
- Only MW 1.45 and MW 1.46 have been tested. Earlier versions may work but are not officially supported.
- Extension:FloatingUI
- Any Codex-compatible skin1, or one of the following skins for the best results:
- Citizen (built-in improvements)
- Vector 2022
- Clone into
extensions/IntegratedProfiles - Files are bundled with-in the repo, but, optionally, you can rebuild them manually:
pnpm install && pnpm build - Load in
LocalSettings.php:
wfLoadExtension( 'IntegratedProfiles' );By default, avatars and banners are stored under {UploadDirectory}/ipavatars and {UploadDirectory}/ipbanners (usually $IP/images/...), as avatar_{id}.{ext} and banner_{id}.{ext}. Profile fields (prefixed with ip-) are stored in user_properties (preferences). IntegratedProfiles does not touch wikitext, contributions, or anything else.
The {id} in those filenames comes from CentralIdLookup, which is either the local user id or the central (gu_id) id when CentralAuth is installed.
See below for the required/recommended setup based on your architecture.
This setup applies to every setup. If you have not installed FloatingUI, I recommend that you do:
wfLoadExtension( 'FloatingUI' ); # Provides tooltip feedback for certain UI actions (and also enhances mobile support, as users can tap a social link to preview it with a tooltip before opening it).No extra configuration is needed. The default backend is enough, so simply load the extension:
wfLoadExtension( 'IntegratedProfiles' );Ensure that $IP/images/avatars and $IP/images/banners are both writable. You can configure a custom FileBackend if you wish, however.
You should follow this if you use CentralAuth, regardless if you are a farm or not.
Requirements:
- CentralAuth (or another
CentralIdLookupprovider). Using shared user tables instead will (likely) not work. - Shared file storage.
- The GlobalPreferences extension.
Register one FileBackend that defines both containers with a constant domainId. Paths must resolve to the same storage from every wiki (NFS, a shared volume, or equivalent). Then set $wgIntegratedProfilesBackend to that name:
wfLoadExtension( 'CentralAuth' );
wfLoadExtension( 'GlobalPreferences' );
$wgGlobalPreferencesDB = '...';
wfLoadExtension( 'IntegratedProfiles' );
$wgFileBackends[] = [
'name' => 'ip-shared',
'class' => \Wikimedia\FileBackend\FSFileBackend::class,
'domainId' => 'ip-farm', // must be identical on every wiki
'lockManager' => 'nullLockManager',
'containerPaths' => [
'ipavatars' => $IP . '/images/ipavatars',
'ipbanners' => $IP . '/images/ipbanners',
],
'fileMode' => 0644,
];
$wgIntegratedProfilesBackend = 'ip-shared';If every wiki already uses the same upload directory (one images/ volume), leave $wgIntegratedProfilesBackend empty. The default backend uses a stable domain id (integratedprofiles), so media is shared without a designated backend. You still need CentralAuth and GlobalPreferences:
wfLoadExtension( 'CentralAuth' );
wfLoadExtension( 'GlobalPreferences' );
$wgGlobalPreferencesDB = '...';
wfLoadExtension( 'IntegratedProfiles' );This extension is compatible with GlobalPreferences. Consider installing this extension alongside IntegratedProfiles, like so:
wfLoadExtension( 'GlobalPreferences' );
$wgGlobalPreferencesDB = '...';See Extension:GlobalPreferences for more information.
The following extensions are used by IntegratedProfiles in order to achieve full functionality:
wfLoadExtension( 'FloatingUI' ); # Provides tooltip feedback for certain UI actions (and also enhances mobile support, as users can tap a social link to preview it with a tooltip before opening it).
wfLoadExtension( 'CentralAuth' );
wfLoadExtension( 'GlobalPreferences' );Integrations are the whole point of IntegratedProfiles!
IntegratedProfiles integrates certain functionalities from NewAuth. If you have access to NewAuth and have the extension loaded and properly configured, it should work correctly without any configuration. If it does not, please contact me.
Below are open-source integrations that implement IntegratedProfiles' hooks or APIs:
- Extension:UserFlairs
You can add any open-source integrations to this list in a PR, if you want.
Some settings can only be applied globally, as modifying them on one wiki would affect every wiki regardless. The following settings are recommended to be set per-wiki:
$wgIntegratedProfilesEnabledSocialLinks$wgIntegratedProfilesLanguageInterwikis$wgIntegratedProfilesEnableUserCards$wgIntegratedProfilesBannerPresetImages$wgIntegratedProfilesBannerPresetDefault
The rest should be global or farm-wide.
$wgIntegratedProfilesBannerPresetImages = [
'custombanner1' => '/images/banners/custombanner1.webp',
'custombanner2' => 'https://static.wiki.local/banner2.webp'
];
$wgIntegratedProfilesBannerPresetDefault = 'custombanner1'; // only useful for single-wiki setupsOn a single wiki these replace the gradient presets. Users without a custom upload get $wgIntegratedProfilesBannerPresetDefault if set, otherwise the first map entry. On a farm they appear below the gradients and only apply on that wiki. Do not set the map globally on a farm.
- If a banner's preset ID is removed, every user who was using that banner is defaulted to
$wgIntegratedProfilesBannerPresetDefaultor the first preset. - After a banner preset is removed, it will no longer be useable. But, if it was ever re-added, the banner will appear on users whom have not changed their wiki banner after it was removed. ** This supports seasonal banners!
$wgIntegratedProfilesEnabledSocialLinks = [ 'website', 'discord', 'roblox' ];While website is in the facts strip, it is still controlled by the enabled social links settings.
Username links open a profile card on click. This is off by default and requires FloatingUI:
wfLoadExtension( 'FloatingUI' );
$wgIntegratedProfilesEnableUserCards = true;You can use $wgIntegratedProfilesLanguageInterwikis to link to language interwikis automatically. Please ensure each language code set here is also registered in the interwiki table of each wiki (shown on Special:Interwiki). No longer locked to Citizen!
$wgIntegratedProfilesLanguageInterwikis = [ 'en', 'ko', 'ja', 'zh' ];Each wiki skips its own content language ($wgLanguageCode and $wgLocalInterwikis), so you can use the same list everywhere.
Note: If a prefix is missing from that wiki’s interwiki table, MediaWiki treats en:User:Name as a local title and the language menu stays on the current host (https://ko.wiki.local/en:User:TestUser instead of https://wiki.local/User:TestUser).
Add both directions, e.g. en = https://wiki.local/$1 and ko = https://ko.wiki.local/$1.
Note
User cards may also be referred to as profile cards or hover cards, especially with-in the codebase. They explicitly appear only on-click, but were originally designed to appear on-hover, hence the different names.
User card previews are experimental and opt-in. Use $wgIntegratedProfilesEnableUserCards to enable this feature on your wiki.
Additionally, as user cards are on-click, you may want to remove redlinks from empty user page URLs. You can achieve these by putting the following in your MediaWiki:Common.js file:
mw.hook('wikipage.content').add(function ($content) {
$content.find('a.new[href*="User:"]').each(function () {
var $link = $(this);
var href = $link.attr('href');
if (href) {
$link.attr( 'href', href.replace(/[?&]action=edit(&redlink=1)?/g, '') );
// $link.attr( 'href', href.replace(/[?&]veaction=edit(&redlink=1)?/g, '') ); // if you replace edit links with VE links
};
});
});Note: User cards may misbehave if FloatingUI is not installed/loaded. Use this feature with FloatingUI active for the best user experience. User cards may not work on every skin.
integratedprofiles-manage: Users with this right can edit other users' profile details, including avatars and banners. Granted tosysopby default. If settings are shared globally (e.g., via GlobalPreferences), then anyone with this right can edit profile details of a user for every other wiki at once.integratedprofiles-animated-avatar: Allows users to upload animated (GIF, animated WebP files, or APNG) avatars. Granted tosysopby default. Again, with shared avatars, this right on one wiki technically applies to all, as a user can upload an animated avatar on any wiki where they have this right, and that avatar is then used anywhere. This has no effect if$wgIntegratedProfilesEnableAnimatedAvatarsis set to false.
Please see better hook documentation at https://www.mediawiki.org/wiki/Extension:IntegratedProfiles where the up-to-date documentation is. Shortcuts:
- IntegratedProfilesAfterMasthead
- IntegratedProfilesAfterAvatar
- IntegratedProfilesGetTabs
- IntegratedProfilesRenderTab
There should be code and usage examples there, along with other information about how these hooks are used internally and where they fit in.
If there's a performant way to implement another hook with a lot of potential use cases, create an issue on this GitHub issue as a request.
if ( ExtensionRegistry::getInstance()->isLoaded( 'IntegratedProfiles' ) ) {
$avatars = MediaWikiServices::getInstance()
->get( 'IntegratedProfiles.AvatarService' );
$url = $avatars->get_avatar_url_for_user( $user );
// Or alternatively, for many users in a batch: $avatars->get_avatar_urls_for_users( $users );
// (recommended cap: 20)
}You can use the Action API to query user avatars from anywhere else for no more than 50 usernames.
action=query&list=integratedprofileavatar&ipauser=User1|User2|User3
Returns a list of { user, avatar_url, has_custom_avatar }. Unknown names are warned and omitted.
Warning
Breaking change: please update your code from using get_card_payload to get_preview_payload, as of v0.7.0.
Query slim public profile information for display outside the profile page (user cards, gadgets, other extensions). Unlike the previous user card endpoint, this works even when $wgIntegratedProfilesEnableUserCards is false.
if ( ExtensionRegistry::getInstance()->isLoaded( 'IntegratedProfiles' ) ) {
$profiles = MediaWikiServices::getInstance()
->get( 'IntegratedProfiles.ProfileService' );
$preview = $profiles->get_preview_payload( $user, $viewer );
// Or alternatively, for many users in a batch:
// $profiles->get_preview_payloads_for_users( $users, $viewer );
}You can query preview payloads for no more than 50 usernames.
action=query&list=integratedprofilepreview&ippuser=User1|User2|User3
Returns a list of { user, user_id, real_name, about, location, website, edit_count, registration, avatar_url, has_custom_avatar, banner, banner_url, featured_article, is_private }. banner is a preset id (accent, ocean, sunset, forest, midnight, ember, sand, aurora) or custom. banner_url is set for a custom upload or a wiki preset image. featured_article is { title, display_title, url } or null. website is { label, url } or null. Unknown names are warned and omitted. When is_private is true, extras are empty (banner falls back to accent).
Style rules: https://github.com/obbywiki/standards
pnpm install
pnpm build
pnpm lint
pnpm test
composer install
composer testPHPUnit is a MediaWiki-dependent suite (tests/phpunit/Unit, tests/phpunit/Integration). It runs in CI, but locally it will need a MediaWiki checkout with IntegratedProfiles at extensions/IntegratedProfiles, then you can run composer phpunit.
GPL-3.0-or-later
Footnotes
-
Not every token used by IntegratedProfiles is implemented in every skin. Use modern skins for the best results. ↩



