Skip to content

About

BETA | Implements modern user profiles with the ability for other extensions to build on it.

Topics

Resources

Code of conduct

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

114 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IntegratedProfiles (Usage)

IntegratedProfiles Preview

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.

Screenshots

Profile Editor

Taken on IntegratedProfiles v0.6.0 using the Citizen skin (with NewAuth active).

IntegratedProfiles Preview: Editor

IntegratedProfiles Preview: Editor

User Cards

Taken on IntegratedProfiles v0.6.0 using the Citizen skin.

IntegratedProfiles Preview: User Cards

Installation

Requirements

  • 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.

Suggestions

  • Extension:FloatingUI
  • Any Codex-compatible skin1, or one of the following skins for the best results:
    • Citizen (built-in improvements)
    • Vector 2022

Install

  1. Clone into extensions/IntegratedProfiles
  2. Files are bundled with-in the repo, but, optionally, you can rebuild them manually: pnpm install && pnpm build
  3. Load in LocalSettings.php:
wfLoadExtension( 'IntegratedProfiles' );

Setup

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.

Mutual setup

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).

Single wiki

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.

Wiki farm

You should follow this if you use CentralAuth, regardless if you are a farm or not.

Requirements:

  • CentralAuth (or another CentralIdLookup provider). Using shared user tables instead will (likely) not work.
  • Shared file storage.
  • The GlobalPreferences extension.

Separate upload directories

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';

Shared $wgUploadDirectory

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' );

Global preferences

This extension is compatible with GlobalPreferences. Consider installing this extension alongside IntegratedProfiles, like so:

wfLoadExtension( 'GlobalPreferences' );

$wgGlobalPreferencesDB = '...';

See Extension:GlobalPreferences for more information.

Suggested extensions

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

Integrations are the whole point of IntegratedProfiles!

Built-in integrations

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.

External integrations

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.

Configuration

Config Type(s) Default Purpose
$wgIntegratedProfilesBackend string '' Named entry in $wgFileBackends. Empty uses {UploadDirectory}/ipavatars and {UploadDirectory}/ipbanners. Must already exist if set. See Setup.
$wgIntegratedProfilesEnableUserCards boolean false On-click profile cards for username links. Requires FloatingUI.
$wgIntegratedProfilesAboutMaxLength number 300 Maximum length in characters for the about tagline.
$wgIntegratedProfilesLinkMaxLength number 255 Maximum length in characters for freeform profile link fields.
$wgIntegratedProfilesEnabledSocialLinks array ['website','twitter','github','discord','roblox','youtube'] Only accepts one of the presets. Feel free to request or add any.
$wgIntegratedProfilesAvatarMaxBytes number 2097152 Maximum avatar upload size in bytes (default 2 MiB).
$wgIntegratedProfilesEnableAnimatedAvatars boolean true When false, reject all animated avatar uploads regardless of user rights. Existing GIFs will still be displayed.
$wgIntegratedProfilesBannerMaxBytes number 4194304 Maximum banner upload size in bytes (default 4 MiB).
$wgIntegratedProfilesBannerPresetImages array [] Map of preset ID => image URL (max 8). Replaces gradients on a single wiki, or creates a local extra row with GlobalPreferences per-wiki.
$wgIntegratedProfilesBannerPresetDefault string '' Optional preset ID to use as the single-wiki default. If empty, the first item in $wgIntegratedProfilesBannerPresetImages will be used.
$wgIntegratedProfilesLanguageInterwikis array [] Language interwiki prefixes to inject on user/user talk pages (e.g. ["en","ko","ja"]). Skips the wiki content language and $wgLocalInterwikis. See below.

Local settings

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.

Banner preset images

$wgIntegratedProfilesBannerPresetImages = [
	'custombanner1' => '/images/banners/custombanner1.webp',
	'custombanner2' => 'https://static.wiki.local/banner2.webp'
];
$wgIntegratedProfilesBannerPresetDefault = 'custombanner1'; // only useful for single-wiki setups

On 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.

Notes

  • If a banner's preset ID is removed, every user who was using that banner is defaulted to $wgIntegratedProfilesBannerPresetDefault or 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!

Social links

$wgIntegratedProfilesEnabledSocialLinks = [ 'website', 'discord', 'roblox' ];

While website is in the facts strip, it is still controlled by the enabled social links settings.

User cards

Username links open a profile card on click. This is off by default and requires FloatingUI:

wfLoadExtension( 'FloatingUI' );
$wgIntegratedProfilesEnableUserCards = true;

Language interwikis

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.

User cards [EXPERIMENTAL]

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.


Rights

  • integratedprofiles-manage: Users with this right can edit other users' profile details, including avatars and banners. Granted to sysop by 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 to sysop by 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 $wgIntegratedProfilesEnableAnimatedAvatars is set to false.

IntegratedProfiles (Development)

Hooks

Please see better hook documentation at https://www.mediawiki.org/wiki/Extension:IntegratedProfiles where the up-to-date documentation is. Shortcuts:

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.

Misc

Getting avatars

For extensions

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)
}

Action API

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.

Getting preview payloads

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.

For extensions

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 );
}

Action API

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).


IntegratedProfiles (Contributing)

Style rules: https://github.com/obbywiki/standards

pnpm install
pnpm build
pnpm lint
pnpm test
composer install
composer test

PHPUnit 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.


License

GPL-3.0-or-later

Footnotes

  1. Not every token used by IntegratedProfiles is implemented in every skin. Use modern skins for the best results. ↩

About

BETA | Implements modern user profiles with the ability for other extensions to build on it.

Topics

Resources

Code of conduct

Contributing

Stars

2 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages