I’d like to share my concept for a custom user leaderboard built for a role-play forum — with filters, a clean card-based UI, and metrics that actually make sense for RP communities.
First of all, I’m not publishing this extension publicly, because it relies on parameters and assumptions specific to my forum — tags, roles, and data structure. However, below I describe which parameters are used and how the backend works, in case these ideas are useful to others.

General
The leaderboard is split into two tabs:
- Character Sheets
- Player Activity
Both tabs:
- Use dedicated API endpoints
- Rely on pre-calculated data
- Do not run heavy statistics queries on every page load
🧙 Character Sheets Leaderboard
This tab ranks characters, not user accounts. All character sheets on the forum use the same standardized block of attributes, and the extension parses this block automatically to extract the character’s stats.

Data Source
- Each character sheet is a dedicated discussion
- Character stats are parsed once and stored as a snapshot in the database
Metrics
- Physiology
- Dexterity
- Magic
- Charisma
Additionally
A total score is calculated and used as the default sorting metric.
Filters
Supported on both frontend and backend:
- Sorting by any attribute
- Result limit
- «Exclude Guardians» checkbox — removes predefined NPC / staff characters
The exclusion logic is duplicated on frontend and backend intentionally, as a safety measure.

🤴 Player Activity Leaderboard
This tab ranks players, not characters. Activity is not based on the total number of forum posts — it’s based only on role-play posts from discussions with a specific tag. In other words, it measures RP activity inside the RP section, instead of mixing it with off-topic, support threads, or character sheets.
What Is Counted
- Only posts from discussions with a specific tag, e.g. role
- Only comment posts – posts.type = comment
- The first post of each discussion is excluded, since in RP forums it’s often a location description, not an actual RP post
For each user, the system calculates:
- Total post count
- Total character count
- Average post length
- Number of active weeks
- A stability ratio
Stability is calculated as:
active weeks / total weeks in period
🔄 How Recalculation Work
Both leaderboards are built around the idea of explicit recalculation, rather than live statistics. Character sheets and activity metrics are relatively heavy to process, and recalculating them on every page view would be unnecessary for a leaderboard that doesn’t need real-time accuracy. Instead, all expensive work is done in advance, and the frontend only reads prepared data.
For character sheets, stats are parsed when a sheet is saved or when a manual recalculation is triggered. The parsed values are normalized and stored as a snapshot in a dedicated table, so the leaderboard never touches raw post content. This makes sorting and filtering instant, regardless of how complex the original sheet format is.
Player activity works the same way: a recalculation step scans role-play posts within a defined period, aggregates statistics per user, and saves the result. After that, the leaderboard simply displays these snapshots. This approach keeps page loads fast, avoids heavy queries, and gives full control over when and how statistics are updated.
The Update button on the leaderboard page triggers this recalculation manually. When it’s clicked, the frontend sends a request to a dedicated API endpoint, which starts rebuilding the snapshots on the server. All heavy processing happens on the backend: existing records are recalculated and replaced with fresh data, and only after that the interface reloads the already updated results.
🌟 Extension Structure
forumaker-magicstats/
├── .gitignore
├── LICENSE
├── composer.json
├── extend.php
├── js/
│ ├── admin.ts
│ ├── forum.ts
│ ├── package.json
│ ├── package-lock.json
│ ├── tsconfig.json
│ ├── webpack.config.js
│ ├── dist/
│ │ ├── admin.js
│ │ └── forum.js
│ ├── node_modules/
│ └── src/
│ ├── admin/
│ │ ├── components/
│ │ │ └── MagicStatsSettingsPage.tsx
│ │ ├── index.ts
│ │ └── extend.ts
│ └── forum/
│ ├── components/
│ │ └── StatsTabs.tsx
│ ├── extenders/
│ │ └── extendIndexPage.tsx
│ ├── pages/
│ │ └── MagicStatsPage.tsx
│ ├── index.ts
│ └── extend.ts
├── migrations/
│ ├── 2026_01_05_000001_create_character_sheets_table.php
│ ├── 2026_01_05_000002_add_source_post_number_to_character_sheets.php
│ └── 2026_01_05_000003_create_user_activity_snapshots_table.php
├── resources/
│ ├── less/
│ │ └── forum.less
│ └── locale/
│ └── en.yml
└── src/
├── Api/
│ └── Controller/
│ ├── CharacterLeaderboardController.php
│ ├── UserActivityLeaderboardController.php
│ ├── RecalculateActivityController.php
│ └── RecalculateCharactersController.php
├── Console/
│ ├── RecalculateCharacterSheets.php
│ └── RecalculateUserActivity.php
├── Listener/
│ └── ParseCharacterSheet.php
├── Model/
│ ├── CharacterSheet.php
│ └── UserActivitySnapshot.php
└── Service/
├── CharacterSheetBackfill.php
└── CharacterSheetParser.php
f anyone is interested in the source code, I can publish the repository on my GitHub