Overview
Citizen is a MediaWiki skin built on theSkinMustache framework. It combines server-side rendering with modern client-side interactivity using multiple technologies:
- PHP: Server-side logic and component generation
- Mustache: Template rendering
- LESS: Styling and theming
- JavaScript: Client-side interactivity (CommonJS modules)
- Vue 3: Interactive components with Composition API
- ResourceLoader: MediaWiki’s asset delivery system
Directory Structure
Core Technologies
PHP Backend
The PHP layer handles server-side rendering and data preparation:SkinCitizen.php: Main skin class extendingSkinMustache- Components: Modular PHP classes implementing
CitizenComponentinterface - Hooks: Integration with MediaWiki’s hook system
PHP Conventions
- All files start with
declare( strict_types=1 ); - Use native PHP types for properties, parameters, and return values
- Use PHPDoc only for collection types (e.g.,
string[]) - Always use MediaWiki-namespaced imports:
- Avoid legacy shims like
use Title;(will be removed in future MW versions)
Mustache Templates
Templates intemplates/ define the HTML structure. They receive data from PHP components via the getTemplateData() method.
LESS/CSS Styling
Citizen uses LESS for styles with a modern approach:- CSS Custom Properties: Preferred over LESS variables (defined in
tokens-citizen.less) - LESS Variables: Only import
variables.lessormixins.lesswhen LESS-specific features are needed - Modular Structure: Styles organized by ResourceLoader module
Style Organization
JavaScript
Citizen uses CommonJS modules for JavaScript:Vue 3 Components
Interactive components use Vue 3 with Composition API:ResourceLoader Integration
Theskin.json file is the source of truth for how resources are loaded. It defines:
- ResourceLoader modules
- Hook registrations
- Configuration variables
- Extension skin styles
Adding Files to ResourceLoader
When adding or removing files underresources/, update the corresponding entry in skin.json:
Configuration Variables
Config variables are declared inskin.json with the wgCitizen prefix:
Extension Styles
Support for MediaWiki extensions is added viaskinStyles/:
- Create a LESS file:
skinStyles/ExtensionName/styles.less - Register in
skin.jsonunderResourceModuleSkinStyles:
Codex Integration
Citizen uses the Codex design system bundled with MediaWiki:- Minimum version: Codex v1.14.0 (bundled with MW 1.43)
- Never assume a specific Codex version - newer MW versions may provide newer Codex
- JS Components: Must be listed in
skin.jsonunder the appropriateCodexModule
Data Flow
- Request arrives at MediaWiki
- SkinCitizen class instantiates
- Components generate template data via
getTemplateData() - Mustache templates render HTML using component data
- ResourceLoader delivers CSS/JS to client
- Client-side scripts initialize (vanilla JS + Vue components)
- User interacts with the page
Build Process
Citizen doesn’t use a traditional build process. Instead:- ResourceLoader handles asset delivery
- LESS is compiled by ResourceLoader on-demand (and cached)
- JavaScript is loaded as CommonJS modules
- No bundling step required for development
- Minification
- Concatenation
- Cache management
- CDN delivery
Extension Points
Citizen provides several ways to extend functionality:- MediaWiki Hooks: Standard hook integration via
skin.json - Configuration Variables: Customizable behavior via
$wgCitizenConfig - User Preferences: Extensible preferences system for gadgets
- ResourceLoader Modules: Can be loaded by extensions
- CSS Custom Properties: Theme customization via CSS variables
Performance Considerations
- Server-side rendering: Critical content rendered server-side for fast initial paint
- Progressive enhancement: Core functionality works without JavaScript
- Lazy loading: Non-critical components loaded on-demand
- ResourceLoader optimization: Automatic minification and caching
- CSS custom properties: Runtime theming without rebuilding
Next Steps
- Explore the Component System
- Learn about Testing
- Review Contributing Guidelines