Wbcom Designs WB Gamification Docs
Back to product Buy Now

Getting Started

Installation, setup wizard, and first steps

Installation

Requirements

Before installing WB Gamification, confirm your environment meets these minimums:

  • WordPress 6.4 or higher
  • PHP 8.1 or higher
  • MySQL 5.7 or MariaDB 10.3 or higher

BuddyPress is optional. The plugin works on any standard WordPress site and automatically activates BuddyPress-specific features when BuddyPress is detected.

Installing the Plugin

From the WordPress admin:

  1. Go to Plugins > Add New Plugin.
  2. Search for WB Gamification.
  3. Click Install Now, then Activate.

Manual upload:

  1. Download the plugin ZIP file.
  2. Go to Plugins > Add New Plugin > Upload Plugin.
  3. Choose the ZIP file and click Install Now.
  4. Click Activate Plugin.

What Happens on Activation

When you activate WB Gamification, the plugin does the following automatically:

  • Creates 20 custom database tables to store events, points, badges, levels, challenges, streaks, kudos, leaderboard snapshots, member preferences, and more.
  • Seeds your site with 5 default levels (Newcomer, Member, Contributor, Regular, Champion) and 30 default badges.
  • Registers all gamification actions appropriate for your active plugins. If BuddyPress is active, BuddyPress triggers load automatically.
  • Redirects you to the Setup Wizard so you can choose a starter template.

You do not need to configure anything manually. The plugin detects your active plugins and loads the right point-earning actions automatically.

After Activation

You are redirected to the Setup Wizard. Choose a starter template that matches your site type - this takes about one minute. After completing the wizard, your site is fully configured and ready for members to start earning points.

If you skip the wizard, default point values are used. You can always return to Gamification > Settings to adjust them.

Multisite

WB Gamification can be activated per-site on a WordPress multisite network. Network-wide activation is not recommended because each site maintains its own gamification data and settings independently.

Quick Start Guide

Get WB Gamification running in five minutes. This guide shows you the complete loop from activation to your first member earning points.

Step 1: Activate and Run the Wizard (2 minutes)

  1. Activate the plugin from Plugins > Installed Plugins.
  2. The Setup Wizard opens automatically.
  3. Click the template that matches your site. For a BuddyPress community, choose Community Engagement. For a blog, choose Blog / Publisher.
  4. Click Use This Template.

The wizard saves your point values and redirects you to the Gamification dashboard.

Step 2: Check What Is Already Working (30 seconds)

Go to Gamification > Settings. You will see every action that is currently active on your site - things like "Post an activity update," "Join a group," and "Complete a course." These are already wired up. No additional configuration is needed.

Step 3: Have a Member Do Something (1 minute)

Log in as a regular member. Do one of the active actions - for example, post an activity update on a BuddyPress community page, or leave a comment on a blog post.

Within a few seconds, a toast notification appears in the bottom-right corner showing how many points were earned.

Step 4: Check the Member's Points (30 seconds)

Points appear immediately in three places:

  • The member-points block on any page where you have placed it
  • The member's BuddyPress profile under the Gamification tab (if BuddyPress is active)
  • Gamification > Members in the admin, where you can view any member's full point history

Step 5: View the Analytics Dashboard (30 seconds)

Go to Gamification > Analytics. You will see KPI cards showing total points awarded, active members, badges earned, and more. The dashboard refreshes every 10 minutes.

What Happens Automatically

From here, the plugin handles everything on its own:

  • Members earn points as they take actions
  • Badges award automatically when members meet the conditions
  • Levels advance when members cross point thresholds
  • Streaks build each day a member is active
  • The leaderboard updates on a rolling basis

You do not need to do anything to keep it running. Explore Gamification > Badges, Levels, and Challenges to customize the experience for your community.

Setup Wizard

The Setup Wizard appears automatically the first time you activate WB Gamification. It takes about one minute to complete and pre-configures point values for your site type so you are not starting from a blank slate.

Choosing a Starter Template

The wizard presents five templates. Pick the one that best describes your site.

Blog / Publisher

Best for standalone WordPress blogs without BuddyPress. Rewards writing quality content and meaningful comments.

Point values configured:

  • Publish a blog post - 25 points
  • Publish your first post ever - 20 points (one-time bonus)
  • Leave a comment - 5 points
  • Your post receives a comment - 3 points

Leaderboard defaults to monthly period.

Community Engagement

Best for BuddyPress-powered communities. Rewards social participation - posting, reacting, connecting, and giving kudos. Requires BuddyPress.

Point values configured:

  • Post an activity update - 10 points
  • Comment on an activity - 5 points
  • Accept a friendship - 8 points
  • Join a group - 8 points
  • Receive a reaction - 3 points
  • Give kudos - 2 points
  • Receive kudos - 5 points

Leaderboard defaults to weekly period.

Online Course

Best for LearnDash-powered course sites. Heavy on course completion and academic progress with credential badges.

Point values configured:

  • Complete a lesson - 20 points
  • Complete a course - 100 points
  • Pass a quiz - 30 points
  • Publish first post - 10 points

Leaderboard defaults to cohort mode so learners compete within their enrollment group.

Coaching Platform

Best for private coaching or accountability communities where members should not compete directly against each other. Leaderboard is private by default - members see their own progress, not a public ranking.

Point values configured:

  • Check in - 15 points
  • Complete a goal - 50 points
  • Publish first post - 10 points

Leaderboard defaults to private mode.

Nonprofit / Mission

Best for volunteer-driven or mission-aligned communities. Uses team leaderboards only so the focus stays on collective impact rather than individual competition.

Point values configured:

  • Log volunteer hours - 30 points
  • Post an activity update - 5 points
  • Join a group - 10 points

Leaderboard defaults to team-only mode.

Skipping the Wizard

If you want to configure everything manually, scroll to the bottom of the wizard page and click Skip setup. Default point values will be used. You can return to Gamification > Settings at any time to adjust point values, leaderboard periods, and all other options.

After Completing the Wizard

After you select a template, the wizard:

  1. Saves the chosen point values to your settings.
  2. Sets the leaderboard default period for your template.
  3. Redirects you to the main Gamification dashboard with a "Setup complete" confirmation.

Changing Settings Later

Nothing the wizard configures is permanent. All point values, leaderboard modes, and other options can be changed at any time in Gamification > Settings. You can also re-run individual pieces of configuration without re-running the full wizard.

How WB Gamification Works

Understanding how the plugin processes activity helps you configure it well and troubleshoot when something unexpected happens.

The Core Idea: Events In, Rules Evaluate, Effects Out

Every time a member does something on your site - publishes a post, comments, completes a course, joins a group - WB Gamification sees it as an event. The engine takes that event, checks its rules, and produces effects like points, badges, and notifications.

The source of the event does not matter to the engine. A WooCommerce purchase, a LearnDash lesson completion, and a BuddyPress activity post all arrive as the same type of object. This is why one plugin can handle so many different site types without add-ons.

The Flow, Step by Step

Here is what happens each time a member takes an action:

1. Action detected A member does something that has a registered gamification trigger - for example, they post an activity update on BuddyPress. WordPress fires the bp_activity_posted_update hook.

2. Event created WB Gamification catches that hook and creates a standardized event record. The record stores: which user, which action, a timestamp, and any relevant metadata (like the word count of a post, which helps with quality-weighted scoring).

3. Points awarded The engine looks up how many points this action is worth (from your settings). It adds a row to the immutable points ledger. This ledger is the permanent record - all other data is derived from it.

4. Badge conditions checked After points are saved, the BadgeEngine checks every active badge condition to see if this member now qualifies. Badge conditions include things like "earned 100 cumulative points" or "published 10 posts." If a condition is met and the member does not already have the badge, it awards immediately.

5. Level checked The LevelEngine compares the member's new cumulative points against your level thresholds. If they have crossed into a new level, it updates their level and fires a level-up notification.

6. Streak updated The StreakEngine records that this member was active today. If today is consecutive with their last active day (within the grace period), their streak counter increases. If they hit a streak milestone (7, 14, 30, 60, 100, 180, or 365 days), they earn bonus points and see a milestone notification.

7. Challenge progress updated If any active challenge involves this action, the ChallengeEngine increments the member's progress counter. If they reach the target, the challenge completes and bonus points are awarded.

8. Notification sent The NotificationBridge collects all the events from this request - points, badge, level-up, streak milestone, challenge completion - and outputs them as toast notifications in the bottom-right corner of the page. BuddyPress notifications are also created if BuddyPress is active.

9. Activity feed updated (if BuddyPress is active) Significant events like earning a badge, levelling up, or receiving kudos are posted to the BuddyPress activity stream so the community can see them.

Rules Are Stored as Data, Not Code

One key design decision: all badge conditions, point values, and level thresholds are stored in your database. This means you can change any rule from the admin settings without writing PHP or editing files. It also means the rules can be read and updated via the REST API.

Auto-Detection of Active Plugins

WB Gamification scans your active plugins on each page load and loads only the integration manifests that are relevant. If WooCommerce is not installed, WooCommerce triggers are never registered. If you later add WooCommerce, the triggers activate automatically - no reconfiguration needed.

Processing Is Asynchronous

Some point awards - particularly high-traffic ones like activity updates - are processed asynchronously using Action Scheduler. This means the member's action completes immediately without waiting for the gamification pipeline to finish. Points and badges may appear a few seconds after the action rather than instantly.

Blocks

One page per block: what it shows and how to add + configure it

Blocks Overview

WB Gamification ships 19 blocks you can drop onto any page, post, or sidebar to show points, badges, levels, leaderboards, streaks, kudos, and more. Every block reads live data, so once it is placed it keeps itself up to date.

What a block is

A block is a ready-made display element. You add it in the WordPress editor, adjust a few settings on the right, and publish. No code needed. Many blocks also have a matching shortcode for classic widgets and theme files.

Add a block to a page

  1. Open the page or post in the WordPress block editor.
  2. Click the + (Add block) button.
  3. Search for the block name (for example, "Leaderboard").
  4. Click it to insert it.
  5. Use the settings panel on the right to adjust what it shows.
  6. Publish or update the page.

All WB Gamification blocks are grouped under the Widgets category in the inserter, and their names start with "Gamification" or the feature name.

The 19 blocks

Block What it shows
Leaderboard Ranked list of members by points for a time period.
Member Points A member's points total, level, and progress.
Badge Showcase Grid of badges a member has earned.
Level Progress Current level, progress bar, and points to the next level.
Challenges Active personal challenges with progress.
Community Challenges Shared goals everyone contributes to together.
Streak Current activity streak and optional heatmap.
Top Members Compact podium or list of top-ranked members.
Kudos Feed Live stream of recent peer kudos, with an optional send form.
Give Kudos A simple form to send kudos to another member.
Year in Community Recap A member's year-in-review summary.
Points History A table of a member's point transactions.
Earning Guide A guide to every way members can earn points.
Redemption Store The rewards a member can redeem points for.
Gamification Hub An all-in-one dashboard combining several blocks.
Cohort Rank A member's rank within their cohort league.
Daily Login Bonus The daily login reward and streak ladder.
Submit Achievement A form for members to submit an achievement for review.
User Status Bar A slim bar showing the logged-in member's points and level.

See also

Leaderboard Block

The Leaderboard block shows members a ranked list of who has earned the most points over a chosen time period. It also highlights the logged-in member's own rank, even when they are not in the visible top entries.

Add it to a page

In the block editor, click +, search for "Leaderboard", and insert the Gamification Leaderboard block.

Prefer a shortcode? Use:

[wb_gam_leaderboard period="all" limit="10" show_avatars="1"]
[wb_gam_leaderboard period="week" limit="5" scope_type="group" scope_id="12"]

Settings

Setting What it does Default
Period Time window to rank by: all-time, month, week, or day. all
Limit How many members to list (1-100). 10
Scope type Set to a group to limit the board to one BuddyPress group. (empty, site-wide)
Scope ID The BuddyPress group ID when scope type is a group. 0
Show avatars Show or hide member profile photos. on
Point type Which currency to rank by on multi-currency sites. (default)

Tips

  • Use a weekly period to keep the competition fresh and give newer members a chance to appear.
  • Scope to a group to run separate leaderboards for different teams or communities.

See also

Member Points Block

The Member Points block shows a member their current points total, their level name, and a progress bar toward the next level. By default it shows the points of whoever is viewing the page.

Add it to a page

In the block editor, click +, search for "Member Points", and insert the Member Points block.

Prefer a shortcode? Use:

[wb_gam_member_points]
[wb_gam_member_points user_id="42" show_level="1" show_progress_bar="1"]

Settings

Setting What it does Default
User ID Whose points to show. Leave at 0 for the logged-in member. 0
Show level Show the member's current level name. on
Show progress bar Show the bar tracking progress to the next level. on
Point type Which currency to display on multi-currency sites. (default)

Tips

  • Place this near the top of a member profile or dashboard page so points are the first thing members see.
  • Leave User ID at 0 so every member sees their own total without you creating a page per person.

See also

Badge Showcase Block

The Badge Showcase block displays a grid of the badges a member has earned. You can also show the badges they have not earned yet, greyed out, so members can see what is still up for grabs.

Add it to a page

In the block editor, click +, search for "Badge Showcase", and insert the Badge Showcase block.

Prefer a shortcode? Use:

[wb_gam_badge_showcase]
[wb_gam_badge_showcase show_locked="1" category="buddypress" limit="12"]

Settings

Setting What it does Default
User ID Whose badges to show. Leave at 0 for the logged-in member. 0
Show locked Also show unearned badges greyed out. off
Category Limit to one badge category (for example, wordpress or buddypress). (empty, all)
Limit Cap how many badges to display. 0 shows all. 0

Tips

  • Turn on Show locked to motivate members by revealing badges they can still earn.
  • Use a category filter to build focused showcases, such as a page of community badges only.

See also

Level Progress Block

The Level Progress block gives a focused view of a member's current level: the level icon, a progress bar, and how many points are needed to reach the next level. It is a great companion to the Member Points block.

Add it to a page

In the block editor, click +, search for "Level Progress", and insert the Level Progress block.

Prefer a shortcode? Use:

[wb_gam_level_progress]
[wb_gam_level_progress show_next_level="1" show_icon="1"]

Settings

Setting What it does Default
User ID Whose level to show. Leave at 0 for the logged-in member. 0
Show progress bar Show the bar tracking progress to the next level. on
Show next level Show the name and point threshold of the next level. on
Show icon Show the current level icon. on
Point type Which currency to base the level on for multi-currency sites. (default)

Tips

  • Pair this with Member Points for a complete "where am I and what's next" snapshot.
  • Keep Show next level on so members always have a clear goal in front of them.

See also

Challenges Block

The Challenges block shows a member the active challenges they can work toward, each with its own progress bar. Challenges are personal goals, so every member sees their own progress.

Add it to a page

In the block editor, click +, search for "Challenges", and insert the Challenges block.

Prefer a shortcode? Use:

[wb_gam_challenges]
[wb_gam_challenges limit="3" show_completed="0"]

Settings

Setting What it does Default
User ID Whose progress to show. Leave at 0 for the logged-in member. 0
Show completed Show challenges the member has already finished. Turn off to show only active ones. on
Show progress bar Show a progress bar on each challenge. on
Limit How many challenges to show. 0 shows all active ones. 0

Tips

  • Turn off Show completed on a dashboard so members focus only on what they can still finish.
  • Set a small limit in a sidebar to feature just one or two priority challenges.

See also

Community Challenges Block

The Community Challenges block shows shared goals that the whole community works toward together. Like a Pokemon GO event, a single global counter climbs as every member contributes, and everyone celebrates when it is reached.

Add it to a page

In the block editor, click +, search for "Community Challenges", and insert the Community Challenges block.

Prefer a shortcode? Use:

[wb_gam_community_challenges]
[wb_gam_community_challenges limit="3"]

Settings

Setting What it does Default
Limit How many community challenges to show. 0 shows all active ones. 0
Show progress bar Show the shared progress bar on each challenge. on

Tips

  • Feature this on your homepage so every visitor sees the community rallying around a shared goal.
  • Completed challenges show a celebration state, so leave finished ones visible for a short while to build momentum.

See also

Streak Block

The Streak block shows a member how many days in a row they have stayed active, and optionally their all-time longest streak and a GitHub-style activity heatmap. Streaks encourage members to come back every day.

Add it to a page

In the block editor, click +, search for "Streak", and insert the Streak block.

Prefer a shortcode? Use:

[wb_gam_streak]
[wb_gam_streak show_longest="1" show_heatmap="1" heatmap_days="90"]

Settings

Setting What it does Default
User ID Whose streak to show. Leave at 0 for the logged-in member. 0
Show longest Also show the member's all-time longest streak. on
Show heatmap Show a contribution heatmap of recent activity. off
Heatmap days How many days of history the heatmap covers (1-365). 90

Tips

  • Turn on the heatmap on a profile page to give members a satisfying visual record of their consistency.
  • Keep heatmap days around 90 for a clean grid; larger ranges can get crowded on mobile.

See also

Top Members Block

The Top Members block is a compact spotlight of your highest-ranked members. Choose a visual podium for the top three or a simple list, with optional level names and badges. It is ideal for sidebars and homepage sections.

Add it to a page

In the block editor, click +, search for "Top Members", and insert the Top Members block.

Prefer a shortcode? Use:

[wb_gam_top_members]
[wb_gam_top_members limit="5" layout="list" show_badges="1" show_level="1"]

Settings

Setting What it does Default
Limit How many members to feature (1-20). 3
Period Time window to rank by: all-time, month, week, or day. all_time
Layout Podium (visual first, second, third) or a plain list. podium
Show badges Show each member's top earned badge. on
Show level Show each member's current level name. on
Point type Which currency to rank by on multi-currency sites. (default)

Tips

  • Use the podium layout with a limit of 3 in a hero section for a strong visual.
  • Switch to the list layout in narrow sidebars where the podium would feel cramped.

See also

Kudos Feed Block

The Kudos Feed block shows a live stream of recent peer recognition: who gave kudos, who received it, and the message. It can also include a built-in form so members can send kudos right from the feed.

Add it to a page

In the block editor, click +, search for "Kudos Feed", and insert the Kudos Feed block.

Prefer a shortcode? Use:

[wb_gam_kudos_feed]
[wb_gam_kudos_feed limit="5" show_messages="0"]

Settings

Setting What it does Default
Limit How many recent kudos to show (1-50). 10
Show messages Show the kudos message text under each entry. on
Show give form Show a built-in form so members can send kudos. on
Give form to Pre-fill the form to send kudos to a specific member. (empty, member chooses)
Give form label Custom label for the send button. (empty, default text)

Tips

  • Place this on your community homepage so recognition is visible and contagious.
  • Turn off Show give form if you only want a read-only feed and are using the Give Kudos block elsewhere.

See also

Give Kudos Block

The Give Kudos block is a simple front-end form that lets a logged-in member send kudos to another member. Use it anywhere you want a focused "send recognition" action without the full feed. Visitors who are not signed in are prompted to log in first.

Add it to a page

In the block editor, click +, search for "Give Kudos", and insert the Give Kudos block.

Prefer a shortcode? Use:

[wb_gam_give_kudos]
[wb_gam_give_kudos to="42" label="Thank this member"]

Settings

Setting What it does Default
To Pre-fill the recipient by user ID or username. Leave empty to let the sender choose. (empty)
Label Custom text for the send button. Send Kudos

Tips

  • Set the To field on a member profile page so visitors can thank that exact person in one click.
  • Leave To empty on a general page so members can pick whoever they want to recognize.

See also

Points History Block

The Points History block shows a member a paginated table of their recent point transactions, with the action that earned each point and the date it happened.

Add it to a page

In the block editor, click the inserter, search for "Points History", and place the block where you want the table to appear. It is found under the WB Gamification category.

Prefer a shortcode? Drop this into any page, post, or widget:

[wb_gam_points_history]
[wb_gam_points_history limit="20" show_action_label="1"]

By default the block shows the logged-in member's own history.

Settings

Setting What it does Default
User ID Whose history to show. Leave at 0 for the logged-in member. 0
Point type Limit the table to a single currency on multi-currency sites. Leave empty for the default currency. empty
Number of rows How many transactions to list (1 to 100). 20
Show action label Show the human-readable action name next to each row. On

Tips

  • Put this on a member's "My Activity" page so they can see exactly how they earned their points.
  • Lower the row count for a compact sidebar; raise it for a full history page.
  • On multi-currency sites, set a point type to keep each currency on its own page.

See also

Redemption Store Block

The Redemption Store block is a member-facing rewards catalog. It lists your active redemption items with their point cost, stock level, and a Redeem button, and can show the member's current balance.

Add it to a page

In the block editor, search for "Redemption Store" and place it on a dedicated rewards page. It is found under the WB Gamification category.

Prefer a shortcode?

[wb_gam_redemption_store]
[wb_gam_redemption_store columns="3" limit="0" show_balance="true"]

Pair it with the member rewards history shortcode so members can see what they have already redeemed:

[wb_gam_my_rewards limit="10" show_status="true"]

Settings

Setting What it does Default
Columns Number of columns in the rewards grid (1 to 4). 3
Limit Maximum number of items to show. 0 shows all active items. 0 (all)
Show balance Show the member's current point balance above the grid. On
Show stock Show how many of each reward remain. On
Button label Custom text for the redeem button. Leave empty for the default. empty
Empty message Message shown when no rewards are available. Leave empty for the default. empty
Point type Which currency the prices and balance use on multi-currency sites. empty

Tips

  • Give the page a clear title like "Rewards Store" so members know what they are spending points on.
  • Use the empty message field to point members to how they can earn more points.
  • On multi-currency sites, set the point type so the prices match the currency members are spending.

See also

Cohort Rank Block

The Cohort Rank block shows the current member's standing in their cohort league: their tier, their rank within the cohort, and the points they have earned this week.

Add it to a page

In the block editor, search for "Cohort Rank" and place it on a member dashboard or profile page. It is found under the WB Gamification category.

Prefer a shortcode?

[wb_gam_cohort_rank]
[wb_gam_cohort_rank limit="5"]

By default the block shows the logged-in member's cohort standing.

Settings

Setting What it does Default
User ID Whose cohort standing to show. Leave at 0 for the logged-in member. 0
Limit How many nearby members to list around the member's rank. 5
Point type Which currency the standing is based on for multi-currency sites. empty

Tips

  • Cohort leagues group members who joined around the same time, so this works best once leagues are set up in your gamification settings.
  • The tier accent (Bronze, Silver, Gold, and higher) is colored automatically to match the member's current tier.
  • Place it near a leaderboard so members see both their global rank and their fairer cohort rank.

See also

Earning Guide Block

The Earning Guide block shows members exactly how to earn points. It lists every enabled action and its point value, grouped by category, in a clean grid.

Add it to a page

In the block editor, search for "Earning Guide" and place it on a help, onboarding, or "How points work" page. It is found under the WB Gamification category.

Prefer a shortcode?

[wb_gam_earning_guide]
[wb_gam_earning_guide columns="3" show_category_headers="true"]

The guide updates automatically as you enable or change point-earning actions, so it never goes out of date.

Settings

Setting What it does Default
Columns Number of columns in the grid (1 to 4). 3
Show category headers Show a section header for each integration, such as WordPress or BuddyPress. On

Tips

  • Put this on your onboarding page so new members understand how to start earning right away.
  • Use fewer columns for narrow layouts and sidebars.
  • Turn off category headers for a simple single-list look.

See also

Year in Community Recap Block

The Year Recap block is a shareable, Wrapped-style card that sums up a member's year: total points, badges earned, top actions, and kudos sent and received. It is best on a dedicated "My Year" page.

Add it to a page

In the block editor, search for "Year in Community Recap" and place it on its own page. It is found under the WB Gamification category.

Prefer a shortcode?

[wb_gam_year_recap]
[wb_gam_year_recap year="2024" show_share="1" show_badges="1" show_kudos="1"]

By default the block shows the logged-in member's recap for the current year.

Settings

Setting What it does Default
User ID Whose recap to show. Leave at 0 for the logged-in member. 0
Year Which year to summarize. Leave at 0 for the current year. 0 (current)
Show share button Show a button members can use to share their recap. On
Show badges Include the badges section in the card. On
Show kudos Include the kudos sent and received section. On
Accent color A hex color for the card's accent elements, for example #6366f1. empty

Tips

  • Launch a "My Year" page at the end of the year and invite members to share their recap card.
  • Match the accent color to your brand for a polished, on-theme card.
  • Set a past year to let members revisit a previous year's highlights.

See also

Gamification Hub Block

The Gamification Hub block is a complete member dashboard in one block. It brings stats, badges, challenges, the leaderboard, and more together in a connected card layout with slide-in detail panels.

Add it to a page

In the block editor, search for "Gamification Hub" and place it on your main member dashboard page. It is found under the WB Gamification category. Only one Hub can be used per page.

Prefer a shortcode?

[wb_gam_hub]

The Hub pulls everything together automatically, so there are no content settings to configure. It shows the logged-in member their own stats.

Settings

The Hub has no content settings. It assembles the member's points, badges, challenges, and leaderboard for you. You can still adjust spacing, colors, and visibility from the block's design controls.

Setting What it does Default
Accent color A custom accent color for the cards. Leave empty to use your theme accent. empty
Card background Background color for the hub cards. empty

Tips

  • Use the Hub as the centerpiece of a single member dashboard page rather than scattering individual blocks.
  • Because only one Hub is allowed per page, build other pages from the smaller blocks if you need more than one.
  • Set an accent color that matches your community branding for a cohesive look.

See also

Daily Login Bonus Block

The Daily Login Bonus block shows a member their current login streak, the points they will get for logging in today, and the upcoming reward tiers in the streak ladder.

Add it to a page

In the block editor, search for "Daily Login Bonus" and place it on a member dashboard or homepage. It is found under the WB Gamification category.

This block is block-only and has no shortcode equivalent. Use the block editor to add it.

Settings

The Daily Login Bonus block has no content settings. It reads the member's streak and the reward ladder you configured in the daily login bonus settings. You can still adjust spacing, colors, and visibility from the block's design controls.

Setting What it does Default
Accent color A custom accent color for the card. Leave empty to use your theme accent. empty
Card background Background color for the bonus card. empty

Tips

  • Place it high on a member dashboard so the daily reward is the first thing members see.
  • The reward tiers shown come from your daily login bonus settings, so adjust them there to change the ladder.

See also

Submit Achievement Block

The Submit Achievement block lets members submit an achievement, with a short description and an optional link, for admin approval. Approved submissions award points just like any other earning action.

Add it to a page

In the block editor, search for "Submit Achievement" and place it on a page where members can share their wins. It is found under the WB Gamification category.

This block is block-only and has no shortcode equivalent. Use the block editor to add it.

Settings

The Submit Achievement block has no content settings. The submission form, daily submission cap, and approval flow are managed in your gamification settings. You can still adjust spacing, colors, and visibility from the block's design controls.

Setting What it does Default
Accent color A custom accent color for the form. Leave empty to use your theme accent. empty
Card background Background color for the form card. empty

Tips

  • Each submission goes to an admin review queue before any points are awarded, so nothing is awarded automatically.
  • There is a daily limit on how many achievements a member can submit, to keep the queue manageable.
  • Pair this with a clear page description telling members what kinds of achievements qualify.

See also

User Status Bar Block

The User Status Bar is a sticky, floating bar that shows the logged-in member their points, level, badges, and streak at a glance. It updates live as the member earns, without a page reload.

Add it to a page

In the block editor, search for "User Status Bar" and place it on any page or in a site-wide template part such as the header. It is found under the WB Gamification category.

This block is block-only and has no shortcode equivalent. Use the block editor to add it.

Settings

Setting What it does Default
Layout How the bar sits on the page: floating or inline. floating
Position Corner the floating bar anchors to, for example top-right. top-right
Show level Show the member's current level. On
Show badges Show the member's badge count. On
Show streak Show the member's current streak. On
Show progress Show the progress bar toward the next level. On
Collapsible Let members collapse and expand the bar. On
Hide for guests Hide the bar from logged-out visitors. On

Tips

  • Add it to a global header template part so the status bar follows members across the whole site.
  • Keep "Hide for guests" on so logged-out visitors never see an empty bar.
  • Choose a corner position that does not cover your theme's own floating buttons.

See also

Shortcodes Reference

Every WB Gamification block has a matching shortcode, except the three block-only blocks (Daily Login Bonus, Submit Achievement, and User Status Bar). All shortcodes begin with [wb_gam_ and work anywhere WordPress processes shortcodes: pages, posts, text widgets, and theme templates. The table below lists each shortcode, what it renders, its main attributes, and the equivalent block.

Shortcode What it renders Key attributes Block equivalent
[wb_gam_leaderboard] Ranked list of members by points for a time period period, limit, scope_type, scope_id, show_avatars Leaderboard
[wb_gam_member_points] A member's total points, level, and progress user_id, show_level, show_progress_bar Member Points
[wb_gam_badge_showcase] Grid of earned (and optionally locked) badges user_id, show_locked, category, limit Badge Showcase
[wb_gam_level_progress] A member's level, icon, and progress to the next level user_id, show_progress_bar, show_next_level, show_icon Level Progress
[wb_gam_challenges] Active challenges with progress and time remaining user_id, limit, show_completed, show_progress_bar Challenges
[wb_gam_streak] A member's current streak and optional heatmap user_id, show_longest, show_heatmap, heatmap_days Streak
[wb_gam_top_members] Compact podium or list of top members limit, period, layout, show_badges, show_level Top Members
[wb_gam_kudos_feed] Stream of recent kudos activity limit, show_messages Kudos Feed
[wb_gam_give_kudos] Form for members to give kudos to a peer (none) Give Kudos
[wb_gam_year_recap] Shareable year-in-review recap card user_id, year, show_share, show_badges, show_kudos, accent_color Year Recap
[wb_gam_points_history] Table of a member's point transactions user_id, limit, show_action_label Points History
[wb_gam_earning_guide] Grid of all earning actions and their point values columns, show_category_headers Earning Guide
[wb_gam_hub] Full member dashboard in one block (none) Gamification Hub
[wb_gam_community_challenges] Group and community challenges with progress limit, show_progress_bar Community Challenges
[wb_gam_cohort_rank] A member's cohort league standing user_id, limit, type Cohort Rank
[wb_gam_redemption_store] Member-facing rewards catalog with Redeem buttons limit, columns, show_balance, type Redemption Store
[wb_gam_my_rewards] A member's own redemption history and coupon codes limit, show_status (shortcode only)

For per-block details and design options, see each block's own page and the blocks and shortcodes overview.

Features

Every gamification feature explained for site owners

Points

Points are the core currency of WB Gamification. Every action a member takes that the plugin is configured to track results in points being added to their permanent point total.

What Points Are

A member's point total is the sum of every point award they have ever received. Points never expire and never decrease (unless you manually adjust them). The total drives badge unlocks, level progression, leaderboard ranking, and challenge completion.

How Members Earn Points

Points are awarded automatically. The moment a member completes a tracked action, points are added to their account. No member needs to claim points or do anything special to receive them.

The plugin tracks actions from your active plugins automatically. Below are the default point values by category.

WordPress Actions

Action Default Points Repeatable
Join the site (register) 15 No
First login 10 No
Complete WordPress profile (add bio) 10 No
Post receives a comment 3 Yes
Publish a blog post 25 Yes
Publish first post ever 20 No
Leave a comment 5 Yes
Comment approved from moderation 5 Yes

Note: The publish and comment actions in the WordPress category are only active when BuddyPress is not installed. When BuddyPress is active, the BuddyPress manifest covers those same actions.

BuddyPress Actions

Action Default Points Repeatable
Post an activity update 10 Yes
Comment on an activity 5 Yes
Accept a friendship 8 Yes
Join a group 8 Yes
Create a group 20 Yes
Complete extended profile 15 No
Receive a reaction 3 Yes
Create a poll 10 Yes
Publish a member blog post 25 Yes
Upload media 5 Yes

WooCommerce Actions

Action Default Points Repeatable
Complete a purchase 25 Yes
Complete first purchase ever 50 No
Leave a product review 15 Yes
Add a product to wishlist (YITH) 5 Yes

LearnDash Actions

Action Default Points Repeatable
Complete a course 100 Yes
Complete a lesson 15 Yes
Complete a topic 5 Yes
Pass a quiz 25 Yes
Assignment approved by instructor 20 Yes

Additional integrations are available for bbPress, LifterLMS, MemberPress, GiveWP, and The Events Calendar.

Changing Point Values

Go to Gamification > Settings and find the Points section. Every active action is listed with its current point value. Click the value field, enter a new number, and save.

Setting a value to 0 effectively disables point awards for that action without disabling the action itself (badge and challenge tracking still fires).

Where Members See Their Points

Members can see their points in several places:

  • BuddyPress profile - the Gamification tab shows total points, current level, and recent activity (requires BuddyPress)
  • Member Points block - place this Gutenberg block on any page; it shows the logged-in member's total, level name, and progress bar toward the next level
  • Leaderboard - members can see their rank relative to others

Viewing the Earning Guide

The Earning Guide block and shortcode ([wb_gam_earning_guide]) displays a formatted list of every active point-earning action with its point value. Add this to a "How to earn points" page to help members understand what actions are worth taking.

Manual Point Awards

Admins can award or adjust points manually. Go to Gamification > Manual Award, select a member, enter a point amount and reason, and click Award Points. The award is logged in the member's point history with the reason you entered.

Manual awards show up in point history the same way as automatic awards.

Points History

Every point transaction is permanently logged. Members can see their full earning history in the Points History block ([wb_gam_points_history]), which shows the action, points earned, and date for each transaction.

Multi-Currency Points

WB Gamification supports multiple distinct point currencies running on the same site. Use this to model real-world economies that don't reduce to a single number - coins for in-game purchases, XP for level progress, reputation for moderation privileges, etc.

When to Use Multiple Currencies

Single currency (the default) covers most communities. Use multiple currencies when:

  • You want a separate XP track for level progression that's not affected by every action ("only forum participation counts toward leveling")
  • You're running a game economy with spendable coins (redeem at the store) and unspendable rep (drives ranking)
  • You want distinct leaderboards per currency ("Top contributors" vs "Top spenders")
  • Each integration has its own scale ("LearnDash coursework points" vs "WooCommerce loyalty points")

How Currencies Work

Each currency has:

  • Slug - a short identifier (coins, xp, reputation)
  • Display name - shown in member-facing UIs
  • Symbol - optional prefix (, 🪙, 💎)
  • Default flag - exactly one currency is the site default; if action manifests don't specify, this is what they award

The default site has one currency: points. To add more, go to Settings → Point Types and create them.

Once created, you can:

  • Assign a currency to actions - set point_type on the action manifest entry
  • Assign a currency to redemption rewards - store catalogs can be currency-scoped
  • Configure conversions - let members convert one currency to another (e.g. "10 XP = 1 coin")

Member Surface

Members see their balances:

  • Member Hub block - a tile per currency, with the configured symbol and label
  • Member Points block - accepts a type parameter to show a specific currency
  • Leaderboard block - same type parameter for currency-scoped rankings
  • Points History block - shows the currency next to each event, color-coded

If your site uses one currency, none of this UI changes - currency labels are hidden when there's only one.

Currency Conversions

Conversions let a member trade one currency for another. Common patterns:

  • XP → coins - "spend your XP on store rewards"
  • Reputation → privileges - "unlock moderation tools at 1000 rep"
  • Currency rebalancing - admin migrates a community from points to xp

Each conversion is configured in Settings → Conversions with:

  • Source currency + target currency
  • Conversion rate (from per to, e.g., 10 → 1)
  • Whether members can self-convert or only admins
  • Optional minimum balance to convert (anti-spam)

Conversions are atomic: the source debit and target credit happen in a single MySQL transaction with a row-level lock on the user's balance row. If the operation fails midway, both rows roll back. The same event_id links the two ledger rows so audit trails show the conversion as a coupled pair.

Action Configuration

Set the currency for an action via the action manifest entry:

'wp_publish_post' => array(
    'label'       => 'Publish a post',
    'category'    => 'wordpress',
    'default_points' => 10,
    'point_type'  => 'xp',  // <-- award XP, not the default currency
),

If point_type is omitted, the action awards the site default currency.

The site owner can override per-action via the Settings → Points page - change the dropdown next to each action's point value.

Materialised Totals

Each member has a row in wb_gam_user_totals per currency. The leaderboard, hub, and member-points blocks read this materialised view rather than aggregating the ledger on every request - sub-100ms response even with millions of rows in wb_gam_points.

Privacy

Currencies inherit the same export/erasure rules as the default points engine. All balances per currency export with the user's data and are erased on deletion.

Configuration

Settings → Point Types and Settings → Conversions.

Setting Default
Currencies points (default, no symbol)
Default currency points
Auto-convert on redemption Off
Show currency labels in single-currency mode Off

Developer Integration

If your plugin awards points, declare the currency in your manifest:

return array(
    'actions' => array(
        'my_action' => array(
            'label' => 'Custom action',
            'default_points' => 5,
            'point_type' => 'coins',  // optional, defaults to site default
        ),
    ),
);

Or, when calling the helper directly:

wb_gam_award_points( $user_id, 'my_action', array(
    'point_type' => 'coins',
) );

See Manifest Files for the full manifest spec.

See Also

Badges

Badges are visual achievements members earn by hitting specific milestones. The plugin ships with 30 default badges and supports unlimited custom badges.

What Badges Are

A badge is a named achievement with an image, description, and one or more conditions that must be met before it awards. Badges award automatically the moment a member meets all conditions. Members keep their badges permanently unless the badge has an expiry period.

Default Badges

The 30 default badges are organized into categories:

Points Milestones

Badges for reaching cumulative point totals. Examples: "First Steps" (100 points), "Rising Star" (500 points), "Community Pillar" (1,500 points), "Champion" (5,000 points).

WordPress Actions

Badges for WordPress-native contributions. Examples: "Published Author" (publish first post), "Prolific Writer" (publish 10 posts), "Commenter" (leave first comment), "Conversation Starter" (post receives a comment).

BuddyPress Actions

Badges for BuddyPress community participation. Examples: "Welcome Aboard" (complete extended profile), "Social Butterfly" (accept 10 friendships), "Group Builder" (create a group), "Reaction Magnet" (receive 50 reactions).

Special

Badges assigned manually by admins or awarded for extraordinary contributions. These do not auto-evaluate - they are given by an admin through the Manual Award interface.

How Badges Are Awarded

Auto-award happens automatically. After every point transaction, the badge engine evaluates all active badge conditions for the member who just earned points. If any condition is now satisfied for the first time, the badge awards immediately.

Conditions that trigger auto-award:

  • Point milestone - member's cumulative points reach a threshold
  • Action count - member has completed a specific action a set number of times

Manual award is done by an admin. Go to Gamification > Manual Award, select a member, choose a badge from the list, and click Award. The member receives a notification right away.

Creating Custom Badges

  1. Go to Gamification > Badges.
  2. Click Add New Badge.
  3. Enter a name, description, and choose or upload a badge image.
  4. Under Award Condition, choose the condition type:
    • Point milestone - enter the cumulative points required
    • Action count - choose the action and the number of times it must be completed
    • Admin only - the badge is never awarded automatically
  5. Optionally configure advanced options (see below).
  6. Click Save Badge.

The new badge is active immediately. Existing members who already meet the condition will not receive it retroactively - it awards only on future transactions.

Badge Images

Each badge displays an image in blocks and on BuddyPress profiles. When you create a custom badge, you can upload any image from your WordPress Media Library. Recommended size is 200x200 pixels. PNG files with transparent backgrounds work best.

Default badges use SVG icons that scale cleanly at any size.

Advanced Badge Options

When creating or editing a badge, you can set the following optional limits:

Expiry (validity_days) - If set, the badge expires this many days after it is earned. An expired badge is removed from the member's showcase. Useful for certifications that need periodic renewal. Leave blank for permanent badges.

Close date (closes_at) - The badge stops awarding after this date. Members who earn it before the date keep it permanently. Useful for event-based or seasonal badges.

Maximum earners (max_earners) - The badge stops awarding once this many members have earned it. Useful for "first 100 members" exclusivity badges.

Credential Badges (OpenBadges 3.0)

Badges marked as Credential badges generate a verifiable digital credential following the OpenBadges 3.0 standard. Members can download the credential JSON file, share it on LinkedIn, or include it in a digital portfolio to prove they earned the badge on your site.

Viewing Badges

Members can see their earned badges in:

  • The Badge Showcase block on any page ([wb_gam_badge_showcase])
  • Their BuddyPress profile Gamification tab (if BuddyPress is active)

Use the show_locked="1" attribute on the Badge Showcase shortcode to display unearned badges grayed out, so members know what they are working toward.

Badge Sharing

Badge Sharing gives each earned badge a public URL with proper Open Graph meta tags and optional LinkedIn credential support. Members can share proof of their achievements on social networks or add them to their LinkedIn profile as verified certifications.

Share URL Format

Every earned badge gets a public page at:

/wb-gamification/badge/{user-login}/{badge-slug}/

The BadgeSharePage engine generates this page dynamically. It outputs:

  • Open Graph title, description, and image (the badge artwork)
  • Twitter Card meta tags
  • A canonical URL

OpenBadges 3.0 Credentials

When a badge is marked as a credential (is_credential: true in the badge definition), the share page also outputs a verifiable JSON-LD credential following the OpenBadges 3.0 specification. This makes the badge machine-readable and verifiable by third-party tools.

The credential JSON is available at:

GET /wp-json/wb-gamification/v1/credential/{user_id}/{badge_id}

Credential badges include a pre-built LinkedIn deep-link on the share page. Clicking it takes the member directly to LinkedIn's "Add Certification" flow with the badge name, issuer, and credential URL pre-filled. No copying and pasting required.

How to Enable Credential Badges

  1. Go to WB Gamification → Badges.
  2. Edit the badge you want to make shareable as a credential.
  3. Check the Is Credential option.
  4. Save the badge.

Non-credential badges still get OG share pages - they just do not output the JSON-LD block or the LinkedIn link.

Toggling the feature

Badge Sharing is enabled by default. To turn it off site-wide, set the badge_share key to false in the wb_gam_features option.

Levels

Levels give members a visible sense of status and long-term progression. As members accumulate points, they advance through a sequence of levels - each with a name, a threshold, and an optional icon.

Default Levels

Five levels are created automatically on activation:

Level Minimum Points
Newcomer 0
Member 100
Contributor 500
Regular 1,500
Champion 5,000

Every member starts as a Newcomer. As they earn points, they advance through the ladder automatically.

How Progression Works

Level state is calculated from the member's total points. After every point award, the plugin compares the member's new total against all level thresholds. If the new total puts them in a higher level, the level is updated immediately.

Level is never stored independently - it is always derived from the points ledger. This means if you change a level threshold, member levels update automatically on their next point award.

Level-Up Notifications

When a member advances to a new level, they receive:

  • A toast notification in the bottom-right corner of the page with the new level name and icon
  • A BuddyPress notification (if BuddyPress is active)
  • An activity feed post announcing the level-up to the community (if BuddyPress is active)

Progress Bar

The Level Progress block and the Member Points block both display a visual progress bar showing how far the member is toward the next level. The bar updates in real time after each page load.

Members can also see their current level name and the points needed for the next level.

Adding Custom Levels

  1. Go to Gamification > Levels.
  2. Click Add New Level.
  3. Enter a level name (for example, "Expert" or "Ambassador").
  4. Enter the minimum points required to reach this level.
  5. Optionally upload a level icon image.
  6. Click Save.

Levels are always sorted by their minimum points threshold. You can add as many levels as your community needs.

Tips for setting thresholds:

  • Think about how many points a typical active member earns per week
  • Space levels so members advance roughly every 2-4 weeks of active participation
  • Reserve your highest level for genuinely long-term members - it loses meaning if everyone reaches it quickly

Editing and Removing Levels

You can rename any level or change its point threshold at any time. Changes take effect immediately. Members who have already passed the new threshold stay at that level; members who are below it will drop to the appropriate lower level on their next page load.

You can remove custom levels, but you cannot remove the five default levels. To effectively disable a default level, raise its threshold very high so it is unreachable.

Displaying Levels

Level information appears in:

  • The Level Progress block - shows current level name, icon, progress bar, and points needed for next level ([wb_gam_level_progress])
  • The Member Points block - shows total points, current level name, and progress bar ([wb_gam_member_points])
  • BuddyPress profiles - the Gamification tab shows current level (if BuddyPress is active)
  • Top Members block - optionally shows each member's level label beneath their name ([wb_gam_top_members show_level="1"])

Challenges

Challenges give members a specific goal to work toward, with a bonus point reward for completing it. They are time-bound, trackable, and displayed with a live progress bar.

What a Challenge Is

A challenge asks a member to perform a specific action a set number of times within a defined period. When they hit the target, the challenge completes automatically and bonus points are awarded immediately.

Example challenges:

  • "Post 5 activity updates this week" - 50 bonus points
  • "Leave 10 comments this month" - 75 bonus points
  • "Complete 3 LearnDash lessons" - 100 bonus points

Creating a Challenge

  1. Go to Gamification > Challenges.
  2. Click Add New Challenge.
  3. Fill in the following fields:

Title - The name members see. Make it action-oriented and specific (for example, "Weekend Writer" or "Community Builder").

Action - Choose the action members must perform. The list shows every active gamification trigger on your site.

Target - The number of times the action must be completed.

Bonus Points - Points awarded when the challenge is completed. This is on top of the regular points members earn for each action.

Start Date / End Date - Optional. Leave blank for an always-on challenge. Set dates for seasonal or event-based challenges. Members cannot start a dated challenge before its start date, and it closes automatically after the end date.

Status - Set to Active to make it visible to members. Draft challenges are not shown.

  1. Click Save Challenge.

How Members Track Progress

Members see their challenge progress in the Challenges block or via the shortcode. For each active challenge, they see:

  • The challenge title
  • A progress bar showing completions versus target
  • How many days remain (if the challenge has an end date)
  • A "Completed" badge once they finish

When a challenge completes, the member receives a toast notification and, if BuddyPress is active, a BuddyPress notification.

Completion and Bonus Points

When a member reaches the target count for a challenge, the system:

  1. Marks the challenge as completed for that member
  2. Awards the bonus points immediately
  3. Sends a completion notification
  4. Posts a completion event to the BuddyPress activity stream (if active)

A member who has completed a challenge will not earn the bonus points again for the same challenge, even if they continue performing the action.

Challenge Display

Gutenberg block: Add the WB Gamification Challenges block to any page. The sidebar lets you set how many challenges to show and whether to include completed ones.

Shortcode:

[wb_gam_challenges limit="3"]
[wb_gam_challenges show_completed="0" limit="5"]
Attribute Default Description
limit 0 (all) Maximum number of challenges to show
show_completed 1 Whether to include completed challenges
show_progress_bar 1 Whether to show the progress bar
user_id 0 (current user) Show challenges for a specific user ID

Tips

  • Short-duration challenges (1 week) maintain more urgency than open-ended ones.
  • Set bonus points higher than what a member would earn just from the regular action points - the challenge should feel worth it.
  • Run a new challenge each week or month to give returning members a reason to engage.
  • Use challenges to highlight specific areas: if forum activity is low, create a "bbPress Reply" challenge.

Community Challenges

Community Challenges let your entire membership work toward a shared goal - similar to Pokémon GO's community events. Every member's qualifying actions contribute to a single global progress bar. When the community hits the target, everyone earns bonus points.

How It Differs from Individual Challenges

Individual challenges are per-member: each person has their own progress bar and wins or loses independently. Community challenges have one progress bar shared across all participants. No member can complete it alone.

Creating a Community Challenge

  1. Go to WB Gamification → Community Challenges → Add New.
  2. Set a title and description visible to members.
  3. Choose the action that contributes to progress (any registered gamification action, e.g., bp_activity_update).
  4. Set the target count - total number of qualifying actions needed.
  5. Set a deadline (date and time).
  6. Set the bonus points awarded to every member on completion.
  7. Click Publish.

The CommunityChallengeEngine hooks into the event bus. Each time the chosen action fires, it increments the global counter by one.

What Members See

Members see the challenge title, description, current global progress, target, and time remaining. You can display this with the [wb_gam_community_challenge] shortcode or the Challenges Gutenberg block.

On Completion

When the global counter reaches the target before the deadline, every member who made at least one contributing action receives the bonus points. The challenge status changes to Completed.

If the deadline passes before the target is reached, the challenge expires without awarding bonus points.

Community Challenges are enabled by default. To turn the feature off site-wide, set the community_challenges key to false in the wb_gam_features option.

Streaks

Streaks reward members for consistent, ongoing participation. The longer a member stays active day after day, the higher their streak count - and at key milestones, they earn bonus points.

How Streaks Work

A streak counts how many consecutive days a member has been active. "Active" means earning at least one point from any action. Streaks are not tied to logins - the member needs to actually do something.

Streaks are timezone-aware. Midnight is calculated using the member's own timezone setting. If they have not set a timezone, the site timezone is used. This means a member in Tokyo and a member in New York each get a fair day boundary.

The Grace Period

Life happens. The streak engine includes a 1-day grace period by default. This means:

  • If a member misses exactly one day, their streak continues - the grace period covers the gap
  • The grace period can only be used once per streak. Missing two consecutive days breaks the streak.
  • The grace period resets after each consecutive day. If you use it on a Wednesday, you can use it again after a full consecutive sequence.

Admins can adjust the grace period from 0 to 3 days in Gamification > Settings > Streaks.

Streak Milestones

When a member's current streak reaches one of these milestones, they earn a bonus and see a milestone notification:

Milestone Event
7 days Bonus points + toast notification
14 days Bonus points + toast notification
30 days Bonus points + toast notification
60 days Bonus points + toast notification
100 days Bonus points + toast notification
180 days Bonus points + toast notification
365 days Bonus points + toast notification

The number of bonus points awarded at each milestone is configurable in Gamification > Settings > Streaks. Set to 0 to give a notification without bonus points.

What Resets a Streak

A streak resets to 1 when:

  • A member misses more than one consecutive day (beyond the grace period)
  • A member's grace period was already used and they miss another day

When a streak resets, the previous streak length is saved as the member's longest streak record. Members can always work toward beating their personal best.

Displaying Streaks

Gutenberg block: Add the WB Gamification Streak block to any page. It shows the current streak count prominently, plus an optional heatmap of activity over the past 90 days (similar to GitHub's contribution graph).

Shortcode:

[wb_gam_streak]
[wb_gam_streak show_longest="1" show_heatmap="1" heatmap_days="90"]
Attribute Default Description
show_longest 0 Also display the member's longest-ever streak
show_heatmap 0 Show the activity heatmap calendar
heatmap_days 90 How many days the heatmap covers (1-365)
user_id 0 (current user) Show streak for a specific user ID

Tips

  • Add the streak block to the member's profile page or dashboard so they see their streak every time they visit.
  • Set milestone bonus points high enough to feel rewarding. A 30-day streak is a significant commitment and deserves meaningful recognition.
  • Use the heatmap on member profiles to give members a visual record of their activity history.

Kudos

Kudos is a peer-to-peer recognition system. Members can give a shoutout to another member, with both the giver and receiver earning points in the process.

What Kudos Is

Kudos lets members publicly recognize each other for helpful contributions, great content, or community support. A kudos can include a short optional message. Both members earn points when kudos is given - the receiver earns more than the giver, reflecting the value of being recognized.

Default Point Values

Role Default Points
Receiver (member getting kudos) 5 points
Giver (member sending kudos) 2 points

These values are configurable in Gamification > Settings > Kudos.

Daily Send Limit

Each member can give a maximum of 5 kudos per day by default. This prevents gaming the system by members repeatedly sending kudos to the same friend. The limit resets at midnight (site timezone).

When a member reaches their daily limit, the kudos button shows an informative message telling them when the limit resets.

The daily limit is configurable. Go to Gamification > Settings > Kudos and change the Daily Kudos Limit field.

Rules and Restrictions

  • Members cannot give kudos to themselves
  • Kudos can include an optional message of up to 255 characters
  • Both point awards (giver and receiver) flow through the full gamification pipeline - they count toward badge conditions, level thresholds, streaks, and challenges

The Kudos Feed

The Kudos Feed block and shortcode display a public stream of recent kudos activity. Each entry shows the giver's avatar, the receiver's avatar, and the optional message.

This creates a visible culture of recognition. When members see others being recognized, they are more likely to send kudos themselves.

Shortcode:

[wb_gam_kudos_feed limit="10"]
[wb_gam_kudos_feed limit="5" show_messages="0"]
Attribute Default Description
limit 10 How many recent kudos to show (max 50)
show_messages 1 Whether to display the kudos message

Sending Kudos (Give Kudos Shortcode)

New in 1.4.0.

Members can send kudos directly from the frontend via the [wb_gam_give_kudos] shortcode. Drop it into any page, template part, or BuddyPress profile section.

Shortcode:

[wb_gam_give_kudos]
[wb_gam_give_kudos to="username"]
[wb_gam_give_kudos label="Cheer this member"]
Attribute Default Description
to - Lock the form to a specific recipient by user_login or user_id. When set, the recipient field is hidden.
label "Send Kudos" Custom submit button label.

The shortcode wraps an underlying server-side block (wb-gamification/give-kudos) so theme builders and template-builder plugins that consume blocks via render_block() can use the same render path. The block is not yet wired into the WordPress block inserter - use the shortcode for now.

Behavior:

  • Logged-out visitors see a sign-in prompt instead of the form.
  • Logged-in members see a recipient input (or the locked recipient if to= is set), a message field (max 255 characters), and a Send button.
  • Submitting POSTs to POST /wb-gamification/v1/kudos with recipient_login (the server resolves the username or email to a user ID).
  • The form respects the kudos cooldown - repeat sends to the same recipient get a polite "try again later" message.
  • Status feedback appears below the submit button (success, cooldown, network error).
  • Responsive: stacks vertically with a full-width submit button on screens ≤640 px.

A common placement is the BuddyPress member profile page (with to="{{member_login}}") so visitors can send kudos directly to the profile they are viewing.

BuddyPress Integration

When BuddyPress is active:

  • Giving kudos creates a BuddyPress activity post so the community can see it
  • The receiver gets a BuddyPress notification
  • The Kudos Feed block pulls from the same data source, so activity appears in both places

Viewing All Kudos

Admins can see all kudos activity in Gamification > Analytics. The kudos table shows the giver, receiver, message, date, and points awarded for each transaction.

Tips

  • Add the Kudos Feed block to your community homepage or sidebar to make recognition visible
  • Consider adding kudos sending directly to member profile pages where it is easy to reach
  • The giver earning points (even just 2) encourages members to actively give recognition rather than passively receive it
  • Pair kudos with a "Most Recognized" challenge (based on kudos received) to make recognition a community event

Leaderboard

The leaderboard ranks members by points earned over a selected time period. It updates automatically and can be embedded on any page.

Time Periods

The leaderboard supports four time periods:

Period What It Shows
All-time Total points since the member joined
Monthly Points earned in the current calendar month
Weekly Points earned in the current calendar week (Monday to Sunday)
Daily Points earned today

Each period is a separate leaderboard snapshot. Members who are active today appear on the daily leaderboard even if they rank lower on the all-time board.

Group Scoping

When BuddyPress is active, you can scope the leaderboard to a single BuddyPress group. Members outside that group are excluded from the ranking. This lets you create group-specific leaderboards for course cohorts, team challenges, or private communities.

To scope a leaderboard to a group, set scope_type="group" and scope_id to the BuddyPress group ID in the block settings or shortcode.

How Rankings Are Calculated

Leaderboard positions are calculated from the points ledger and stored in a snapshot cache. The cache is refreshed automatically on a schedule. This means:

  • Very recent activity may take a short time to appear on the leaderboard
  • Page loads are fast because the ranking query runs against the cached snapshot rather than recounting points from scratch

If you award points manually and need the leaderboard to update immediately, you can clear the snapshot cache from Gamification > Settings.

The "Your Rank" Section

When a logged-in member views the leaderboard, the block highlights their current rank below the top list even if they are not in the visible top section. This way every member can see where they stand regardless of their position.

Member Opt-Out

Members can opt out of appearing on the leaderboard from their notification preferences. An opted-out member is excluded from all leaderboard snapshots. Admins cannot override a member's opt-out choice.

See the Privacy documentation for more details on how to access preference settings.

Adding the Leaderboard to a Page

Using the Gutenberg block:

  1. Edit any page.
  2. Click the block inserter (+) and search for WB Gamification Leaderboard.
  3. Add the block. Use the sidebar panel to set the period, limit, and group scope.
  4. Publish or update the page.

Using a shortcode:

[wb_gam_leaderboard period="week" limit="10"]
[wb_gam_leaderboard period="all" limit="20" scope_type="group" scope_id="5"]

Available period values: all, month, week, day

Top Members Block

For a compact podium-style display of the top 3 members, use the Top Members block instead. It shows avatars in a visual podium layout and is well-suited for homepage sections or sidebars.

[wb_gam_top_members limit="3" layout="podium"]
[wb_gam_top_members limit="5" layout="list" show_badges="1"]

Cohort Leagues

Cohort Leagues add Duolingo-style weekly competitions to your community. Instead of every member competing against everyone else, members compete in small groups of similar ability. This makes competition feel winnable for average members - not just your top performers.

How It Works

At the start of each week, the CohortEngine automatically sorts members into cohorts based on their tier. Members in the same tier compete only against each other for that week.

At the end of the week, the engine evaluates each cohort:

  • Top performers in a cohort get promoted to a higher tier the following week.
  • Bottom performers get demoted to a lower tier.
  • Middle performers stay in place.

Point totals reset each week. Historical points (used for levels and badges) are unaffected - cohort leagues track weekly points separately.

Tiers

The default tier structure runs from bottom to top. New members start in the lowest tier. Exact tier names and thresholds are configurable in the league settings.

Why It Drives Engagement

Weekly resets create recurring motivation. Members who missed last week's top spot have a fresh chance every Monday. The promotion/demotion mechanic gives both top and bottom performers a reason to act - one to protect a hard-earned tier, the other to escape demotion.

The cohort model also prevents discouragement. A member with 200 points never appears on the same leaderboard as a member with 20,000 points.

Setup

  1. Go to WB Gamification → Leagues to configure tier names, cohort size, and promotion/demotion thresholds.
  2. The engine runs its weekly sort automatically via WordPress cron.

Cohort Leagues are enabled by default. To turn them off site-wide, set the cohort_leagues key to false in the wb_gam_features option (or via the wb_gam_feature_flags filter).

Redemption Store

The Redemption Store lets members spend their accumulated points on rewards you define. It closes the loop on your points economy - points become worth something tangible, which increases the motivation to earn them.

Creating a Reward Item

  1. Go to WB Gamification → Redemption Store → Add Reward.
  2. Enter a title and description visible to members.
  3. Set the points cost required to redeem.
  4. Choose a reward type:
Reward Type What It Does
discount_pct Generates a percentage-off coupon code
discount_fixed Generates a fixed-amount coupon code
custom You define the fulfillment manually
  1. Optionally set a stock limit. When stock hits zero, the item becomes unavailable.
  2. Click Publish.

How Members Redeem

Members browse available rewards on the store page (use the [wb_gam_store] shortcode or the REST endpoint GET /wp-json/wb-gamification/v1/redemption/items). When they redeem an item, the RedemptionController deducts the points cost and creates a transaction record.

For discount reward types, a WooCommerce coupon code is generated automatically and shown to the member. For custom rewards, you handle fulfillment manually and mark the redemption as fulfilled in the admin.

Transaction Log

Every redemption is recorded with the member ID, reward ID, points spent, timestamp, and fulfillment status. View the log at WB Gamification → Redemption Store → Transactions.

Stock Management

Stock counts decrement on each successful redemption. If you set no stock limit, the reward is unlimited. You can update stock at any time from the reward edit screen.

Submissions (UGC Achievements)

Submissions let members claim achievements that the system cannot automatically detect - volunteer hours, offline milestones, custom community goals. Members submit, admins approve, points and badges fire through the standard award pipeline.

What Submissions Are

A submission is a member-supplied claim that they did something earnable. Each submission has:

  • Title - short description ("Volunteered 3 hours at Saturday cleanup")
  • Details + photo - a short write-up of what they did, with an Add Media button to attach a photo as proof right in the form (a screenshot, event photo, or certificate). Every logged-in member can attach a photo this way - they don't need to be an admin.
  • Optional URL - or just paste a link to evidence hosted elsewhere (a social post, a Google Drive file)
  • Action - the gamification action this submission represents (admin defines the catalog)

When an admin approves the submission, the system fires the standard event for that action. The member earns the configured points exactly as if the action had fired automatically. Badges, levels, streaks, and the leaderboard all update through the same path - there is no parallel "submitted points" track.

Member Flow

  1. Member places the Submit Achievement block on a page (or admins place it on the Hub).
  2. Member fills the form: a title, a short description (with Add Media to attach a proof photo), an optional evidence URL, and picks an action from the allowed list.
  3. The submission lands in the moderation queue with status pending.
  4. Admin approves (→ points fire) or rejects (→ no points, member optionally notified).
  5. Approved submission appears on the member's points history with a "submitted" badge.

Admin Flow

Gamification → Submissions in the WordPress admin.

The queue lists every pending submission with member, title, URL, action, and submission timestamp. Each row has Approve and Reject buttons. Bulk actions support batch approve/reject.

Approving routes through PointsEngine::award so:

  • The configured points for the action are granted
  • The action's daily cap (if any) is enforced
  • All downstream effects (badge unlock, level up, streak credit) fire normally

Rejecting marks the submission as rejected and (optionally) emails the member with a reason.

Daily Cap

To prevent abuse, members can submit at most 5 achievements per day. The cap is configurable.

Member History

The member's points history (/u/{user}/?tab=history) shows each approved submission inline with their auto-earned actions. Rejected submissions are private to the member and the admin team.

Notifications

  • Submission received - admin email + admin-bar count badge
  • Submission approved - member email (if enabled) + toast notification + points awarded
  • Submission rejected - optional member email with reason

Configuration

Settings → Submissions.

Setting Default
Enabled On
Daily cap per member 5
Allowed actions All actions tagged submittable: true in the action manifest
Default reject reason "We could not verify this achievement at this time."
Auto-approve Off

To make an action submittable, set submittable: true on the action manifest entry. By default, only a curated subset of actions are submittable (volunteer-hours-style ones).

Privacy

Submissions are stored in the wb_gam_submissions table with the submitter's user ID, the title, optional URL, action ID, and timestamps. Approved submissions are GDPR-exported alongside other gamification data. Rejected submissions are erased on user deletion.

See Also

Daily Login Bonus

The Daily Login Bonus rewards members for showing up consistently. The longer a member's active streak, the bigger the bonus they earn each day.

How It Works

When a member visits the site for the first time on a given calendar day, they automatically earn a login bonus. The bonus increases at five tier milestones:

Streak day Bonus points
Day 1 10
Day 3 20
Day 7 50
Day 14 100
Day 30 250

Between milestones, the previous tier's value applies. So Day 8 earns 50 (the Day 7 tier), Day 25 earns 100 (the Day 14 tier), and so on. Day 30+ permanently earns 250.

The bonus fires once per calendar day in the member's own timezone. A second visit on the same day does not earn an extra bonus.

What Counts as a Login

A member is considered to have "logged in" the moment any tracked action fires for them on a day where they have not yet earned the bonus. This includes:

  • Logging in via the WordPress login form
  • Returning to the site with an active session cookie (returning visitor)
  • Performing any tracked action (commenting, posting, viewing the hub page)

The bonus is awarded before any other points from that action, so members see two toast notifications stacked: the login bonus first, then the per-action points.

Display Surface

The Daily Bonus block (Gutenberg + frontend) shows the member their current streak and the points they will earn today, plus a preview of upcoming tier rewards.

Place the block on the Hub page, on member dashboards, or anywhere members land after login.

Configuration

Settings → Daily Login Bonus.

Setting Default
Enabled On
Tier ladder [1=>10, 3=>20, 7=>50, 14=>100, 30=>250]
Reset on missed day Yes
Award timezone Member's WP profile timezone, falls back to site default

The tier ladder is editable as a JSON array. Add custom milestones or change the values to match your reward economy.

Streak vs Login Streak

The login bonus uses its own counter, separate from the gamification streak engine. A member can have a 7-day login streak and a 3-day activity streak at the same time - they're distinct mechanics.

If you want a single unified streak, disable the login bonus and rely on the standard streak engine alone.

Privacy

The login bonus does not store IP addresses or session identifiers. It tracks only the date of the most recent bonus award, stored in user meta as wb_gam_last_login_bonus_date. This is included in GDPR export and erasure.

See Also

  • Streaks - independent activity streak (any earning action) with milestones
  • Points - how the bonus integrates with the points ledger
  • Notifications - how the toast for the bonus appears

Year Recap

The Year Recap is a shareable end-of-year summary for each member - their top earnings, badges, streaks, and milestones from the past 12 months. Think Spotify Wrapped, but for community engagement.

What's In a Recap

Each member's recap shows:

  • Total points earned in the year
  • Top 3 actions by points contributed
  • Top 5 badges earned (or all badges, if fewer than 5)
  • Longest streak (days)
  • Total challenges completed
  • Total kudos given and received
  • Rank within the community (e.g., "Top 5% of members this year")
  • Cohort performance (if cohort leagues are active)

The recap is generated automatically from the points ledger - no admin action required.

Member Flow

The Year Recap block on a member's profile or hub page shows their personal recap. A "Share my recap" button generates a public, OG-tagged URL members can share to social media, with an auto-generated image showing their top stats.

The shared URL works without authentication - any visitor can view a member's public recap (controlled by the member's privacy settings).

When the Recap Generates

Two windows by default:

  1. December 1 - recap for the current year locks in. Members can share through Dec 31 plus the new year.
  2. Anytime - admins can trigger an out-of-cycle recap via WP-CLI:
    wp wb-gamification member recap --user=42 --year=2025
    

The recap is cached in the wb_gam_recap_cache table, so multiple shares of the same recap don't recompute every time.

Display Surface

The Year Recap block can be placed on:

  • The member's profile page (BuddyPress integration)
  • A dedicated /recap/ page (WP Page or auto-generated)
  • The Hub page during December

The shareable URL is /recap/{user_login}/{year}. Members get a QR code in the block that points to their share URL - useful for printed materials or in-person events.

Privacy

A member can opt out of the shareable URL - their personal recap still shows on their dashboard, but the public URL returns a 404 if they have set wb_gam_recap_public = 0 in their preferences.

The recap data is:

  • ✓ Included in GDPR export
  • ✓ Erased on user deletion
  • ✓ Excluded from the public URL when opt-out is set

Configuration

Settings → Year Recap.

Setting Default
Enabled On
Lock date December 1
Public share by default On (members can opt out)
Show cohort comparison Yes (if cohort leagues active)
Top-N actions 3
Top-N badges 5

Customization

The recap output can be filtered with wb_gam_year_recap_data to add custom stats or remove default ones. The recap template can be overridden via the standard theme template hierarchy: theme/wb-gamification/recap.php.

See Also

Public Profile Pages

WB Gamification ships member profile pages at /u/{user_login} - sharable, OG-tagged, member-controllable, search-engine-friendly. Use them for social proof, recruiting, or just to give members something to be proud of.

What's On a Profile

Each public profile shows:

  • Member name + avatar
  • Total points + current level + level progress bar
  • All earned badges (with hover descriptions)
  • Longest streak
  • Challenges completed
  • Top actions (last 30 days)
  • Optional: bio text, social links (if member fills them in)

Hidden by default:

  • The member's individual point events (history)
  • Their kudos feed (givens / receives)
  • Personal contact info

Privacy Controls

As of 1.5.2 public profiles are on by default (opt-out). Three layers:

  1. Site-wide setting - admin can disable public profiles entirely (Settings → Privacy). This kill switch always wins.
  2. Member preference - each member can opt out by setting the per-user wb_gam_profile_public flag to 0. An unset/empty value means public.
  3. Per-section toggles - a member can show their badges but hide their streak, etc.

By default, when public profiles are enabled site-wide, each member's profile is visible until they explicitly opt out. (Before 1.5.2 the per-user flag was opt-IN, but no member-facing UI ever wrote it, so every /u/ profile returned 404 - that is fixed in 1.5.2.) The owner of a profile and administrators (manage_options) can always view it regardless of the flag.

The wb_gam_profile_publicly_visible filter (bool $visible, int $user_id) lets a site override visibility per member - see the Filters reference.

A profile that is opted out (per-user flag 0) returns a 404 instead of a partial page - search engines and visitors see no information.

URL Structure

URL What it shows
/u/{user_login} The member's full profile
/u/{user_login}/badges Just their badges (lightweight)
/u/{user_login}/recap/{year} Their year recap (separate privacy toggle)

The URL slug uses user_login (the WordPress login name). This is stable - username changes are not allowed in WordPress core, so the URL never breaks.

SEO + Social

Each profile page renders:

  • OG meta tags - og:title, og:description, og:image (auto-generated card)
  • Twitter Card meta - same as OG
  • Schema.org JSON-LD - Person type with name, avatar, badges as Achievement items
  • Canonical URL - points to the profile page so duplicate-content scoring stays clean

This means a member sharing their profile to LinkedIn, Twitter, Facebook gets a rich preview card with their avatar, name, and top achievement.

Auto-Generated OG Image

The profile generates a dynamic 1200×630 OG image showing the member's avatar, name, point total, and top badge. The image is cached for 24 hours per member and regenerates when their stats change significantly.

BuddyPress Coexistence

If BuddyPress is active, the profile URL /members/{user}/ continues to work for the BP profile. The WB Gamification profile at /u/{user}/ is a separate, complementary surface - admins choose which to feature in their navigation.

Configuration

Settings → Privacy → Public Profiles.

Setting Default
Enabled site-wide On
Default per-member visibility On (members opt out explicitly; owner + admins always view)
Show badges On (when profile is public)
Show streak On
Show challenges On
Show top actions On
Show kudos Off
Show bio On (when member fills it)
OG image generator On

See Also

  • Privacy - full GDPR export and erasure behavior
  • Year Recap - shareable per-year recap that uses the same opt-in flag
  • Badge Sharing - sharable URL per badge with OG image

Cosmetics and Profile Frames

Cosmetics let members personalize their community presence using visual items - profile frames, overlays, or custom CSS effects. The CosmeticEngine manages the item catalog, member inventory, and equipped state.

Creating a Cosmetic Item

  1. Go to WB Gamification → Cosmetics → Add Item.
  2. Enter a name for the item (visible to members).
  3. Choose the type (e.g., profile_frame, overlay).
  4. Upload the asset (image URL or CSS asset) in the Asset URL field.
  5. Optionally enter a CSS class to apply when the item is equipped.
  6. Set the award type:
Award Type How Members Get It
admin_grant You assign it manually to specific members
purchase Members spend points from their balance
  1. If purchase, enter the points cost.
  2. Click Save.

How Members Equip Cosmetics

Members browse their cosmetic inventory on their profile page and click to equip an item. Only one item of each type can be equipped at a time. Equipping a new frame automatically unequips the previous one.

BuddyPress Profile Display

When BuddyPress is active, equipped cosmetics appear on the member's BP profile avatar and profile header. The CosmeticEngine outputs the asset and CSS class via the BuddyPress profile display hooks.

Awarding Cosmetics to Members

To grant a cosmetic item to a specific member:

  1. Go to WB Gamification → Cosmetics → Items.
  2. Click the item name.
  3. Under Grant to Members, search for and select the member.
  4. Click Grant.

You can also award cosmetics automatically as badge rewards or level-up bonuses using the Rules engine.

Notifications

WB Gamification tells members what they have earned in real time. Notifications appear as toast popups on the frontend, as BuddyPress inbox notifications, and as activity feed entries.

Toast Notifications

Toast notifications are small popups that appear in the bottom-right corner of the page immediately after a member earns a reward. They disappear automatically after 4 seconds.

There are six notification types:

Type When It Shows Example
Points After any point-earning action "+10 points - Activity update posted"
Badge When a badge is earned "Badge earned: Community Pillar"
Level up When advancing to a new level "You reached Contributor!"
Streak milestone When hitting a streak milestone "30-day streak! Keep it up."
Challenge completed When a challenge is finished "Challenge complete: Weekend Writer"
Kudos received When someone sends kudos "[Member] sent you kudos"

Each toast is dismissible. Members can click it to close it early, or just wait for it to disappear.

Note: Silent awards (challenge bonus points, streak bonus points) do not show a points toast - only the challenge or streak notification fires.

BuddyPress Notifications

When BuddyPress is active, every significant gamification event creates a BuddyPress notification. Members see these in their notification bell in the header, just like friend requests and group invites. The following events create BuddyPress notifications:

  • Badge earned
  • Level-up
  • Challenge completed
  • Kudos received
  • Streak milestone hit

Members can mark these as read from the BuddyPress notifications panel the same way as any other notification.

Activity Feed Events

When BuddyPress is active, major achievements are also posted to the BuddyPress activity stream. This makes achievements visible to the whole community, not just the member who earned them. Activity feed events are created for:

  • Badge earned
  • Level-up
  • Kudos given (shows giver, receiver, and message)
  • Challenge completed

Activity feed posts from gamification events look and behave exactly like other BuddyPress activity. Members can like and comment on them.

Member Notification Preferences

Members can control how they receive notifications from their profile settings. The available preference is the notification mode:

Mode Behavior
smart (default) Notifications appear for meaningful events (badges, levels, milestones). Routine point toasts are shown but at reduced frequency to avoid noise.
all Every point award, badge, level-up, and other event shows a notification.
quiet Only major events (badge earned, level-up) trigger notifications. Routine point toasts are suppressed.

Members access their preference from their profile settings page. Admins can set the default mode in Gamification > Settings.

Admin-Side Notifications

Admins do not receive individual member-event notifications. Instead, the Analytics dashboard gives an overview of community-wide activity. The dashboard refreshes every 10 minutes and shows trends in points, badges, and active members.

Weekly Recap Emails

Weekly Recap Emails automatically send every member a personalized summary of their gamification activity from the past seven days. The WeeklyEmailEngine handles scheduling, content assembly, and delivery via WordPress's built-in mail system.

What the Email Contains

Each email shows the member:

  • Points earned during the week
  • Badges unlocked during the week
  • Current streak status
  • Leaderboard position (if leaderboard is active)

The email uses your site name and custom sender details.

Configuration

  1. Go to WB Gamification → Settings → Emails.
  2. Set the sender name and sender email address.
  3. Optionally customize the email subject line.

Emails send automatically once per week via WordPress cron (wp_wb_gam_weekly_email). The send day and time are configurable in settings.

Weekly Recap Emails are enabled by default. To turn them off site-wide, set the weekly_emails key to false in the wb_gam_features option.

Disabling for Individual Members

Members can opt out of recap emails from their profile notification preferences. The engine respects the wb_gam_member_prefs table - members with email notifications disabled are skipped.

Troubleshooting Delivery

If emails are not sending, check:

  1. WordPress cron is running (wp cron event list).
  2. Your hosting environment allows wp_mail() outbound connections.
  3. The weekly_emails feature flag has not been turned off in wb_gam_features.

For reliable delivery on high-volume sites, use a transactional email service (SendGrid, Mailgun, Postmark) connected via a WordPress SMTP plugin.

Outbound Webhooks

Outbound Webhooks let WB Gamification send real-time event data to external services like Zapier, Make (formerly Integromat), or n8n. Each time a qualifying event fires on your site, the WebhookDispatcher sends a signed HTTP POST to your configured endpoint.

Supported Events

Event When It Fires
points_awarded Any time a member earns points
badge_earned A badge is awarded to a member
level_changed A member moves to a new level
streak_milestone A member hits a streak milestone
challenge_completed An individual challenge is completed
kudos_given A member gives kudos to another member

Creating a Webhook

  1. Go to WB Gamification → Webhooks → Add Webhook.
  2. Enter the destination URL (your Zapier webhook URL, Make webhook, etc.).
  3. Check the events you want this endpoint to receive.
  4. Click Save. The plugin generates a secret key for this webhook.

You can create multiple webhooks for different destinations or event subsets.

Payload Format

Each POST request sends a JSON body:

{
  "event": "points_awarded",
  "user_id": 42,
  "data": { ... },
  "timestamp": 1700000000
}

The exact data keys vary by event type.

Verifying Signatures

Every request includes an X-WB-Gam-Signature header. The value is an HMAC-SHA256 hash of the raw request body, signed with the webhook's secret key.

To verify in your receiving application:

$signature = hash_hmac( 'sha256', $raw_body, $secret_key );
// Compare with the X-WB-Gam-Signature header value.

Always verify signatures before processing webhook data. Reject any request where the signature does not match.

Admin Management

View all registered webhooks, their last delivery status, and recent delivery logs at WB Gamification → Webhooks. You can pause, edit, or delete any webhook from this screen.

Analytics

The Analytics dashboard gives you a high-level view of how your community's gamification program is performing. All data is aggregated and read-only - you cannot modify any records from this screen.

Accessing the Dashboard

Go to Gamification > Analytics in your WordPress admin.

Period Selector

At the top of the dashboard, a period selector lets you choose between three reporting windows:

Period What It Shows
7 days Activity from the past week
30 days Activity from the past month (default)
90 days Activity from the past quarter

Changing the period reloads all KPI cards and tables for that window.

KPI Cards

Six summary cards appear at the top of the page:

Points Awarded - Total points given to all members during the selected period. A rising trend indicates increasing member participation.

Active Members - Number of distinct members who earned at least one point during the period. Compare this against your total member count to see your engagement rate.

Badges Earned - Total badge awards during the period. A drop in this number can indicate members have collected the easy badges and you may need new milestone badges.

Badge Earn Rate - Percentage of active members who also earned a badge during the period. Useful for understanding whether your badge thresholds are achievable.

Challenge Completion Rate - Percentage of members who started a challenge and completed it. Low completion rates may indicate challenge targets are too high or time windows too short.

Streak Health - Percentage of members with a current streak greater than 0. This measures day-over-day retention - members maintaining a streak are likely to return tomorrow.

Top Actions Table

Below the KPI cards, a table shows the top point-earning actions ranked by total points awarded during the period. Columns:

  • Action name
  • Number of times the action was performed
  • Total points awarded from this action
  • Number of distinct members who performed it

Use this table to understand which behaviors your members are taking most often. If a high-value action (like completing a course) rarely appears, consider whether it is promoted enough or whether the points value is motivating.

Top Earners Table

A table of the top point-earners for the period with their avatar, name, total points in the period, and rank.

This is distinct from the public leaderboard - it shows only the selected period and is only visible to admins.

Daily Points Sparkline

A small line chart shows total points awarded each day across the selected period. Use it to spot days with unusually high or low activity, and correlate with events like challenge launches or content publishing.

Data Freshness

All analytics queries are cached for 10 minutes. The dashboard notes the last-refreshed time at the bottom of the page. If you need up-to-the-minute data after a major manual award, wait 10 minutes or clear the object cache.

What Is Not Shown

The analytics dashboard shows aggregate data only. It does not show:

  • Individual member point transactions (see Gamification > Members for that)
  • Historical data beyond 90 days via the period selector (though all data remains in the database)
  • Real-time live updates - the page must be reloaded to see fresh data

Privacy

WB Gamification is built with GDPR compliance in mind. Member data is exportable, erasable, and partially controllable by the member themselves through preference settings.

What Data Is Collected

WB Gamification stores the following data associated with each member's user ID:

  • Point events - a log of every action that earned points, including the action type, points awarded, timestamp, and optional metadata (such as word count)
  • Badge records - which badges were earned and when, plus expiry dates where applicable
  • Level state - the member's current level, derived from their point total
  • Streak data - current streak count, longest streak, last active date, and timezone
  • Challenge progress - progress toward each challenge and completion timestamps
  • Kudos sent and received - giver, receiver, message, and timestamp for every kudos transaction
  • Member preferences - leaderboard opt-out status, show_rank setting, and notification mode

No payment data, private messages beyond kudos messages, or off-site tracking is stored.

WordPress Privacy Tools Integration

WB Gamification integrates with WordPress's built-in privacy tools found at Tools > Privacy. You can use these tools to handle data subject requests.

Personal Data Export

When an admin initiates a personal data export for a member (from Tools > Export Personal Data), WB Gamification adds the following to the export file:

  • Full point history with action labels, points, and dates
  • All earned badges with names and earned dates
  • Current level name and total points
  • All kudos sent, including recipient names and messages
  • All kudos received, including sender names and messages
  • Current streak count and longest streak
  • Challenge completion records
  • Notification and privacy preference settings

The export is provided as a ZIP file containing an HTML report the member can read directly.

Personal Data Erasure

When an admin initiates a personal data erasure for a member (from Tools > Erase Personal Data), WB Gamification deletes:

  • All point event records for that user
  • All earned badge records for that user
  • All kudos records where the user is either giver or receiver
  • The streak record for that user
  • All challenge progress records for that user
  • The member preference record for that user

After erasure, the member's gamification history is permanently gone. This action is irreversible.

Note: Erasing a member's data does not affect leaderboard snapshots that were already generated before the erasure. Those snapshots are anonymized automatically when cached data expires.

Member Preferences

Members can control two privacy-related settings from their profile:

Leaderboard opt-out - When enabled, the member is excluded from all leaderboard snapshots. They will not appear on any public leaderboard, including the Leaderboard block and Top Members block. This setting takes effect on the next leaderboard cache refresh (within 10 minutes).

Show rank - When disabled, the member's rank is hidden on their public profile. They can still see their own rank privately, but other members visiting their profile will not see it.

Notification mode - Controls the frequency and types of notifications the member receives. See the Notifications documentation for details.

Members find these settings in their profile settings page under the Gamification section. If BuddyPress is active, this is within the BuddyPress profile settings. Without BuddyPress, it appears in the standard WordPress user profile screen.

Admin Data Controls

Admins can:

  • View any member's full point history via Gamification > Members
  • Award or adjust points manually with a logged reason
  • Award or revoke badges manually
  • View all kudos activity in the Analytics dashboard
  • Prune old event logs via WP-CLI (wp wb-gamification logs prune --before=6months) to manage database size without affecting member-facing data

Data Retention

By default, point event logs are kept indefinitely. On large sites, this can add up to significant database storage over time. Use the WP-CLI log prune command to delete raw event logs older than a specified date. Point totals, badge records, and level state are not affected by pruning - only the detailed event log entries are removed.

Member Achievement Surfaces

WB Gamification gives each member a place to see their own progress inside the member areas they already use - the BuddyPress profile, the WooCommerce My Account page, and (optionally) the LearnDash profile. All of these reuse the plugin's existing blocks and the mapped Hub page, so there is no duplicated display logic to keep in sync.

The Shared Renderer

Every surface goes through WBGam\Engine\MemberSurface. Each integration adapter decides which blocks to show and where to mount them; MemberSurface owns the common plumbing:

  • Enqueuing the styles the reused blocks need on a non-block host page (design tokens, base frontend CSS, the Lucide icon font, and the Hub stylesheet when the Hub block is used).
  • Rendering one or more block shortcodes scoped to a specific member.
  • Appending a "View full dashboard" link to the mapped Hub page (option wb_gam_hub_page_id) - never a hardcoded slug. The link only appears on the member's own surface and only when a Hub page is mapped.
  • Wrapping the output and passing it through the wb_gam_member_surface_html filter so a host can wrap or augment it without forking the renderer.

Surface 1 - BuddyPress Achievements Tab

When BuddyPress is active, members get an Achievements profile tab with Overview / Badges / Points / Streak sub-tabs, each scoped to the displayed member. Full detail in BuddyPress Achievements Tab.

Surface 2 - WooCommerce My Account Endpoint

Stores running WooCommerce without BuddyPress still get a member-facing surface. WBGam\Integrations\WooCommerce\AccountIntegration adds an Achievements item to the My Account menu and an endpoint at:

/my-account/achievements/

My Account is always the logged-in customer's own account, so the endpoint renders the member's full Hub block (their self dashboard) plus the mapped "View full dashboard" link.

This surface only boots when WooCommerce is active (class_exists('WooCommerce')). The rewrite endpoint is registered on init; it is flushed once on upgrade (guarded by the wb_gam_wc_account_endpoint_v1 option) and again on plugin activation. If the endpoint does not resolve on an existing install, re-save Permalinks under Settings > Permalinks to flush rewrite rules.

LearnDash only exposes a "before template" hook on its profile, so rather than stack blocks there, WB Gamification adds a single clean My Achievements link at the top of the LearnDash profile, pointing to the mapped Hub page.

This surface is off by default. LearnDash's profile extension point is less native than the BuddyPress tab or the WooCommerce endpoint, so sites opt in:

add_filter( 'wb_gam_learndash_profile_link', '__return_true' );

It only boots when LearnDash is active (LEARNDASH_VERSION defined), and renders nothing for logged-out visitors or when no Hub page is mapped.

The Mapped Hub Page

All three surfaces link to (and the WooCommerce endpoint renders) the Hub page you map during setup. The mapping is stored in the wb_gam_hub_page_id option. Because the surfaces resolve the Hub from that option, you can move or rename the Hub page without breaking any link.

Customizing Any Surface

Every surface's wrapped markup passes through one filter before output:

add_filter(
	'wb_gam_member_surface_html',
	static function ( string $html, int $user_id ): string {
		// Wrap or augment the surface for every host (BP / WC / LD).
		return $html;
	},
	10,
	2
);

See Also

Member Management

WB Gamification gives site owners a dedicated place to see and manage every member's progress, plus a bulk grant for rewarding a whole role or the entire community at once. Added in 1.5.3.

Members Roster

Go to WB Gamification > Members in your admin sidebar.

The Members page is a searchable, paginated table of every member, showing each one's points, level, and badges. It is admin-only (manage_options) and is built to stay fast on large communities - the per-page points and badge data are primed in a fixed number of queries, so the row loop never runs N+1.

Searching and paging

Type a name, username, or email into the search box. The roster searches across username, display name, email, and nicename, and pages through the full member list. Each fetch returns the page rows plus the total count and page count.

Per-member actions

Each row has three actions:

  • Award - jumps to the Award Points page to grant (or deduct) points for that member.
  • Exclude / Include - toggles whether the member can earn. Excluding sets the per-user wb_gam_sandboxed veto: the member keeps their points but stops earning and drops off leaderboards. Including reverses it. This is the per-member counterpart to the role and account lists in Member Access.
  • Reset points - zeroes the member's balance. The reset is recorded as a balancing debit, so the points ledger keeps a full audit trail rather than silently dropping rows.

REST endpoints

All admin-only (manage_options), under wb-gamification/v1:

Method Endpoint Purpose
GET /members Paginated, searchable roster (page, per_page, search)
POST /members/{id}/exclude Toggle the per-user earning veto (excluded)
POST /members/{id}/reset-points Zero the member's balance via a balancing debit

Bulk Award

Go to WB Gamification > Award Points and find the Bulk Award card.

Bulk Award grants the same number of points to every member of a chosen role, or to all members at once. Use it for community-wide rewards - a launch bonus, a milestone celebration, a thank-you to everyone in a role.

  • Award to - pick all members, or a specific role.
  • Points each - the amount to grant to every targeted member. Bulk awards are positive only.

Accounts excluded in Member Access are skipped automatically, even in a bulk grant - the bulk award routes through the same exclusion-aware batch path as every other award. For very large communities, prefer WP-CLI.

REST endpoint

curl -X POST https://example.com/wp-json/wb-gamification/v1/points/bulk \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "target": "all", "points": 50 }'
Field Type Description
target string all for every member, or a role slug
points integer Points to grant each member (positive, 1 to 100000)

Admin-only (manage_options). The response reports how many members were actually awarded after exclusions are applied.

See Also

Point Expiry

Point expiry lets you decay the balance of members who stop earning, to nudge re-engagement. It is off by default - turn it on only if your community wants points to lapse with inactivity. Added in 1.5.3.

Configure it under WB Gamification > Settings > Points, in the Point expiry card.

Opt-In

Point expiry ships disabled. With it off, balances never decay and the daily job does nothing. You enable it explicitly with the Enable point expiry checkbox.

Setting Option Default
Enable point expiry wb_gam_points_decay_enabled 0 (off)
Inactive for (days) wb_gam_points_decay_days 90
Decay amount (percent) wb_gam_points_decay_percent 100

How the Daily Decay Works

When enabled, a daily WP-Cron job (wb_gam_points_decay) finds members who:

  • have a positive primary-currency balance, and
  • have had no points activity for at least the configured number of days.

For each of those members, it reduces their primary-currency balance by the configured percent. At the default 90 days / 100 percent, a member who stops earning for 90 days has their balance zeroed; set a smaller percent (for example 25) to taper instead of wipe.

Only the primary currency is decayed. On multi-currency sites, other point types are untouched.

Applied Once Per Inactivity Streak

Decay fires once per inactivity streak, not every day. The job stamps a wb_gam_decayed_at marker on each decayed member and will not decay them again while they remain inactive. The moment a member earns again, the marker is behind their new activity, so a future inactivity streak re-arms the decay. In short: one decay per quiet spell, and earning again resets the clock.

Developer Hook

A site can react to each sweep with the wb_gam_points_decayed action, which fires after every run with the number of members decayed:

add_action(
	'wb_gam_points_decayed',
	static function ( int $count ): void {
		// Log or notify on how many members were decayed this run.
	}
);

Full signature in the Actions reference.

See Also

Settings

Admin configuration reference for each area

Points & Actions

Go to WB Gamification > Points in your admin sidebar.

The Actions Table

Each row represents one user behavior that can earn points. Actions are detected automatically from active plugins - no setup required. You will not see any rows until at least one supported plugin (WordPress core, BuddyPress, WooCommerce, etc.) is active.

The table has five columns:

Column What it controls
On Checkbox. Uncheck to disable the action entirely. Disabled actions earn zero points and fire no badges or challenges.
Action The name and description of the behavior, e.g. "Publish a post" or "Upload media."
Points How many points a member earns each time this action fires. Enter any whole number from 0 to 9999.
Repeat Whether the action can be earned more than once. Yes means every occurrence earns points. Once means the member earns points only the first time. This is set per-action in the manifest and cannot be changed from the admin.
Daily cap The maximum number of times this action counts in a single day. Shows a number or ∞ (unlimited). Like Repeat, this is defined in the manifest and is read-only in the table.

Changing point values

  1. Find the action row.
  2. Edit the number in the Points column.
  3. Click Save Changes at the bottom of the page.

Changes take effect immediately for any future action. Past points are not recalculated.

Enabling and disabling actions

Uncheck the On toggle next to any action and save. Members performing that action will no longer earn points, badges, or challenge progress from it.

Action categories

Actions are grouped into cards by category:

Category Source
WordPress Core WordPress events - publishing posts, comments, user registration
BuddyPress Social events - profile updates, activity posts, friendships, group joins
Commerce WooCommerce - purchases, product reviews
Learning LearnDash - course completions, quiz scores
Social Reactions, kudos, and other peer-recognition events
General Actions from other integrations or custom manifests

If a category does not appear, the plugin that provides it is not active on your site.

Understanding "Repeatable", "Cooldown" and "Daily Cap"

Repeatable: Once - Useful for one-time milestones like "Complete your profile" or "Write your first post." The member earns the points exactly one time, no matter how many times they perform the action.

Repeatable: Yes - The action counts every time. Use the Cooldown and Daily Cap fields to prevent abuse.

Cooldown (seconds) - Editable in 1.4.0. The minimum gap between two awards of the same action for the same member. Set bp_activity_comment to a 60-second cooldown so a member can not earn points for 50 comments posted in 30 seconds. Set to 0 to disable the cooldown.

Daily cap - Editable in 1.4.0. A hard ceiling on how many times an action can earn points in one calendar day (UTC). For example, if commenting has a daily cap of 10, a member who posts 50 comments earns points for only the first 10 each day. Set to 0 to allow unlimited awards per day.

Both Cooldown and Daily cap are editable directly in the actions table. Type a new value and click outside the field - the change saves automatically (no Save button needed). A short green flash confirms the save.

Setting either field to 0 is itself a saved override that turns the limit off - it does not restore the manifest default value. To revert to the manifest default (for example, to put a 60-second cooldown back after you set it to 0), call DELETE /wp-json/wb-gamification/v1/actions/{action_id}/overrides via REST or remove the action's row from the wb_gam_action_overrides site option.

Overrides are stored in the wb_gam_action_overrides site option, keyed by action ID. The engine merges overrides on top of the manifest values, so the same effective values are used by rate-limit checks, the admin display, and REST consumers.

Log Retention

Below the action categories, the Log Retention card controls how long the points history table keeps rows.

Field Default Range
Keep points history for 6 months 1-24 months

Rows older than this value are pruned automatically by WP-Cron once per day. The events table (the source of truth) is never pruned. This means you can always recalculate totals from events even after the points log is trimmed.

Reduce this value on high-traffic sites to keep the database lean. Increase it if you rely on per-period analytics.

Click Save Changes to apply.

Levels Configuration

Go to WB Gamification > Levels in your admin sidebar.

Levels give members a visible rank as they accumulate points. A member's level updates automatically the moment their cumulative points cross a threshold - no cron job or manual refresh needed.

The Levels Table

The table lists every level ordered from lowest to highest threshold.

Column Description
Level Name The display name members see on their profile, e.g. "Newcomer," "Member," "Veteran."
Min Points Required The cumulative point total a member needs to reach this level.
Delete Removes the level. The starting level (0 points) cannot be deleted.

Editing existing levels

  1. Click into the Level Name or Min Points Required field for any row.
  2. Change the value.
  3. Click Save Levels.

All members are re-evaluated against the new thresholds on their next activity. If you lower a threshold, members already past that point keep their current (higher) level - they are not downgraded.

The 0-point starting level has its Min Points field locked at 0 and displays "Starting level." You can rename it but not delete or change its threshold.

Adding a New Level

The Add New Level card below the table adds a new threshold.

Field Description
Level Name Required. A short name for the new level.
Min Points Required Required. Must be at least 1.

Fill both fields and click Add Level. The new row appears in the table sorted by points threshold.

  • Always keep one level at 0 points. This is the default rank for all new members.
  • Space thresholds far enough apart that members must genuinely engage to advance.
  • Give levels meaningful names that reflect community status.

Example:

Level Name Min Points
Newcomer 0
Member 100
Regular 500
Veteran 2,000
Legend 10,000

Deleting a Level

Click Delete next to any non-zero level. You will see a confirmation prompt. Deleting a level does not remove any member's points. Members who were at the deleted level fall back to the highest remaining level below their point total.

The starting level (Min Points = 0) is protected and cannot be deleted. Always keep at least one level at 0 so new members have a default rank immediately.

Badge Management

Go to WB Gamification > Badges in your admin menu.

Badges are visual rewards that recognize specific milestones, achievements, or behaviors. Members earn them automatically or receive them from an admin. The badge library shows all badges in a grid. Each card shows the badge icon, name, how many members have earned it, and whether it awards automatically or requires manual granting.

Creating a New Badge

Click + Create New Badge in the toolbar. A form appears with two sections: badge details and award condition.

Badge Details

Field Required Description
Badge ID Yes A unique machine-readable identifier. Lowercase letters, numbers, and underscores only (e.g. first_post). Cannot be changed after creation.
Name Yes The display name shown to members when they earn the badge (e.g. "First Post").
Description No Explains what the badge is for. Shown on badge cards and the public share page.
Icon No An image from your Media Library. Recommended size: 128×128 px PNG with a transparent background. Click Choose Icon to open the media picker. Click Remove to clear it.
Category No Groups badges in the frontend showcase. Options: General, Points, WordPress, BuddyPress, Special.
Is Credential No Marks the badge as a verifiable OpenBadges 3.0 credential. Members can share a verified badge URL - useful for professional achievements on LinkedIn.
Closes at No A date and time after which no new members can earn this badge. Leave blank for no cutoff. Displayed in your site's timezone.
Max earners No The maximum number of members who can earn this badge. Once reached, the badge stops auto-awarding. Leave blank for unlimited.

Auto-Award Condition

This section controls how the badge is awarded.

Condition When it awards
Admin awarded only (manual) The badge is never awarded automatically. Only admins can grant it via the Award Points page or the Badges page.
Reaches a point milestone Awards automatically when a member's total points reach or exceed a threshold you specify. Enter the point value in Points Threshold.
Performs an action N times Awards automatically when a member completes a specific action a set number of times. Choose the Action from the dropdown and enter the Target Count.

Click Create Badge to save.

Editing a Badge

Click any badge card in the grid to open its edit form. All fields are editable except the Badge ID. Change what you need and click Save Changes.

Deleting a Badge

While editing a badge, click Delete Badge. Confirm the prompt. This permanently removes the badge definition and all earned records. Members who previously held the badge will lose it from their profiles.

The 30 Default Badges

The plugin ships with 30 pre-built badge definitions covering common milestones (first post, point milestones, social actions, tenure). They appear in the badge grid on a fresh install. You can edit, delete, or supplement them with your own.

Challenge Manager

Go to WB Gamification > Challenges in your admin menu.

Challenges give members a time-limited goal: perform a specific action a set number of times before the deadline to earn bonus points. Progress counts only while the challenge is active.

Individual vs Community Challenges

Unified in 1.4.0. The Challenge Manager page now has two tabs:

  • Individual Challenges - each member works toward their own copy of the goal. Points and bonuses are awarded per member.
  • Community Challenges - the whole community works toward one shared goal. Every member's contribution counts toward the collective target.

The two tabs share the same admin page (the standalone Community Challenges submenu was removed). Existing direct links to ?page=wb-gam-community-challenges continue to work - they now load the same page with the Community tab pre-selected.

Time Zones

Fixed in 1.4.0. All challenge Start Date and End Date values are stored in UTC. When you open the edit form, the displayed time is automatically converted to your browser's local timezone - so a challenge created at "9:00 AM your time" is shown as 9:00 AM on every edit, regardless of how your server is configured. The activation check is also in UTC, so a challenge configured to start at 9:00 AM local time becomes active at 9:00 AM local time without drift.

Creating a Challenge

The Create Challenge form is at the top of the page.

Field Required Default Description
Title Yes - A short name shown to members on the challenge card, e.g. "Post 10 photos this week."
Action Yes - The user behavior that counts toward this challenge. Choose from all registered actions (same list as the Points tab).
Target Count Yes 10 How many times the member must perform the action to complete the challenge. Minimum 1.
Bonus Points No 50 Extra points awarded when the member hits the target. Set to 0 for a challenge with no point bonus (e.g. badge-only reward).
Start Date No Now When the challenge becomes available. Actions before this date do not count.
End Date No 7 days from now The deadline. Members must reach the target before this date and time.

Click Create Challenge to save. The new challenge appears in the All Challenges list below.

The Challenge List

The table shows all challenges with these columns:

Column Description
Title Challenge name
Action The action being tracked
Target Required action count
Bonus Bonus points on completion
Status Active or other status
Dates Start date → End date
Actions Edit or Delete buttons

Editing a Challenge

Click Edit next to any challenge. The form at the top of the page fills with the existing values. Make your changes and click Update Challenge. Click Cancel to go back without saving.

Deleting a Challenge

Click Delete in the challenge row. Confirm the prompt. This removes the challenge definition. Member progress toward the deleted challenge is not removed from the events log, but the challenge no longer appears to members.

Notes on Challenge Design

  • Default 7-day duration. The end date defaults to 7 days from when you create the challenge. Adjust this for shorter sprints (24-hour flash challenges) or longer campaigns.
  • Actions must be enabled. If you disable an action on the Points tab, it will not count toward challenges that use it.
  • One action per challenge. Each challenge tracks a single action type. To create multi-action goals, create multiple challenges and use a badge as the reward for completing all of them.
  • Bonus points stack with regular points. Members earn their normal per-action points throughout the challenge period, plus the bonus on completion.

Kudos Settings

Go to WB Gamification > Kudos in your admin sidebar.

Kudos is a peer-recognition system. Members send kudos to each other to say "great work." Both the giver and the receiver can earn points, which encourages participation on both sides.

Fields

Max kudos per day

Default: 5

The maximum number of kudos a single member can send in one calendar day. Once a member hits this limit, they cannot send more until the next day.

This prevents kudos flooding. If members are using kudos to farm points for a friend, lower this value. If you want kudos to feel free and frictionless, raise it.

Recommended values by community size:

Community size Suggested limit
Small (< 100 members) 3-5
Medium (100-1,000) 5-10
Large (1,000+) 10-20

Points per kudos received

Default: 5

The number of points the recipient earns each time they receive a kudos. This rewards members for creating content and behavior that others appreciate.

Set to 0 if you want kudos to be symbolic recognition without point value.

Points per kudos given

Default: 2

The number of points the sender earns each time they give kudos to another member. Keeping this lower than the receiver value ensures that the primary reward goes to the person being recognized, not the person clicking the button.

Set to 0 if you only want the receiver to benefit.

Saving

Click Save Changes after adjusting any value. Changes apply to all future kudos immediately. Existing kudos in the log are not retroactively recalculated.

Notes

  • Kudos daily limits and point values work independently. You can have a high limit with low point values (social and lightweight) or a low limit with high point values (rare and meaningful).
  • The Kudos feed block ([wb_gam_kudos_feed] shortcode) displays recent kudos activity on the frontend.
  • If BuddyPress is active, kudos events also appear in the BuddyPress activity stream.

Rank Automation Rules

Go to WB Gamification > Rules in your admin sidebar.

Rank Automation rules trigger actions automatically when a member reaches a specific level. Use them to onboard members into groups, grant role upgrades, or send congratulatory messages - all without writing any code.

How rules work

Each rule has:

  • A trigger - which level the member must reach
  • An action - what happens when they reach it

Rules fire once per member per level. If a member already passed a level before you created a rule for it, they will not receive the action retroactively.

You can add multiple rules for the same level. Each rule triggers independently.

Adding a New Rule

Fill in the Add New Rule form at the bottom of the page.

Step 1: Choose the trigger level

Select the level from the When member reaches level dropdown. This list shows all levels you have configured in the Levels tab.

Step 2: Choose the action type

Select one of the three action types from the Perform action dropdown. The form shows only the fields relevant to your selection.


Action type: Add to BuddyPress group

Automatically adds the member as a member of a BuddyPress group.

Field Description
BuddyPress Group ID The numeric ID of the group. Find this in BuddyPress > Groups - hover over a group name and look for gid= in the URL.

Use case: Add members who reach "Veteran" level to a private "VIP Members" group, giving them access to exclusive content.


Action type: Add WordPress role

Adds a WordPress role to the member's account. This adds the role - it does not replace their existing roles.

Field Description
Role slug The lowercase WordPress role slug, e.g. contributor, editor, or a custom role slug registered by another plugin.

Use case: Grant contributor access to members who reach the "Regular" level, allowing them to submit posts for review.


Action type: Send BuddyPress message

Sends a private BuddyPress message to the member from a specified user.

Field Description
Message sender user ID The user ID of the account that appears as the sender. Defaults to 1 (the site admin).
Message subject The subject line of the private message.
Message content The body of the message. Plain text.

Use case: Send a congratulations message when a member reaches "Gold" level, including instructions for their new benefits.


Click Add Rule to save. The rule appears in the rules table immediately.

Viewing and deleting rules

The rules table shows:

Column Description
When member reaches The level name that triggers the rule
Action The action type
Parameters The configuration values (group ID, role, or message details)

Click Delete next to any rule and confirm the prompt to remove it. Deleting a rule does not undo actions already performed for members who previously reached the level.

Use case examples

Goal Trigger level Action type Configuration
Welcome new members to a starter group Newcomer (0 pts) Add to BP group Group ID of your "All Members" group
Unlock content for engaged members Regular (500 pts) Add WP role subscriber-plus (custom role)
Personally congratulate top contributors Legend (10,000 pts) Send BP message Sender = admin, personalized message
Give editors posting rights at Veteran level Veteran (2,000 pts) Add WP role contributor

Manual Point Awards

Go to WB Gamification > Award Points in your admin menu.

Use this page to grant or deduct points from any member directly. All awards go through the standard points engine, so badges, level-ups, streaks, and hooks fire exactly as they would for any automatic event.

The Award Form

User

A dropdown listing all WordPress users. Select the member who will receive or lose points.

Points

Enter a positive number to award points. Enter a negative number to deduct points.

The maximum you can award or deduct in a single action is ±10,000 points.

Examples:

  • 100 - awards 100 points
  • -50 - deducts 50 points
  • 10000 - awards the maximum in one action

Reason / Note

Optional. A short note stored with the award entry and shown in the recent history table below. Maximum 200 characters.

The note is visible only to admins. It is not shown to the member.

Use this to document why you made the adjustment. Examples from the form placeholder: "Contest winner," "Support bonus," "Policy violation."

Click Award Points to submit.

Recent Manual Awards

The table below the form shows the 20 most recent manual awards. Each row shows:

Column Description
User The member's display name
Points The amount awarded (green badge) or deducted (red badge)
Note The reason entered at the time
Date The date and time of the award in your site's date/time format

The note shown is the most recent note stored for each user, not necessarily the note from that specific row. Notes are stored as user meta, so if you award a user twice, the note column for older rows will show the most recent note.

Common use cases

Rewarding contest winners Run a community photo contest. Award the top three entries 500, 300, and 100 points respectively. Enter "Photo contest - 1st place" in the reason field.

Support bonuses A member helped another user solve a complex problem. Award 50 bonus points with the note "Community support bonus."

Policy violations A member spammed the activity feed. Deduct 100 points with the note "Spam warning - policy violation." Combine this with a WP role change via Rank Automation if needed.

Onboarding boosts Give new members a 25-point welcome bonus to help them reach the first level threshold faster.

Notes

  • You cannot award more than ±10,000 points per form submission. For larger adjustments, submit the form multiple times.
  • Deducting points below zero is possible. A member's total can go negative if you deduct more than they have earned.
  • All manual awards appear in the points log alongside automatic events.

API Keys

Go to WB Gamification > API Keys in your admin menu.

API keys let remote sites connect to this WordPress installation as a centralized gamification hub. A remote site sends requests to this site's REST API using the key as an authentication credential.

Generating a New Key

Fill in the Generate New Key form.

Field Required Description
Label Yes A human-readable name for the key. Use the name of the site or application it belongs to, e.g. "MediaVerse Production."
Site ID No A short machine-readable identifier for the remote site, e.g. mediaverse-prod. Used for per-site reporting and filtering in the points log.

Click Generate Key.

Copy the key immediately

The full API key is shown once in a notice at the top of the page immediately after generation. It will not be shown again. Copy it now and store it securely (a password manager or secrets vault).

After you navigate away from the page, the key table shows only the first 12 characters followed by ... - enough to identify the key but not enough to use it.

The Active Keys Table

Column Description
Label The name you gave the key
Site ID The machine identifier you provided
Key (prefix) First 12 characters of the key for identification
Created When the key was generated
Last Used The most recent time the key authenticated a request, or - if unused
Status Active or Revoked
Actions Revoke and Delete buttons

Revoking a key

Click Revoke next to an active key. The key remains in the table with a "Revoked" status badge. Requests sent with a revoked key are rejected with a 401 response. The remote site is immediately locked out without deleting the audit record.

Use revoke when you suspect a key has been compromised but want to keep the entry visible for review.

Deleting a key

Click Delete next to any key (active or revoked) and confirm the prompt. The key is permanently removed from the database. Unlike revoking, this removes the record entirely.

Use delete to clean up keys from decommissioned sites.

How authentication works

Remote sites include the key in the X-WB-Gam-Key HTTP request header:

X-WB-Gam-Key: your-api-key-here

Any request to the WB Gamification REST API (/wp-json/wb-gamification/v1/) that includes a valid active key is authenticated as an admin-level consumer. All endpoints are available to authenticated key requests.

Typical use case: centralized gamification

You operate multiple WordPress sites in your network. One site acts as the gamification hub - it holds all the point rules, badge definitions, and leaderboards. Each other site has WB Gamification installed in remote mode and sends events to the hub via REST API using its own API key. Members accumulate points across all connected sites in one unified profile.

Generate one key per remote site. Label each key clearly so you can identify and revoke individual sites if needed.

Realtime and Notification Settings

Go to WB Gamification > Settings > Realtime in your admin sidebar.

This section controls how live reward feedback reaches members - the transport that delivers updates, and where on screen reward toasts appear.

Toast Position

Default: Bottom right (recommended)

Reward toasts (points, badges, kudos) slide in from the corner you pick here. The toast is corner-aware, so a bottom corner slides up and a top corner slides down.

Option Stored value
Bottom right (recommended) bottom-right
Bottom left bottom-left
Top right top-right
Top center top-center

Bottom right is recommended because it never overlaps your theme header or navigation. Choose a top position only if a chat or support widget already sits in the bottom corner.

The selection is stored in the wb_gam_toast_position option. Developers can override it per request with the wb_gam_toast_position filter - see the Filters reference.

Realtime Transport

Default: Heartbeat

The transport decides how the browser receives live updates. WP Heartbeat is the shipped default and is right for most sites - it polls on a shared, throttled tick (15s steady, a 5s burst for ~30s after a member action, near-suspend on hidden tabs).

Option When to use
Heartbeat Default. Works on every host.
SSE Server-Sent Events stream for sub-second toasts. Opt-in: it also requires the wb_gam_sse_allowed filter to return true and a host built for long-lived connections.
Auto Client tries SSE first (when permitted) and falls back to Heartbeat.

SSE is gated because its long-poll pins one PHP-FPM worker per connected member, which does not scale on a standard pool. Full transport detail, host requirements, and the wb_gam_sse_allowed filter are in the developer guide: Realtime transport.

The transport can also be set with WP-CLI:

wp option get wb_gam_realtime_transport      # default: heartbeat
wp option update wb_gam_realtime_transport auto

Member Access (Earning Exclusion)

Go to WB Gamification > Settings > Access in your admin sidebar.

This section decides who is allowed to earn. Most communities exclude administrators, staff, support agents, and bots so internal testing and service accounts do not skew the leaderboard. Added in 1.5.3.

What Exclusion Does

An excluded member:

  • Keeps any points they already earned - nothing is deleted.
  • Stops accruing new points, badges, levels, and streaks - every award path is blocked, not just the obvious ones.
  • Is hidden from leaderboards - they no longer appear in the leaderboard or top-members surfaces.

Exclusion is enforced at the single award choke point in PointsEngine::user_can_earn(), so it covers both the synchronous and the asynchronous (Action Scheduler) award paths and every caller. Logged-out visitors never earn.

Manual admin awards and the WP-CLI points award command can still grant points to an excluded account on purpose - those paths pass an explicit force flag so an owner can correct a balance even for a sandboxed user.

Excluded Roles

Tick any roles that should never earn. Any member who holds one of the checked roles is excluded.

The roles list is your site's real role names (Administrator, Editor, Subscriber, plus any custom roles). The selection is stored in the wb_gam_excluded_roles option as an array of role slugs.

Most communities exclude Administrator and any staff role here.

Excluded Accounts

Exclude specific accounts regardless of their role. Enter usernames, emails, or user IDs separated by commas or new lines, for example:

supportbot, qa@example.com, 42

On save, each entry is resolved to a user. Unrecognized entries are dropped, and the saved field shows the resolved usernames. The resolved IDs are stored in the wb_gam_excluded_users option as an array of user IDs.

Per-Member Exclusion

Beyond roles and the accounts list, a single member can be excluded from the Members roster page (the Exclude / Include toggle). That toggle writes the per-user wb_gam_sandboxed meta, which is a per-user veto checked by the same user_can_earn() gate. See Member Management.

Developer Hook

After the role, account-list, and per-user checks are applied, the result passes through a filter so code can extend or override the owner's choices:

add_filter(
	'wb_gam_user_can_earn',
	static function ( bool $can, int $user_id ): bool {
		// Block everyone whose email is unverified, for example.
		return $can;
	},
	10,
	2
);

Full signature in the Filters reference.

See Also

Modules

Go to WB Gamification > Settings > Modules in your admin sidebar.

Not every community wants every mechanic. This section turns optional engagement modules on or off so you only ship what your members will actually use. Added in 1.5.3.

Optional Modules

Module What it covers
Kudos Peer kudos - the kudos-feed and give-kudos blocks/shortcodes
Streaks Daily and weekly streak tracking - the streak block/shortcode
Challenges Individual challenges - the challenges block/shortcode and the Challenges admin page
Community challenges Group challenges - the community-challenges block/shortcode and the Community Challenges admin page
Cohort leagues Cohort-based leaderboard leagues - the cohort-rank block/shortcode
Redemption store Rewards store - the redemption-store block, its shortcodes, and the Redemption admin page

The toggle map is stored in the wb_gam_modules option as slug => '1' | '0'. A module is on by default; only an explicit '0' turns it off.

What Disabling a Module Does

When a module is off:

  • Its blocks render nothing. A page that still contains a disabled module's block outputs nothing for that block.
  • Its shortcodes render nothing. A post still containing a disabled module's shortcode outputs nothing for that shortcode.
  • Its admin submenu page is removed (for modules that have one - Challenges, Community challenges, Redemption store).
  • All data is preserved. Disabling hides a module; it does not delete kudos, streaks, challenge definitions, redemption items, or any history. Turn it back on and everything returns.

Always-On Core

These are never optional and have no toggle:

  • Points
  • Badges
  • Levels
  • Leaderboards

They are the foundation every other module builds on, so they always run.

Developer Hook

Each module's enabled state passes through a filter, so code can force a module on or off regardless of the saved setting:

add_filter(
	'wb_gam_module_enabled',
	static function ( bool $enabled, string $slug ): bool {
		// Force the redemption store off everywhere.
		return 'redemption' === $slug ? false : $enabled;
	},
	10,
	2
);

Full signature in the Filters reference.

See Also

Admin Tools

Go to WB Gamification > Settings > Tools in your admin sidebar.

Tools are the maintenance and portability controls a site owner reaches for occasionally: move your configuration between sites, rebuild the leaderboard snapshot, and (in the danger zone) wipe all member progress. Added in 1.5.3.

Settings Import / Export

Export the plugin configuration to a JSON file, then import it on another site to clone your setup. This is the fast way to mirror a staging site onto production, or to seed a new community with a configuration you have already tuned.

  • Export downloads a JSON document of every wb_gam_* configuration option.
  • Import applies a document produced by export. Only keys that start with wb_gam_ and are not on the exclusion list are written.

The export and import deliberately exclude runtime, derived, and schema state - the database version, feature schema gates, caches, snapshots, flush markers, and wizard flags - so an import never corrupts the target site or drags one site's derived state onto another. Configuration travels; machine state does not.

Action REST endpoint
Export GET wb-gamification/v1/tools/export-settings
Import POST wb-gamification/v1/tools/import-settings

Both are admin-only (manage_options). The engine behind them is WBGam\Engine\SettingsIO.

Rebuild Leaderboard

Recompute the leaderboard snapshot and clear its caches. Use this if a leaderboard ever looks stale - after a bulk import, a manual database change, or a points correction.

This is the admin equivalent of the WP-CLI command:

wp wb-gamification doctor --recompute-leaderboard
Action REST endpoint
Rebuild leaderboard POST wb-gamification/v1/tools/recompute-leaderboard

Admin-only (manage_options).

Reset Member Progress (Danger Zone)

DANGER: this permanently clears member progress and cannot be undone. Export your settings first if you want a copy of your configuration, and take a database backup before you run it.

Use this when you want to keep your whole setup - badge definitions, levels, rules, challenge definitions, point types, reward items, member preferences, webhooks, API keys, and every setting - but start every member from zero. A typical case is launching to real members after a testing period.

What is wiped (member progress):

  • Points and the immutable event log
  • User point totals
  • Earned badges
  • Streaks
  • Kudos
  • Leaderboard cache
  • Challenge logs
  • Cohort membership
  • Community-challenge contributions (and each community challenge's progress counter is reset to zero, keeping its definition)
  • Redemptions
  • Submissions
  • Per-user progress meta (login streak counters, cached level, league tier, recap bests, onboarding toast flag, notification cursors)

What is kept (configuration and definitions):

  • Badge definitions, levels, rules, challenge definitions
  • Point types and reward items
  • Member preferences
  • Webhooks and API keys
  • All settings

The reset is engineered as a single confirmed operation. The REST endpoint requires an explicit confirm: true on top of the admin capability check, so it can never fire by accident:

curl -X POST https://example.com/wp-json/wb-gamification/v1/tools/reset-progress \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "confirm": true }'
Action REST endpoint
Reset member progress POST wb-gamification/v1/tools/reset-progress (admin-only, requires confirm: true)

The engine behind it is WBGam\Engine\ProgressReset. It fires the wb_gam_progress_reset action after the wipe so adapters can clear their own derived state.

See Also

Integrations

Connecting WB Gamification to other plugins

Integrations Overview

WB Gamification connects to other WordPress plugins automatically. You do not configure integrations manually - the ManifestLoader scans for manifest files at plugins_loaded priority 5 and registers their actions before the engine boots.

How Auto-Discovery Works

Each integration is a PHP file that returns an array of trigger definitions. When the target plugin is active, the manifest loads and its actions become available in the points engine, badge rules, and challenge conditions. If the target plugin is not active, the manifest returns an empty array and is skipped entirely.

First-party manifests ship inside the integrations/ directory of WB Gamification itself. Drop-in manifests ship inside the target plugin (like WPMediaVerse Pro) and are discovered automatically when that plugin is installed.

Supported Integrations

Plugin Actions Manifest Location
WordPress Core 8 integrations/wordpress.php
BuddyPress 10 integrations/buddypress.php
bbPress 3 integrations/bbpress.php
WooCommerce 4 integrations/woocommerce.php
LearnDash 5 integrations/learndash.php
LifterLMS 5 integrations/contrib/lifterlms.php
MemberPress 3 integrations/contrib/memberpress.php
GiveWP 4 integrations/contrib/givewp.php
The Events Calendar 3 integrations/contrib/the-events-calendar.php
Jetonomy 4 integrations/jetonomy.php
Jetonomy Pro 7 integrations/jetonomy-pro.php
WPMediaVerse Pro 17 wpmediaverse-pro/wb-gamification.php

In addition to the manifest actions above, Jetonomy reputation deltas are mirrored 1:1 into the points ledger (see Jetonomy integration), and WB Gamification defers its own leaderboard display to Jetonomy's reputation ranking when Jetonomy is active.

Zero Configuration

Once an integrated plugin is active, its actions appear immediately in:

  • The points engine (with default point values you can override)
  • Badge award conditions
  • Challenge target conditions
  • The Actions admin screen (WB Gamification → Actions)

Default point values are set per action in each manifest. You can override any default from WB Gamification → Actions → Edit.

Checking Integration Status

Run wp wb-gamification doctor --verbose to see which integrations are detected, how many actions are registered per integration, and whether any duplicate hook registrations exist.

BuddyPress Integration

The BuddyPress integration is the most comprehensive integration in WB Gamification. It covers the core social loop - posting, commenting, friending, and group activity - as well as BuddyPress add-ons for reactions, polls, member blogs, and media.

The manifest loads automatically when BuddyPress is active. No configuration is required.

Actions

Action ID Label Default Points Repeatable
bp_activity_update Post an activity update 10 Yes (30s cooldown)
bp_activity_comment Comment on an activity 5 Yes (30s cooldown)
bp_friends_accepted Accept a friendship 8 Yes
bp_groups_join Join a group 8 Yes
bp_groups_create Create a group 20 Yes
bp_profile_complete Complete extended profile 15 No (once only)
bp_reactions_received Receive a reaction 3 Yes
bp_polls_created Create a poll 10 Yes
bp_publish_post Publish a member blog post 25 Yes
bp_media_upload Upload media 5 Yes (60s cooldown)

Notes

  • bp_friends_accepted awards the member who accepts the request, not the one who initiated it.
  • bp_profile_complete fires on xprofile_updated_profile. It is non-repeatable - a member earns it once.
  • bp_reactions_received requires the BuddyPress Reactions add-on.
  • bp_polls_created requires the BuddyPress Polls add-on.
  • bp_publish_post requires the BP Member Blog add-on and awards on publish_post for post post type only. Pages and custom post types are excluded.
  • bp_media_upload requires the BuddyPress Media add-on.

Profile Display

When BuddyPress is active, WB Gamification adds a gamification panel to member profiles showing points, level, badges, and streak. This is handled by ProfileIntegration and DirectoryIntegration.

Activity Feed

Points and badge events post to the BuddyPress activity feed via BPActivity. Members see their own achievements and (optionally) achievements from members they follow.

Member Directory

The member directory gains a sort option for Most Points when BuddyPress Directory Integration is active.

WooCommerce Integration

The WooCommerce integration rewards purchasing behavior and product engagement. The manifest loads automatically when WooCommerce is active.

Actions

Action ID Label Default Points Repeatable
wc_order_completed Complete a purchase 25 Yes
wc_first_purchase Complete first purchase ever 50 No (once only)
wc_product_reviewed Leave a product review 15 Yes (1/product/day)
wc_wishlist_add Add a product to wishlist 5 Yes (5min cooldown)

Notes

  • wc_first_purchase fires on the same hook as wc_order_completed but checks whether this is the customer's first completed order. It only awards points when exactly one completed order exists for that customer.
  • wc_product_reviewed fires on comment_post with a guard that checks the post type is product and the comment is approved. This prevents double-awarding if you also have the WordPress Core comment action active.
  • wc_wishlist_add requires the YITH WooCommerce Wishlist plugin. It fires on yith_wcwl_added_to_wishlist.

Preventing Double Points on Reviews

The WooCommerce manifest's review action explicitly checks post_type === 'product'. The WordPress Core manifest's comment action targets non-product post types. The two actions do not overlap.

Member Surface

WB Gamification adds an Achievements item to the WooCommerce My Account menu and an endpoint at /my-account/achievements/ that renders the member's full Hub dashboard. This gives stores running WooCommerce without BuddyPress a member-facing gamification surface. See Member Achievement Surfaces. If the endpoint 404s on an existing install, re-save Settings > Permalinks to flush rewrite rules.

Requirements

  • WooCommerce active

LearnDash Integration

The LearnDash integration rewards learners at every stage of the course progression path - from individual topics through to full course completion and instructor-approved assignments.

The manifest loads automatically when LearnDash is active.

Actions

Action ID Label Default Points Repeatable
ld_course_completed Complete a LearnDash course 100 Yes
ld_lesson_completed Complete a LearnDash lesson 15 Yes
ld_topic_completed Complete a LearnDash topic 5 Yes
ld_quiz_passed Pass a LearnDash quiz 25 Yes
ld_assignment_approved Assignment approved by instructor 20 Yes

Notes

  • ld_topic_completed uses the manifest default of 5 points (the source file shows 5, not 15 - see the topic entry).
  • ld_quiz_passed only awards points when the learner actually passes (the pass flag in the quiz data is true). Failed quiz attempts earn nothing.
  • ld_assignment_approved fires when an instructor marks an assignment as approved, not when the learner submits it. This rewards quality work, not just submission.
  • All five actions are repeatable with no cooldown, so learners earn points every time they complete a lesson or course - even if they revisit it.

The default values reward depth of engagement. A learner who completes an entire course earns 100 points for the course itself plus 15 per lesson and 5 per topic along the way. Adjust point values to reflect how much depth matters in your learning community.

Member Surface (opt-in)

WB Gamification can add a single "My Achievements" link to the top of the LearnDash profile, pointing to the mapped Hub page. It is off by default - opt in with the wb_gam_learndash_profile_link filter. See Member Achievement Surfaces.

Requirements

  • LearnDash active

bbPress Integration

The bbPress integration rewards forum participation. The manifest loads automatically when bbPress is active.

Actions

Action ID Label Default Points Repeatable
bbp_new_topic Create a forum topic 10 Yes (5min cooldown)
bbp_new_reply Post a forum reply 5 Yes (60s cooldown)
bbp_topic_closed Topic resolved / closed 20 Yes

Notes

  • bbp_topic_closed fires when a topic is marked as closed or resolved. It awards points to the topic author, not the moderator who closed it. The action checks $r['is_closed'] - reopening a topic does not trigger the award.
  • Cooldowns on bbp_new_topic (5 minutes) and bbp_new_reply (60 seconds) prevent abuse from rapid posting.

Relationship to BuddyPress Integration

bbPress and BuddyPress actions are separate and do not conflict. A forum reply is a different action from a BuddyPress activity update - they fire on different hooks and represent different types of community participation. You can have both integrations active at the same time.

Requirements

  • bbPress active

WPMediaVerse Pro Integration

WPMediaVerse Pro ships its own gamification manifest (wb-gamification.php in the plugin root). When both WPMediaVerse Pro and WB Gamification are active, ManifestLoader discovers the file automatically and registers all 17 actions. No configuration is needed.

This is a drop-in manifest - it lives inside WPMediaVerse Pro, not inside WB Gamification. That means manifest updates ship with WPMediaVerse Pro releases.

Actions by Category

Media (content creation and engagement received)

Action ID Label Default Points
mvs_upload_photo Upload a photo 10
mvs_create_album Create an album 15
mvs_receive_like Receive a like on photo 2
mvs_receive_comment Receive a comment on photo 5
mvs_receive_favorite Photo bookmarked by someone 2

mvs_receive_like and mvs_receive_favorite award the media owner, not the person who reacted. Self-likes (liking your own content) are excluded - the engine compares the reactor ID against the media author and returns 0 if they match.

Social (engagement given - awards the actor)

Action ID Label Default Points Daily Cap
mvs_receive_follow Gain a new follower 3 -
mvs_give_comment Write a meaningful comment 3 20
mvs_give_follow Follow another member 1 50
mvs_bookmark_photo Bookmark a photo 1 30

mvs_give_comment requires the comment to be 20 or more characters. Single-word or empty comments earn nothing. Daily caps prevent point farming.

Note: mvs_receive_follow awards the member being followed (social category), not the follower - it appears here because it measures social growth.

Competition

Action ID Label Default Points
mvs_battle_win Win a photo battle 100
mvs_challenge_participate Enter a photo challenge 10
mvs_challenge_win_1st Win 1st place in a challenge 200
mvs_challenge_win_2nd Win 2nd place in a challenge 100
mvs_challenge_win_3rd Win 3rd place in a challenge 50
mvs_tournament_round_win Win a tournament round 150
mvs_tournament_win Win a tournament 500

Competition actions have no cooldowns or daily caps - they are high-stakes events that fire infrequently by design.

Engagement (streaks)

Action ID Label Default Points
mvs_streak_milestone Hit an upload streak milestone 50 (base)

mvs_streak_milestone fires when a member hits 7, 30, 100, or 365 consecutive upload days. The manifest uses a points_callback that reads the $xp bonus passed by WPMediaVerse Pro's streak engine - the actual points awarded may exceed the 50-point default depending on streak length.

Requirements

  • WPMediaVerse Pro active
  • WB Gamification (free) active

LifterLMS Integration

The LifterLMS integration rewards learning progress: completing courses and lessons, passing quizzes, and earning achievements and certificates. The manifest loads automatically when LifterLMS is active.

Actions

Action ID What it rewards Default Points
llms_course_completed Complete a LifterLMS course 100
llms_lesson_completed Complete a LifterLMS lesson 10
llms_quiz_passed Pass a LifterLMS quiz 25
llms_achievement_earned Earn a LifterLMS achievement 30
llms_certificate_earned Earn a LifterLMS certificate 50

Requirements

  • LifterLMS active

How it works

This integration is auto-detected. No configuration is needed. As soon as LifterLMS is active, points fire automatically whenever a student completes a course or lesson, earns an achievement, or is issued a certificate.

llms_quiz_passed only awards points when the student reaches a passing grade on the attempt. A failed attempt earns nothing. llms_certificate_earned rewards the final milestone in any course that issues certificates.

MemberPress Integration

The MemberPress integration rewards membership activity: activating a membership, renewing it, and joining as a paid member for the first time. The manifest loads automatically when MemberPress is active.

Actions

Action ID What it rewards Default Points
mp_membership_activated Activate a MemberPress membership 50
mp_membership_renewed Renew a MemberPress membership 30
mp_first_membership Join as a paid member for the first time 100

Requirements

  • MemberPress active

How it works

This integration is auto-detected. No configuration is needed. Points fire automatically as soon as MemberPress is active and a member activates or renews a membership.

mp_membership_activated has a one-hour cooldown so a single signup is not rewarded more than once. mp_first_membership fires on the same signup event but only awards once per member, the very first time they join as a paid member.

GiveWP Integration

The GiveWP integration rewards donor activity: completing a donation, making a first donation, contributing to recurring donations, and helping a campaign reach its goal. The manifest loads automatically when GiveWP is active.

Actions

Action ID What it rewards Default Points
give_donation_completed Complete a donation 30
give_first_donation Make first donation ever 75
give_recurring_donation Make a recurring donation payment 20
give_campaign_goal_reached Campaign reaches its goal 15

Requirements

  • GiveWP active

How it works

This integration is auto-detected. No configuration is needed. Points fire automatically as soon as GiveWP is active and a donation is successfully processed.

Points recognize the act of donating, not the amount. Values are not tied to donation size, which preserves donor privacy and avoids rewarding larger donors disproportionately. give_first_donation awards once per member, the first time they ever donate. give_recurring_donation requires the GiveWP Recurring Donations add-on.

The Events Calendar Integration

The Events Calendar integration rewards event participation: RSVPing to an event, purchasing a ticket, and checking in on the day. The manifest loads automatically when The Events Calendar is active.

Actions

Action ID What it rewards Default Points
tec_rsvp_registered RSVP to an event 10
tec_ticket_purchased Purchase an event ticket 20
tec_event_checked_in Check in to an event 15

Requirements

  • The Events Calendar active

How it works

This integration is auto-detected. No configuration is needed. Points fire automatically as soon as The Events Calendar is active and a member RSVPs, buys a ticket, or checks in.

tec_rsvp_registered only awards on a "going" RSVP. Declining an RSVP earns nothing. tec_event_checked_in awards the attendee when they are checked in at the event.

WordPress Core Integration

The WordPress Core integration rewards everyday site activity such as registering, logging in, publishing posts, and leaving comments. It is built in and works with no other plugin installed.

Actions

Action ID What it rewards Default Points
wp_user_register Register an account on the site 15
wp_first_login Log in for the very first time 10
wp_profile_complete Save a WordPress profile that includes a bio 10
wp_post_receives_comment Post author earns when an approved comment lands on their content 3
wp_publish_post Publish a new blog post 25
wp_first_post Publish your first post ever 20
wp_leave_comment Leave an approved comment 5
wp_comment_approved Have a pending comment approved from moderation 5

Notes

  • wp_user_register, wp_first_login, wp_profile_complete, and wp_first_post are awarded once and do not repeat.
  • wp_publish_post and wp_first_post fire on the transition into the published state, so editing an already-published post does not re-award points.
  • wp_post_receives_comment rewards the post author and is capped at 10 awards per day to stop comment-spam grinding. wp_leave_comment rewards the commenter and has a 60-second cooldown.
  • Comment actions skip product reviews so they never overlap with the WooCommerce integration.
  • The post and comment actions for individual authors (wp_publish_post, wp_first_post, wp_leave_comment, wp_comment_approved) are standalone-only: when BuddyPress is active, BuddyPress covers the same activity and these stay off to prevent double-awarding.

How it works

These actions fire automatically on core WordPress hooks such as user_register, wp_login, transition_post_status, and comment_post. There is nothing to wire up. As soon as the plugin is active, a member registering, logging in, publishing, or commenting earns points.

Point values, daily caps, and cooldowns are configured in Settings. Adjust any default above or disable an action you do not want to reward.

Requirements

  • None. This integration works out of the box with WordPress alone.

Jetonomy Integration

WB Gamification connects to Jetonomy automatically when Jetonomy is active. Two things happen: Jetonomy activity awards WB Gamification points, and - to avoid showing two identical leaderboards - WB Gamification defers its own leaderboard display to Jetonomy's reputation ranking.

Jetonomy Events Award WB Gam Points

WBGam\Integrations\Jetonomy\JetonomyIntegration mirrors every Jetonomy reputation delta 1:1 into the WB Gamification points ledger via the jetonomy_reputation_changed action. Positive deltas award points; negative deltas debit (only when the member has enough balance). Sandboxed users are skipped in both directions, and Jetonomy's own reputation row is never touched - only the gamification ledger mirrors it.

Forum and content reputation events (post / reply / vote / idea / flag) are recorded under prefixed action IDs (jetonomy_*) so forum-sourced points stay distinct from native WB Gam awards in reports.

In addition, the auto-discovered manifests register discrete Jetonomy actions:

Manifest Example actions
integrations/jetonomy.php jetonomy_space_joined, jetonomy_join_request_approved, jetonomy_trust_level_up, jetonomy_membership_activated
integrations/jetonomy-pro.php jetonomy_pro_poll_created, jetonomy_pro_poll_voted, jetonomy_pro_message_sent, jetonomy_pro_badge_earned, jetonomy_pro_reaction_added

jetonomy_pro_badge_earned awards WB Gam points when a member earns a Jetonomy custom badge, hooking jetonomy_pro_badge_earned.

Leaderboard Deferral

Because WB Gamification mirrors Jetonomy reputation 1:1 into points, the two leaderboards would rank the same members in the same order - a genuine duplicate. Rather than show both, WBGam\Integrations\Jetonomy\DisplayDefer suppresses WB Gam's leaderboard display when Jetonomy is active and lets Jetonomy's reputation leaderboard be the single source of truth.

When deferral is on, WB Gamification suppresses:

  • The leaderboard block and the [wb_gam_leaderboard] shortcode
  • The top-members block and the [wb_gam_top_members] shortcode
  • The Hub block's leaderboard card

Suppression is done by blanking the rendered output (render_block and do_shortcode_tag filters), so any place those blocks or shortcodes appear - including the member achievement surfaces - renders nothing for the leaderboard.

Badges Are Kept

Badges are deliberately not deferred. WB Gamification's badge engine is the broader system (OpenBadges 3.0, expiry, share pages, any-event triggers), and the two badge sets are complementary rather than duplicates: Jetonomy uses forum-native criteria, WB Gam uses site-wide actions. Both badge sets keep rendering.

Overriding the Deferral

Deferral defaults to on when Jetonomy is active (JETONOMY_VERSION defined). Override it with the wb_gam_defer_leaderboard_to_jetonomy filter:

// Force-show WB Gam's own leaderboard even when Jetonomy is active.
add_filter( 'wb_gam_defer_leaderboard_to_jetonomy', '__return_false' );

// Or defer even when Jetonomy is not active (unusual).
add_filter( 'wb_gam_defer_leaderboard_to_jetonomy', '__return_true' );

See the Filters reference for the full signature.

Requirements

  • Jetonomy active (reputation mirroring + leaderboard deferral).
  • Jetonomy Pro active for the jetonomy_pro_* actions, including jetonomy_pro_badge_earned.

BuddyPress

BuddyPress-specific display and integration

BuddyPress Activity Feed Integration

Overview

WB Gamification posts four types of events to the BuddyPress activity stream automatically. These entries create social proof - other members see achievements as they happen and are naturally encouraged to participate.

All four event types are registered under the wb_gamification component and appear in the "Gamification" filter group in the activity stream.

Event Types

Event Activity Type Hook That Triggers It
Badge earned badge_earned wb_gam_badge_awarded
Level reached level_changed wb_gam_level_changed
Kudos given kudos_given wb_gam_kudos_given
Challenge completed challenge_completed wb_gam_challenge_completed

Each activity entry links back to the member's BuddyPress profile URL via bp_core_get_user_domain().

Example Activity Text

  • Badge earned: "Jane Smith earned the Community Voice badge"
  • Level reached: "Jane Smith reached the Contributor level"
  • Kudos given: "Jane Smith gave kudos to Tom Harris: Great answer!"
  • Challenge completed: "Jane Smith completed the 7-Day Streak challenge"

Toggling Individual Event Types

Each stream event type is individually toggled via a WordPress option. The default for all four is enabled (1).

Option Key Default Controls
wb_gam_bp_stream_badge_earned 1 Badge earned posts
wb_gam_bp_stream_level_changed 1 Level-up posts
wb_gam_bp_stream_kudos_given 1 Kudos given posts
wb_gam_bp_stream_challenge_completed 1 Challenge completed posts

Disable a specific event type

// Disable kudos posts in the activity stream.
update_option( 'wb_gam_bp_stream_kudos_given', 0 );

Re-enable via admin (Settings → Gamification → BuddyPress)

You can also toggle these from the admin settings page without writing code.

Quality-Weighted Reactions

ActivityIntegration also hooks into the wb_gam_points_for_action filter to apply a quality bonus. When a member receives a reaction on an activity_update post (rather than a comment or other type), the points awarded for bp_reactions_received are boosted to a minimum of 5 (compared to the default 3).

// This filter runs at priority 10 inside ActivityIntegration.
add_filter( 'wb_gam_points_for_action', function( $points, $action_id, $user_id, $event ) {
    // Only modifies bp_reactions_received on activity_update posts.
    if ( 'bp_reactions_received' === $action_id && 'activity_update' === ( $event->metadata['activity_type'] ?? '' ) ) {
        return max( $points, 5 );
    }
    return $points;
}, 10, 4 );

You can override this behaviour by adding your own filter at a higher priority.

How Posts Appear in the Stream

All posts use bp_activity_add() with hide_sitewide: false, so they appear on the site-wide activity feed as well as the member's profile feed. Posts are never marked as spam.

The item_id field varies per event:

  • badge_earned - always 0
  • level_changed - the new level's DB row ID
  • kudos_given - the wb_gam_kudos row ID (for linking)
  • challenge_completed - the challenge's DB row ID

No Configuration Required

ActivityIntegration::init() runs on bp_loaded and performs a function_exists('buddypress') guard. If BuddyPress is not active, no hooks are registered.

BuddyPress Member Directory Integration

Overview

WB Gamification adds a compact rank badge next to each member's name in the BuddyPress member directory. The badge shows the member's current level name only - no point count or progress bar, keeping the directory listing clean.

What Appears in the Directory

A single <span> with the level name is injected via the bp_directory_members_item action hook:

<span class="wb-gam-directory-rank">Contributor</span>

This appears inside each member list item, adjacent to the member's name and avatar.

Who Sees a Rank Badge

The badge only appears under two conditions:

  1. The member has earned a level (i.e., wb_gam_level_name user meta is set and non-empty).
  2. The member has not opted out of showing their rank (wb_gam_member_prefs.show_rank is not 0).

Members who have never earned any points - and therefore have no level assigned - show no badge at all. "Newcomer" (the default starting level) will appear once the user meta is written, which happens on the first level-up evaluation.

Opt-Out Behaviour

The directory badge respects the same show_rank preference as the profile header. If a member sets show_rank = 0 in wb_gam_member_prefs, their badge is hidden from both the profile header and the directory listing.

A NULL value (no row in the preferences table) defaults to visible.

Styling the Directory Badge

/* Target the rank badge in the member directory */
.wb-gam-directory-rank {
  display: inline-block;
  padding: 2px 8px;
  font-size: 0.75rem;
  background: var(--wb-gam-rank-bg, #f3f4f6);
  color: var(--wb-gam-rank-color, #374151);
  border-radius: 9999px;
  margin-left: 6px;
  vertical-align: middle;
}

Add this to your child theme's stylesheet or via Appearance → Customize → Additional CSS.

No Configuration Required

DirectoryIntegration::init() is called on bp_loaded. It guards with function_exists('buddypress') before registering any hooks. Deactivating BuddyPress removes the integration silently.

BuddyPress Profile Display

Overview

WB Gamification automatically adds a rank badge to every member's BuddyPress profile header. No shortcode or configuration is required. As soon as both plugins are active, every profile shows the member's current level name, total point count, and a progress bar toward the next level.

What Members See

The rank block appears inside the bp_before_member_header_meta hook, directly below the member's avatar and name.

Element Source
Level name wb_gam_level_name user meta, defaults to "Newcomer"
Point count Summed from wb_gam_points ledger
Progress bar (current_points - current_level_min) / (next_level_min - current_level_min) × 100

The progress bar is only rendered when a next level exists in the wb_gam_levels table.

Default Level Names

Fresh installs seed five levels:

Level Minimum Points
Newcomer 0
Member 100
Contributor 500
Regular 1,500
Champion 5,000

You can rename or add levels at WP Admin → Gamification → Levels.

HTML Structure

<div class="wb-gam-profile-rank">
  <span class="wb-gam-rank-badge">Contributor</span>
  <span class="wb-gam-points-count">650 pts</span>
  <div class="wb-gam-progress-bar" title="30%">
    <div class="wb-gam-progress-fill" style="--wb-gam-fill:30%"></div>
  </div>
</div>

The fill width is driven by a CSS custom property --wb-gam-fill. Override it in your theme to change the bar colour or animation.

Styling with CSS Variables

/* Override in your child theme or Custom CSS */
.wb-gam-profile-rank {
  --wb-gam-bar-color: #6366f1;
  --wb-gam-bar-bg: #e5e7eb;
  --wb-gam-bar-height: 6px;
}

Opt-Out: Hiding the Rank

Members can hide their rank badge. The preference is stored in wb_gam_member_prefs.show_rank (default 1 = visible).

When show_rank = 0, the render_rank() method returns early and nothing is output. The NULL state (no row in the table) also defaults to visible.

Setting the preference via SQL (admin use only)

-- Hide rank for user 42
INSERT INTO wp_wb_gam_member_prefs (user_id, show_rank)
VALUES (42, 0)
ON DUPLICATE KEY UPDATE show_rank = 0;

Setting the preference via REST API

POST /wp-json/wb-gamification/v1/members/42/prefs
Authorization: Bearer <cookie nonce>
Content-Type: application/json

{ "show_rank": false }

No Configuration Needed

ProfileIntegration::init() is called on the bp_loaded action. It performs a function_exists('buddypress') guard before registering any hooks. If BuddyPress is deactivated, the block silently does nothing.

See Also

  • BuddyPress Achievements Tab - the dedicated profile tab (Overview / Badges / Points / Streak) added by the same integration, separate from this header rank display.

BuddyPress Achievements Tab

Overview

When BuddyPress is active, WB Gamification adds an Achievements tab to every member profile. No shortcode or configuration is required - as soon as both plugins are active, the tab appears in the profile navigation and renders the member's gamification data through the same blocks used everywhere else in the plugin.

The tab is added by WBGam\BuddyPress\ProfileIntegration, which boots on the bp_loaded action and guards on function_exists('buddypress') before registering anything.

What Members See

The tab is labelled Achievements (slug achievements) and sits at navigation position 35. It has four sub-tabs:

Sub-tab Slug Shows Source block(s)
Overview overview Points + level progress and the current streak (a concise personal summary) member-points, streak
Badges badges Earned and locked badges badge-showcase
Points points The member's points history points-history
Streak streak Streak heatmap and milestones streak

overview is the default sub-tab. All content is scoped to the displayed member (bp_displayed_user_id()), so visiting another member's profile shows that member's achievements.

How It Renders

Each sub-tab renders existing gamification blocks through their shortcodes, scoped to the displayed member with user_id. There is no profile-only template to keep in sync - the profile reuses the single source of block markup.

The shared plumbing (asset enqueue, the mapped "View full dashboard" link, and the surface wrapper) lives in WBGam\Engine\MemberSurface. The same renderer also powers the WooCommerce My Account endpoint and the opt-in LearnDash profile link, so the three surfaces stay consistent. See Member Achievement Surfaces.

When a member views their own profile and a Hub page is mapped (option wb_gam_hub_page_id), the surface appends a "View full dashboard" link to the mapped Hub page. The link never appears on another member's profile, and never when no Hub page is mapped.

Customizing the Surface

The wrapped surface markup passes through the wb_gam_member_surface_html filter before output, so a theme or add-on can wrap or augment the tab without duplicating the renderer:

add_filter(
	'wb_gam_member_surface_html',
	static function ( string $html, int $user_id ): string {
		return '<h2>' . esc_html__( 'Achievements', 'my-textdomain' ) . '</h2>' . $html;
	},
	10,
	2
);

See the Filters reference for the full signature.

Profile Header Rank

The Achievements tab is separate from the rank badge that WB Gamification adds to the profile header (level name, point count, progress bar). That header display is documented in BuddyPress Profile Display and is controlled by the member's show_rank preference.

No Configuration Needed

ProfileIntegration::init() runs on bp_loaded. If BuddyPress is deactivated, the tab silently does nothing.

Developer Guide

Hooks, REST API, WP-CLI, and extension cookbook

Getting Started for Developers

WB Gamification is built as a platform - not just a plugin. Choose your path based on what you're building.

Three Paths

Path 1: WordPress Plugin Developer

"I want to add gamification to my plugin"

The fastest way is a manifest file - a single PHP file that tells WB Gamification what actions your plugin provides.

  1. Create wb-gamification.php in your plugin's root directory
  2. Return an array of action definitions
  3. WB Gamification auto-discovers it on activation

See the full manifest tutorial Download the manifest template

For advanced use cases, use the PHP API directly:

// Register a custom action programmatically.
wb_gam_register_action( array(
    'id'             => 'my_plugin_action',
    'label'          => 'Custom Action',
    'hook'           => 'my_plugin_did_something',
    'user_callback'  => fn() => get_current_user_id(),
    'default_points' => 25,
    'category'       => 'my-plugin',
) );

// Check if a user has earned a badge.
if ( wb_gam_has_badge( $user_id, 'first-post' ) ) {
    // Show special content.
}

// Award points manually.
wb_gam_award_points( $user_id, 50, 'custom_reward' );

See all PHP API functions

Path 2: Theme Developer

"I want to display gamification data in my theme"

Use Gutenberg blocks or shortcodes - no PHP knowledge needed.

Blocks (recommended): Add any of the 17 blocks in the editor: Leaderboard, Hub, Member Points, Points History, Badge Showcase, Earning Guide, Daily Bonus, Streak, Challenges, Community Challenges, Cohort Rank, Top Members, Kudos Feed, Submit Achievement, Level Progress, Redemption Store, Year Recap.

Shortcodes (classic themes):

[wb_gam_hub]
[wb_gam_leaderboard period="week" limit="10"]
[wb_gam_member_points]
[wb_gam_badge_showcase show_locked="1"]
[wb_gam_level_progress]
[wb_gam_challenges]
[wb_gam_streak]
[wb_gam_earning_guide]

PHP template tags:

// In your theme templates:
$points = wb_gam_get_user_points( get_current_user_id() );
$level  = wb_gam_get_user_level( get_current_user_id() );
$badges = wb_gam_get_user_badges( get_current_user_id() );
$streak = wb_gam_get_user_streak( get_current_user_id() );

See all blocks and shortcodes

Path 3: App / Headless Developer

"I want to build a mobile app or headless frontend"

Use the REST API with API key authentication.

Setup:

  1. Generate an API key in WP Admin > Gamification > API Keys
  2. Use the key in the X-WB-Gam-Key header

JavaScript SDK (recommended):

import { WBGamification } from '@wbcom/wb-gamification';

const client = new WBGamification({
  baseUrl: 'https://your-site.com',
  apiKey: 'your-api-key',
});

const leaders = await client.getLeaderboard('week', 10);
const member  = await client.getMember(42);
await client.submitEvent(42, 'completed_lesson', { lesson_id: 5 });

Direct REST API:

# Get leaderboard
curl -H "X-WB-Gam-Key: YOUR_KEY" \
  https://your-site.com/wp-json/wb-gamification/v1/leaderboard?period=week

# Award points
curl -X POST -H "X-WB-Gam-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"user_id":42,"action_id":"manual","points":50}' \
  https://your-site.com/wp-json/wb-gamification/v1/events

OpenAPI spec: GET /wp-json/wb-gamification/v1/openapi.json - import into Postman, Swagger UI, or any OpenAPI tool.

Webhooks for real-time event notifications to your backend: See webhook documentation

See full REST API reference


Architecture Overview

Trigger Sources
  |- WordPress hooks (publish_post, wp_login, etc.)
  |- BuddyPress hooks (bp_activity_posted, etc.)
  |- REST API (POST /events)
  |- WP-CLI (wp wb-gamification points award)
  |- Manifest files (auto-discovered)
       |
Event Normalization -> WB_Gam_Event
       |
Rule Evaluation Engine
  |- PointsEngine  -> append-only points ledger
  |- BadgeEngine   -> rule-based badge awards
  |- LevelEngine   -> threshold-based progression
  |- ChallengeEngine -> time-bound goals
  |- StreakEngine   -> daily/weekly tracking
  |- KudosEngine   -> peer recognition
       |
Output Consumers
  |- Gutenberg blocks (17 blocks)
  |- BuddyPress (profile, directory, activity)
  |- REST API (18 controllers)
  |- Webhooks (Zapier, Make, n8n)
  |- Toast notifications
  |- Your custom code (hooks + PHP API)

Extension Points

Layer How to extend Documentation
Add actions Manifest file or wb_gam_register_action() Manifest tutorial
Modify points wb_gam_points_for_action filter Hooks reference
Custom badge rules wb_gam_should_award_badge filter Hooks reference
React to events wb_gam_after_points_award action Hooks reference
React to badges wb_gam_after_badge_award action Hooks reference
React to levels wb_gam_level_changed action Hooks reference
Custom display Shortcodes, blocks, or PHP API Blocks & shortcodes
External systems Webhooks or REST API Webhooks, REST API

Architecture

Design Principle

WB Gamification is event-sourced. The only write path is:

Event in → Rules evaluate → Effects out

All gamification state (points, badges, levels, streaks) is derived from the immutable wb_gam_events table. BuddyPress display, WooCommerce triggers, and the REST API are consumers of this pipeline - they never write state directly.

Boot Sequence

All hooks register on plugins_loaded. The priority order ensures each layer is ready before the next depends on it.

Priority Component What It Does
0 WB_Gamification::instance() Registers all hooks, constants, autoloader
1 DbUpgrader::init() Runs schema migrations if wb_gam_db_version is behind
5 ManifestLoader::scan() Auto-discovers wb-gamification.php manifests in every plugin directory
6 Registry::init() Registers discovered actions and badge triggers; fires wb_gam_register
8 Engine::init(), WPHooks, BPHooks Boots the event pipeline; registers WordPress and BuddyPress trigger hooks
10 BadgeEngine, ChallengeEngine, StreakEngine, etc. Secondary engines subscribe to wb_gam_points_awarded
12 NotificationBridge Subscribes to badge/level/streak hooks to dispatch BP notifications
15 Privacy Registers GDPR erasure and export handlers
20 SiteFirstBadgeEngine Subscribes last so site-first-action checks see all other state
bp_loaded ProfileIntegration, DirectoryIntegration, ActivityIntegration BuddyPress surface integrations, after BP is fully booted

PSR-4 Namespace Map

Namespace Directory Purpose
WBGam\Engine\ src/Engine/ Core engines, event bus, DB, cron
WBGam\API\ src/API/ REST controllers (16 controllers)
WBGam\Admin\ src/Admin/ Admin pages, setup wizard, analytics
WBGam\BuddyPress\ src/BuddyPress/ BP profile, directory, activity integrations
WBGam\Integrations\ src/Integrations/ WordPress, WooCommerce, and other plugin hooks
WBGam\Abilities\ src/Abilities/ WordPress Abilities API capability registrations
WBGam\Blocks\ src/Blocks/ Gutenberg block render callbacks
WBGam\Extensions\ src/Extensions/ Public helper functions (functions.php)
WBGam\CLI\ src/CLI/ WP-CLI command classes

Engine Pipeline

Every gamification event flows through Engine::process() in this order:

1. Validate (user_id > 0, action_id not empty)
2. Check action enabled  (get_option wb_gam_enabled_{action_id})
3. Rate-limit gate       (daily_cap, cooldown - PointsEngine::passes_rate_limits())
4. Enrich metadata       (apply_filters: wb_gam_event_metadata)
5. Before-evaluate gate  (apply_filters: wb_gam_before_evaluate - return false to abort)
6. Persist event         (INSERT wb_gam_events - UUID PK, immutable)
7. Calculate points      (admin option → wb_gam_points_for_action filter → RuleEngine multipliers)
8. Write points ledger   (INSERT wb_gam_points with event_id FK)
9. Fire hooks            (do_action: wb_gam_points_awarded)
10. Side effects         (LevelEngine::maybe_level_up, StreakEngine::record_activity, WebhookDispatcher::dispatch)

Steps 1-5 are synchronous and write nothing. Steps 6-10 are the only database writes. This means apply_filters('wb_gam_before_evaluate', true, $event) can abort processing without leaving any trace in the database.

Async Processing

High-volume actions can use Engine::process_async() instead of Engine::process(). This performs the rate-limit check synchronously (fast, no writes) then queues the full pipeline via Action Scheduler under the wb-gamification group.

If Action Scheduler is unavailable (unit tests, early boot), process_async() falls back to synchronous processing automatically.

Manifest Auto-Discovery

At priority 5, ManifestLoader::scan() runs two passes:

  1. First-party: loads every *.php file in wb-gamification/integrations/
  2. Third-party: scans WP_PLUGIN_DIR/*/wb-gamification.php - any installed plugin can declare triggers by dropping this file

Manifest files return a plain PHP array. They are read-only configuration - no dependency on WB Gamification being loaded when the file is included. If the gamification plugin is not installed, the file is simply ignored.

Constants

WB_GAM_VERSION   // '1.0.0'
WB_GAM_FILE      // absolute path to wb-gamification.php
WB_GAM_PATH      // plugin dir path (trailing slash)
WB_GAM_URL       // plugin dir URL (trailing slash)
WB_GAM_BASENAME  // 'wb-gamification/wb-gamification.php'

Database Version Tracking

The current schema version is stored in get_option('wb_gam_db_version'). On each boot at priority 1, DbUpgrader::init() compares this to WB_GAM_VERSION. If behind, it runs the appropriate upgrade_to_X_Y_Z() methods in sequence. Each version gets its own upgrade method - no compound migrations.

Match the admin UI to your brand

Every color in the admin screens reads from a single palette of CSS custom properties defined in assets/css/admin/tokens.css (the --wbgam-* tokens). No screen hard-codes a hex value, so you can re-theme the whole admin UI by overriding a few tokens - no need to touch component styles.

Drop this in a small admin stylesheet (or a snippet plugin) to point the accent color at your brand:

/* Re-brand the WB Gamification admin */
:root {
    --wbgam-primary:        #8b5cf6;  /* buttons, links, active states */
    --wbgam-primary-hover:  #7c3aed;
    --wbgam-primary-light:  #f5f3ff;  /* subtle accent backgrounds */
}

The same pattern works for the success / warning / danger families and the surface, border, and text tokens. Because every rule resolves through these variables, one override cascades everywhere consistently.

Build Your First Integration

Add gamification to your WordPress plugin in 5 minutes. No PHP dependency on WB Gamification is required - your manifest file is silently ignored when the plugin is not installed.


Step 1: Create the manifest file

Create a file named wb-gamification.php in your plugin's root directory:

your-plugin/
├── your-plugin.php        (main plugin file)
└── wb-gamification.php    (gamification manifest)

Paste the following into wb-gamification.php and customise it:

<?php
/**
 * WB Gamification manifest for My Reviews Plugin.
 */

defined( 'ABSPATH' ) || exit;

return array(
    'plugin'   => 'my-reviews-plugin',
    'version'  => '1.0.0',
    'triggers' => array(

        // Award 10 points every time a member submits a review.
        array(
            'id'             => 'my_reviews_submitted',
            'label'          => 'Submitted a Review',
            'description'    => 'Awarded each time a member publishes a product review.',
            'hook'           => 'my_reviews_after_submit',
            'user_callback'  => function ( $review_id, $user_id ) {
                return (int) $user_id;
            },
            'default_points' => 10,
            'category'       => 'reviews',
            'icon'           => 'dashicons-star-half',
            'repeatable'     => true,
            'cooldown'       => 3600,   // One review per hour max.
            'daily_cap'      => 3,      // Up to 3 reviews per day.
        ),

        // One-time 50-point bonus for the very first review.
        array(
            'id'             => 'my_reviews_first_review',
            'label'          => 'First Review Bonus',
            'description'    => 'One-time bonus when a member submits their first review.',
            'hook'           => 'my_reviews_after_submit',
            'user_callback'  => function ( $review_id, $user_id ) {
                return (int) $user_id;
            },
            'default_points' => 50,
            'category'       => 'reviews',
            'repeatable'     => false,
        ),
    ),
);

Required fields

Every trigger must include these three keys or it will be skipped:

Key Type Description
id string Unique action identifier. Use a plugin_action naming convention
hook string The WordPress action hook that fires when the event occurs
default_points int Default points awarded. Admins can override this in the settings UI

See the Manifest Files reference for the full list of optional fields (user_callback, metadata_callback, cooldown, daily_cap, async, etc.).


Step 2: Activate both plugins

  1. Install and activate WB Gamification.
  2. Install and activate your plugin.

WB Gamification scans every active plugin directory for a wb-gamification.php file at plugins_loaded priority 5. No registration code is needed.


Step 3: Verify

  1. Go to WP Admin > Gamification > Settings > Points tab.
  2. Your custom actions should appear in the actions list with their default point values.
  3. Trigger the action (e.g. submit a review) and confirm points are awarded.

You can also verify via WP-CLI:

wp wb-gamification actions list

Advanced: Programmatic registration

If your trigger logic is too complex for a static manifest, register actions programmatically from your plugin's functions.php or a class constructor:

add_action( 'wb_gam_register', function () {
    if ( ! function_exists( 'wb_gam_register_action' ) ) {
        return;
    }

    wb_gam_register_action( array(
        'id'             => 'my_reviews_submitted',
        'label'          => 'Submitted a Review',
        'hook'           => 'my_reviews_after_submit',
        'user_callback'  => function ( $review_id, $user_id ) {
            return (int) $user_id;
        },
        'default_points' => 10,
        'category'       => 'reviews',
        'repeatable'     => true,
        'cooldown'       => 3600,
        'daily_cap'      => 3,
    ) );
} );

The wb_gam_register action fires at plugins_loaded priority 6, after all manifests have been loaded.


Available developer hooks

wb_gam_manifest_paths (filter)

Add custom directories for the manifest scanner to check. Useful if you store manifests in a theme or mu-plugin:

add_filter( 'wb_gam_manifest_paths', function ( array $paths ): array {
    $paths[] = get_stylesheet_directory() . '/gamification/';
    return $paths;
} );

wb_gam_manifests_loaded (action)

Fires after all manifest files have been loaded and validated. Receives the full array of discovered action definitions:

add_action( 'wb_gam_manifests_loaded', function ( array $actions ): void {
    // Log how many actions were discovered.
    error_log( 'WB Gamification loaded ' . count( $actions ) . ' manifest actions.' );
} );

Validation and debugging

When WP_DEBUG is enabled, the ManifestLoader logs warnings for:

  • Manifest files that do not return an array - check that your file ends with return array( ... );
  • Triggers missing required keys (id, hook, default_points) - the trigger is skipped and a message is logged with the file path and missing key name

Check your debug log at wp-content/debug.log to diagnose manifest issues.


Next steps

Manifest Files

How Manifests Work

Any WordPress plugin can award gamification points without depending on WB Gamification at runtime. Create a file named wb-gamification.php in your plugin's root directory. The file returns a plain PHP array. WB Gamification discovers and loads it automatically at plugins_loaded priority 5 - before any hooks fire.

If WB Gamification is not installed, your manifest file is simply never loaded. No dependency errors, no fatal calls.

File Location

your-plugin/
├── your-plugin.php        (main plugin file)
└── wb-gamification.php    (gamification manifest)

Manifest Structure

<?php
/**
 * WB Gamification manifest for My Plugin.
 *
 * This file is auto-discovered by WB Gamification at plugins_loaded priority 5.
 * It is safe to ship in the free version - WB Gamification is an optional dependency.
 */
return [
    'plugin'   => 'my-plugin',          // Used in Registry collision reports.
    'version'  => '1.0.0',              // Your plugin version (informational).
    'triggers' => [
        // Each array in 'triggers' is a gamification action definition.
        [
            'id'                  => 'my_plugin_action',
            'label'               => 'Did Something',
            'description'         => 'Awarded when a member does something in My Plugin.',
            'hook'                => 'my_plugin_action_hook',
            'user_callback'       => function( $user_id, $data ) { return $user_id; },
            'metadata_callback'   => function( $user_id, $data ) { return [ 'item_id' => $data->id ]; },
            'default_points'      => 10,
            'category'            => 'my_plugin',
            'icon'                => 'dashicons-star-filled',
            'repeatable'          => true,
            'cooldown'            => 3600,
            'daily_cap'           => 5,
            'async'               => false,
            'standalone_only'     => false,
            'requires_buddypress' => false,
        ],
    ],
];

Trigger Field Reference

Field Type Required Description
id string Yes Unique action identifier. Use plugin_name_action format to avoid collisions
label string Yes Human-readable label shown in the admin actions list
description string No Longer description shown in tooltips and the setup wizard
hook string Yes WordPress action hook name to listen on
user_callback callable Yes Receives the hook arguments. Must return the WordPress user ID to award points to
metadata_callback callable No Receives the hook arguments. Returns an array merged into event metadata (available in wb_gam_points_for_action filter)
default_points int Yes Default points awarded. Admins can override this in the settings UI
category string No Category slug for grouping in the admin UI (e.g. buddypress, woocommerce)
icon string No Dashicon class (e.g. dashicons-heart) for the admin UI
repeatable bool No Whether the action can be awarded more than once. Default true
cooldown int No Minimum seconds between repeated awards for the same user. 0 = no cooldown
daily_cap int No Maximum awards per calendar day per user. 0 = unlimited
async bool No Route through Action Scheduler instead of processing synchronously. Use for high-volume events
standalone_only bool No Set true to skip this trigger when BuddyPress is active (because BP's own hooks cover the same event better)
requires_buddypress bool No Set true to only register this trigger when BuddyPress is active

Complete Working Example

This example awards points when a member submits a contact form in a fictional forms plugin, with a daily cap and metadata enrichment:

<?php
return [
    'plugin'   => 'my-forms-plugin',
    'version'  => '2.1.0',
    'triggers' => [
        // Award points for submitting any form.
        [
            'id'              => 'my_forms_submission',
            'label'           => 'Submitted a Form',
            'description'     => 'Awarded each time a member submits a form.',
            'hook'            => 'my_forms_submission_complete',
            'user_callback'   => function( $form_id, $user_id ) {
                return (int) $user_id;
            },
            'metadata_callback' => function( $form_id, $user_id ) {
                return [ 'form_id' => (int) $form_id ];
            },
            'default_points'  => 5,
            'category'        => 'forms',
            'icon'            => 'dashicons-feedback',
            'repeatable'      => true,
            'cooldown'        => 0,
            'daily_cap'       => 3,
            'async'           => false,
        ],

        // Award a one-time bonus for the first form submission.
        [
            'id'              => 'my_forms_first_submission',
            'label'           => 'First Form Submission',
            'description'     => 'One-time bonus for a member\'s very first form submission.',
            'hook'            => 'my_forms_submission_complete',
            'user_callback'   => function( $form_id, $user_id ) {
                return (int) $user_id;
            },
            'default_points'  => 25,
            'category'        => 'forms',
            'repeatable'      => false,   // Only once per member.
            'cooldown'        => 0,
            'daily_cap'       => 0,
            'async'           => false,
        ],

        // BP-only trigger: award points for form submissions inside a group.
        [
            'id'                  => 'my_forms_group_submission',
            'label'               => 'Submitted a Group Form',
            'description'         => 'Awarded when a member submits a form inside a BuddyPress group.',
            'hook'                => 'my_forms_group_submission_complete',
            'user_callback'       => function( $form_id, $user_id, $group_id ) {
                return (int) $user_id;
            },
            'default_points'      => 8,
            'category'            => 'forms',
            'repeatable'          => true,
            'cooldown'            => 3600,
            'daily_cap'           => 5,
            'requires_buddypress' => true,  // Only registers when BP is active.
        ],
    ],
];

Conditional Triggers: standalone_only and requires_buddypress

These two flags let you ship one manifest that works correctly in both BuddyPress and non-BuddyPress environments.

Scenario: Your plugin fires my_plugin_post_published. When WordPress is running standalone, you want to award points for it. But when BuddyPress is active, the BuddyPress bp_publish_post integration already covers this event more richly - so you want to skip your version.

[
    'id'              => 'my_plugin_post_published_standalone',
    'hook'            => 'my_plugin_post_published',
    'standalone_only' => true,   // Skip when BuddyPress is active.
    // ...
],
[
    'id'                  => 'my_plugin_post_published_bp',
    'hook'                => 'my_plugin_post_published',
    'requires_buddypress' => true,   // Only register when BuddyPress is active.
    // ...
],

Both flags are stripped from the trigger before it is passed to Registry::register_action().

Registering Actions Programmatically

You can also call the PHP helper directly instead of using a manifest file. This is useful when your trigger logic is complex enough to warrant a full class:

add_action( 'wb_gam_register', function() {
    wb_gam_register_action( [
        'id'             => 'my_plugin_action',
        'label'          => 'My Action',
        'hook'           => 'my_plugin_hook',
        'user_callback'  => fn( $user_id ) => $user_id,
        'default_points' => 10,
        'category'       => 'my_plugin',
        'repeatable'     => true,
        'cooldown'       => 0,
        'daily_cap'      => 0,
    ] );
} );

This fires after Registry::init() at plugins_loaded priority 6.

Validation

The ManifestLoader validates every manifest and trigger at load time:

  1. Manifest must return an array. If the file does not return array( ... ), it is skipped. When WP_DEBUG is enabled, a message is logged to debug.log.
  2. Each trigger must include id, hook, and default_points. Missing any of these causes the trigger to be skipped with a debug log entry identifying the file and missing key.

This means you can ship a manifest confidently - malformed entries are silently ignored in production and loudly reported during development.

Developer Hooks

wb_gam_manifest_paths (filter)

Add custom directories for the manifest scanner. The ManifestLoader scans every directory in this array for *.php files:

add_filter( 'wb_gam_manifest_paths', function ( array $paths ): array {
    $paths[] = get_stylesheet_directory() . '/gamification/';
    return $paths;
} );

wb_gam_manifests_loaded (action)

Fires after all manifests have been loaded and validated. Receives the complete array of action definitions:

add_action( 'wb_gam_manifests_loaded', function ( array $actions ): void {
    error_log( 'WB Gamification loaded ' . count( $actions ) . ' manifest actions.' );
} );

Quick Start

New to manifest files? Follow the Build Your First Integration tutorial to create a working manifest in 5 minutes.

Helper Functions

All functions are defined in src/Extensions/functions.php and available globally once WB Gamification is active. No use statement or class prefix is needed.


Action Registration

wb_gam_register_action( array $args ): void

Register a custom action that awards points when a WordPress hook fires. Routes directly to Registry::register_action().

Parameter Type Required Description
$args['id'] string Yes Unique action identifier
$args['label'] string Yes Human-readable label
$args['description'] string No Optional description
$args['hook'] string Yes WordPress hook name
$args['user_callback'] callable Yes Returns the user ID from hook arguments
$args['default_points'] int Yes Default points awarded
$args['category'] string No Category slug
$args['icon'] string No Dashicon class
$args['repeatable'] bool No Allow multiple awards. Default true
$args['cooldown'] int No Seconds between awards. 0 = none
$args['daily_cap'] int No Max awards per day. 0 = unlimited
$args['weekly_cap'] int No Max awards per week. 0 = unlimited
add_action( 'wb_gam_register', function() {
    wb_gam_register_action( [
        'id'             => 'my_plugin_signup',
        'label'          => 'Signed up via My Plugin',
        'hook'           => 'my_plugin_user_signup',
        'user_callback'  => fn( $user_id ) => $user_id,
        'default_points' => 50,
        'category'       => 'my_plugin',
        'repeatable'     => false,
    ] );
} );

wb_gam_register_badge_trigger( array $args ): void

Register a custom badge trigger condition. Routes to Registry::register_badge_trigger().

Parameter Type Required Description
$args['id'] string Yes Unique trigger identifier
$args['label'] string Yes Human-readable label
$args['hook'] string Yes WordPress hook to listen on
$args['condition'] callable Yes Returns true when the badge should be awarded

wb_gam_register_challenge_type( array $args ): void

Register a custom challenge type. Routes to Registry::register_challenge_type().

Parameter Type Required Description
$args['id'] string Yes Unique challenge type identifier
$args['label'] string Yes Human-readable label
$args['action_id'] string Yes Action ID this challenge tracks
$args['countable'] bool No Whether progress is tracked by count

Points Functions

wb_gam_get_user_points( int $user_id ): int

Get the total accumulated points for a user. Reads from the object cache first; falls back to a SUM query on wb_gam_points.

$points = wb_gam_get_user_points( get_current_user_id() );
echo "You have {$points} points.";

wb_gam_award_points( int $user_id, int $points, string $action_id = 'manual', int $object_id = 0 ): bool

Award points to a user manually. Bypasses cooldown and cap checks. Routes through Engine::process() so the event is persisted and all hooks fire normally.

Returns false if $points <= 0 or $user_id <= 0.

Parameter Type Default Description
$user_id int - WordPress user ID
$points int - Points to award (must be > 0)
$action_id string 'manual' Action ID logged against the points row
$object_id int 0 Optional related object (e.g. post ID)
// Award 100 bonus points.
$awarded = wb_gam_award_points( $user_id, 100, 'promo_bonus' );

if ( $awarded ) {
    // Points were written and hooks fired.
}

wb_gam_get_user_action_count( int $user_id, string $action_id ): int

Get how many times a specific action has been awarded to a user.

$post_count = wb_gam_get_user_action_count( $user_id, 'publish_post' );
if ( $post_count >= 10 ) {
    // User is a prolific writer.
}

Badge Functions

wb_gam_has_badge( int $user_id, string $badge_id ): bool

Check whether a user currently holds a specific badge. Respects expiry - expired badges return false.

if ( wb_gam_has_badge( $user_id, 'top_contributor' ) ) {
    // Show a special UI element.
}

wb_gam_get_user_badges( int $user_id ): array

Get all badges currently held by a user as an array of badge data rows. Expired badges are excluded.

$badges = wb_gam_get_user_badges( $user_id );
foreach ( $badges as $badge ) {
    echo $badge['name'] . ' - earned ' . $badge['earned_at'];
}

Level Functions

wb_gam_get_user_level( int $user_id ): ?array

Get the current level for a user. Returns null if no level threshold has been met.

Return shape: array{ id: int, name: string, min_points: int } or null

$level = wb_gam_get_user_level( $user_id );
if ( $level ) {
    echo "Level: " . $level['name'];
}

Streak Functions

wb_gam_get_user_streak( int $user_id ): array

Get a user's current streak data.

Return shape: array{ current_streak: int, longest_streak: int, last_active: string }

$streak = wb_gam_get_user_streak( $user_id );
echo "Current streak: {$streak['current_streak']} days";
echo "Best streak: {$streak['longest_streak']} days";

Leaderboard Functions

wb_gam_get_leaderboard( string $period = 'all', int $limit = 10 ): array

Get the leaderboard for a given period. Reads from wb_gam_leaderboard_cache for performance.

Parameter Type Default Description
$period string 'all' 'all', 'week', 'month', 'day'
$limit int 10 Number of entries to return
$top_10 = wb_gam_get_leaderboard( 'week', 10 );
foreach ( $top_10 as $row ) {
    printf( "#%d: %s - %d pts\n", $row['rank'], $row['display_name'], $row['points'] );
}

Feature Flags

wb_gam_is_feature_enabled( string $feature ): bool

Check whether a feature flag is currently enabled. Reads from WBGam\Engine\FeatureFlags.

if ( wb_gam_is_feature_enabled( 'cohort_leagues' ) ) {
    // Show cohort league UI.
}

Common feature flags: cohort_leagues, weekly_email, cosmetics, redemption_store, site_first_badges.

Extending Blocks

WB Gamification ships 12 server-rendered blocks. Each one fires a uniform set of WordPress action hooks that let you inject UI before or after the block's HTML - without forking it.

The hooks

Three hooks per block render:

do_action(    'wb_gam_block_before_render', $slug, $attributes, $context );
do_action(    'wb_gam_block_after_render',  $slug, $attributes, $context );
apply_filters( 'wb_gam_block_data',         $data, $slug, $attributes );
Hook Type Fires when
wb_gam_block_before_render action Immediately before the block emits any HTML
wb_gam_block_after_render action Immediately after the block finishes its HTML
wb_gam_block_data filter When a block invokes it to allow data transforms

$slug is the block slug without the wb-gamification/ namespace prefix.

Block slugs

Slug Block List-style?
badge-showcase Member's earned badges Yes
challenges Active challenges with progress bars Yes
earning-guide "How to earn points" reference Yes
hub Layout-owning member hub page (full-width) No
kudos-feed Recent peer kudos Yes
leaderboard Ranked member list Yes
level-progress Current level + bar to next No
member-points Single points total No
points-history Recent point transactions Yes
streak Current + longest streak (+ heatmap) No
top-members Top-N member card Yes
year-recap Year-in-review No

Hook signatures

wb_gam_block_before_render (action, 3 args)

do_action( 'wb_gam_block_before_render', string $slug, array $attributes, array $context );
  • $slug - block slug (e.g. 'leaderboard')
  • $attributes - resolved block attributes from the editor / shortcode (['period' => 'all_time', 'limit' => 10, ...])
  • $context - per-block runtime state. Typically includes user_id and any block-specific keys the block has already computed. Listeners receive this so they don't have to re-derive state.

Listeners can echo HTML (it appears before the block's wrapper <div>) or buffer/manipulate output via ob_start().

wb_gam_block_after_render (action, 3 args)

Same signature as before_render. Fires after the closing wrapper. Listeners echo HTML to append below the block.

wb_gam_block_data (filter, 3 args)

apply_filters( 'wb_gam_block_data', mixed $data, string $slug, array $attributes );
  • $data - block-specific payload (rows, badges, history items, etc.)
  • $slug - block slug
  • $attributes - block attributes

Returns the filtered data. Note: not every block fires this filter today - see the block's render.php to confirm before relying on it. The action hooks fire for all 17 blocks unconditionally.

When hooks DON'T fire

Empty-state render paths intentionally skip the hooks:

  • User not logged in (where the block requires login)
  • No data to show (e.g. no badges earned, no challenges active)
  • Block is hidden by an admin gate

If you need to know about those states, listen to the underlying engine event - wb_gam_streak_broken, wb_gam_points_awarded, etc. - rather than the block hooks.

Common patterns

Append a CTA below a block

add_action( 'wb_gam_block_after_render', function ( $slug, $attributes, $context ) {
    if ( 'leaderboard' !== $slug ) return;
    ?>
    <div class="my-cta">
        <button class="my-share-rank"><?php esc_html_e( 'Share my rank', 'my-plugin' ); ?></button>
    </div>
    <?php
}, 10, 3 );

Conditional banner before a block

add_action( 'wb_gam_block_before_render', function ( $slug, $attributes, $context ) {
    if ( 'streak' !== $slug ) return;
    if ( ! my_plugin_in_campaign_window() ) return;
    echo '<div class="my-banner">🔥 Double points week!</div>';
}, 10, 3 );

Annotate block data via filter

add_filter( 'wb_gam_block_data', function ( $data, $slug, $attributes ) {
    if ( 'leaderboard' !== $slug ) return $data;
    foreach ( (array) $data as &$row ) {
        $row['country'] = get_user_meta( $row['user_id'], 'country', true );
    }
    return $data;
}, 10, 3 );

Track block impressions for analytics

add_action( 'wb_gam_block_after_render', function ( $slug ) {
    $counts = get_transient( 'my_block_renders' ) ?: [];
    $counts[ $slug ] = ( $counts[ $slug ] ?? 0 ) + 1;
    set_transient( 'my_block_renders', $counts, HOUR_IN_SECONDS );
} );

Replace a block's output entirely (advanced)

Capture the block's render output and replace it. This is intentionally awkward - if you find yourself needing it, consider building a competing block reading the same REST endpoint instead.

add_action( 'wb_gam_block_before_render', function ( $slug ) {
    if ( 'leaderboard' === $slug ) ob_start();
}, 10, 3 );

add_action( 'wb_gam_block_after_render', function ( $slug ) {
    if ( 'leaderboard' !== $slug ) return;
    ob_get_clean(); // discard the original
    echo my_render_alternate_leaderboard();
}, 10, 3 );

Performance notes

  • Both action hooks fire once per block render. Keep listeners cheap; they're on the page-render hot path.
  • Don't issue per-row DB queries from a wb_gam_block_data filter - batch your lookups.
  • For analytics, prefer transient-based aggregation over per-render update_option() calls.

What you CAN'T do (today)

  • Replace a block's render with a "skip default" flag. Output capture (above) works but is awkward.
  • Inject a column into a tabular block. The templates aren't column-pluggable. If you need this for a specific block, open an issue with the use case.
  • Modify the wrapper <div> attributes. The wrapper attrs are computed by get_block_wrapper_attributes() and not filterable from outside the block. Use the _after_render action with ob_start() if you must rewrite.

These are tracked as future-roadmap items; see plans/INTEGRATION-GAPS-ROADMAP.md.

Worked example

A complete worked example with 4 patterns lives at examples/10-inject-into-block-render/. Copy it into your plugin and run on a Local install - every pattern is verified.

  • hooks-filters.md - full hook + filter reference (43 actions + 12 filters fired by the engine)
  • rest-api.md - for replacing a block, build a competing block that reads the same REST endpoint
  • manifest-files.md - for tracking new events that flow through the engine + into block renders

Block Attribute Schema (Wbcom Block Quality Standard)

WB Gamification blocks adhere to the canonical Wbcom Block Quality Standard - a uniform attribute schema that every block carries so themes, page builders, and assistive tools can rely on the same controls (responsive spacing, typography, hover colours, visibility) across every Wbcom plugin.

This document is the reference for that schema as it ships in wb-gamification. Consumers building editor plugins, custom blocks that extend ours, or REST integrations should read it before relying on attribute names.

Source of truth: src/shared/utils/attributes.js (JavaScript export) and src/Blocks/CSS.php (PHP consumer). The standard is shared with wbcom-essential; both are derived from ~/.claude/skills/wp-block-development/references/block-quality-standard.md.

Directory casing matters. Block sources live at src/Blocks/<slug>/ (capital B, matches the WBGam\Blocks\ PSR-4 namespace) and compile to build/Blocks/<slug>/. The Registrar scans build/Blocks/ - case-sensitive on Linux production.

Where the schema lives

src/shared/utils/attributes.js   ← exported attribute groups
src/shared/utils/css.js          ← matching CSS generator (editor preview)
src/Blocks/CSS.php               ← PHP CSS generator (frontend render)

Spread the standard groups into a block's attributes to opt in:

import { getStandardAttributes } from '../../shared';

export default {
	apiVersion: 3,
	name: 'wb-gamification/redemption-store',
	attributes: {
		...getStandardAttributes(),
		// Block-specific attributes here.
		columns: { type: 'number', default: 3 },
	},
};

getStandardAttributes() is the union of uniqueIdAttribute, spacingAttributes, shadowAttributes, borderAttributes, and visibilityAttributes. Typography is opt-in (most blocks don't need a built-in font picker) - import typographyAttributes separately when you do.

Attribute groups

uniqueIdAttribute

Key Type Default Purpose
uniqueId string '' Per-instance scope. Generated by useUniqueId() on first render and persisted into post content. CSS rules emitted by CSS::generate() are scoped to .wb-gam-block-{uniqueId}.

Always include this attribute. Without it, two instances of the same block on a single page collide.

spacingAttributes

Per-side padding and margin with three responsive variants. Defaults: padding 24px on all sides; margin 0.

Key Type Default Purpose
padding object { top: 24, right: 24, bottom: 24, left: 24 } Desktop.
paddingTablet object undefined ≤ 1024px.
paddingMobile object undefined ≤ 767px.
paddingUnit string 'px' One unit applies to all three breakpoints.
margin, marginTablet, marginMobile, marginUnit - - Same shape.

undefined on tablet/mobile means "inherit desktop". The CSS generator only emits a media-query block when the attribute is a populated object.

typographyAttributes

Optional. Import explicitly when a block exposes type controls.

Key Type Default Purpose
fontFamily string '' CSS family list, sanitised on render.
fontSize, fontSizeTablet, fontSizeMobile number undefined Three breakpoints.
fontSizeUnit string 'px' One unit for all three.
fontWeight string '' normal, 500, etc.
lineHeight, lineHeightUnit number / string undefined / '' Unitless when blank.
letterSpacing number undefined Always rendered as px.
textTransform string '' One of none, uppercase, lowercase, capitalize.

shadowAttributes

Key Type Default Purpose
boxShadow boolean false Master toggle. Other shadow keys are ignored when this is false.
shadowHorizontal number 0 px
shadowVertical number 4 px
shadowBlur number 8 px (absolute)
shadowSpread number 0 px
shadowColor string 'rgba(0, 0, 0, 0.12)' Any valid CSS colour.

borderAttributes

Key Type Default Purpose
borderRadius object { top: 0, right: 0, bottom: 0, left: 0 } Per-corner radius. The standard treats the four object keys as TL/TR/BR/BL.
borderRadiusUnit string 'px'

visibilityAttributes

Key Type Default Purpose
hideOnDesktop boolean false Adds wb-gam-hide-desktop class on the wrapper.
hideOnTablet boolean false wb-gam-hide-tablet.
hideOnMobile boolean false wb-gam-hide-mobile.

The matching utility classes live in src/shared/base.css and apply display: none !important at the matching breakpoint.

Render-side contract (PHP)

Every standardised block calls CSS::add( $unique_id, $attrs ) from its render.php to emit a scoped style tag in the page footer:

use WBGam\Blocks\CSS;

function wb_gam_render_redemption_store( array $attributes, string $content, $block ): string {
	$unique_id = ! empty( $attributes['uniqueId'] )
		? $attributes['uniqueId']
		: substr( md5( wp_json_encode( $attributes ) ), 0, 10 );

	CSS::add( $unique_id, $attributes );

	$wrapper_attrs = get_block_wrapper_attributes(
		array(
			'class' => sprintf(
				'wb-gam-block-%s %s',
				sanitize_html_class( $unique_id ),
				CSS::get_visibility_classes( $attributes )
			),
		)
	);

	return sprintf( '<div %s>…</div>', $wrapper_attrs );
}

The generator emits desktop rules at the top, then @media (max-width: 1024px) for tablet, then @media (max-width: 767px) for mobile - matching the breakpoints in useResponsiveValue.js.

Filter hooks

Hook Args Purpose
wb_gam_block_css (filter) (string $css, string $unique_id, array $attrs) Override or augment the generated CSS for a given instance. Useful for theme override packs.
wb_gam_block_manifests (filter) (string[] $manifest_paths) Filter the list of block.json paths discovered by the auto-registrar.

Backwards compatibility

Saved post content containing the pre-migration block markup will gain deprecated migrations during Phase D of WBCOM-BLOCK-STANDARD-MIGRATION. Until then, only blocks rebuilt to the new schema (redemption-store first) carry these attributes.

See also

  • src/shared/utils/attributes.js - JavaScript schema source
  • src/Blocks/CSS.php - PHP CSS generator
  • src/Blocks/Registrar.php - build/blocks/ auto-registrar
  • plans/WBCOM-BLOCK-STANDARD-MIGRATION.md - full migration plan
  • Extending Blocks - wb_gam_block_before_render / _after_render hooks

Database Schema

All tables use the WordPress table prefix (default wp_). The current schema version is tracked by get_option('wb_gam_db_version').

Migrations live in src/Engine/DbUpgrader.php. Each version gets its own upgrade_to_X_Y_Z() method. Tables are created on activation via src/Engine/Installer.php using dbDelta().


Core Tables

wb_gam_events

Immutable event log. This is the source of truth for all gamification state. Events are never deleted except during GDPR erasure. All other tables are derived from this one and can be replayed.

Column Type Description
id VARCHAR(36) PK UUID generated at event creation time
user_id BIGINT UNSIGNED WordPress user ID
action_id VARCHAR(100) Action identifier (e.g. publish_post)
object_id BIGINT UNSIGNED NULL Optional related object (e.g. post ID)
metadata LONGTEXT JSON-encoded metadata bag (quality signals, word counts, etc.)
site_id VARCHAR(100) Remote site identifier for cross-site events (empty for local)
created_at DATETIME Event timestamp (UTC)

Indexes: idx_user_action (user_id, action_id), idx_user_created (user_id, created_at), idx_created (created_at), idx_site_id (site_id)

wb_gam_points

Points ledger. Derived from events. Each row represents one point award transaction and links back to the event that caused it via event_id.

Column Type Description
id BIGINT UNSIGNED PK AUTO_INCREMENT Ledger row ID
event_id VARCHAR(36) NULL FK to wb_gam_events.id
user_id BIGINT UNSIGNED WordPress user ID
action_id VARCHAR(100) Action identifier
points INT Points awarded (positive integer)
object_id BIGINT UNSIGNED NULL Optional related object
created_at DATETIME Transaction timestamp

Indexes: idx_event (event_id), idx_user_created (user_id, created_at), idx_user_action_created (user_id, action_id, created_at) (sargable for leaderboard queries), idx_action (action_id), idx_created (created_at)


Member Tables

wb_gam_user_badges

Earned badges. One row per member per badge. The UNIQUE KEY user_badge (user_id, badge_id) prevents duplicate awards.

Column Type Description
id BIGINT UNSIGNED PK AUTO_INCREMENT
user_id BIGINT UNSIGNED WordPress user ID
badge_id VARCHAR(100) Badge identifier (FK to wb_gam_badge_defs.id)
earned_at DATETIME Award timestamp
expires_at DATETIME NULL Expiry timestamp (added v0.3.0). NULL = never expires

Indexes: UNIQUE user_badge (user_id, badge_id), idx_expires_at (expires_at)

wb_gam_levels

Level definitions. Configurable per community. Seeded with 5 default levels on fresh install.

Column Type Description
id INT UNSIGNED PK AUTO_INCREMENT
name VARCHAR(255) Display name (e.g. "Contributor")
min_points BIGINT UNSIGNED Minimum points required to reach this level
icon_url VARCHAR(500) NULL Optional level icon URL
sort_order INT Display order in admin UI

Index: min_points (min_points) - used in level-up queries

Default levels: Newcomer (0), Member (100), Contributor (500), Regular (1500), Champion (5000)

wb_gam_streaks

Streak state per member. One row per user, updated on every point-earning activity.

Column Type Description
user_id BIGINT UNSIGNED PK WordPress user ID
current_streak INT UNSIGNED Current consecutive day/week count
longest_streak INT UNSIGNED All-time best streak
last_active DATE Last date the member earned points
timezone VARCHAR(50) Member timezone for day boundary calculations. Default UTC
grace_used TINYINT(1) Whether the one-time grace day has been used
updated_at DATETIME Auto-updated on each write

wb_gam_member_prefs

Per-user notification and privacy preferences. One row per user; missing row = all defaults.

Column Type Default Description
user_id BIGINT UNSIGNED PK WordPress user ID
leaderboard_opt_out TINYINT(1) 0 1 = hidden from public leaderboard
show_rank TINYINT(1) 1 0 = hide rank badge on profile and directory
notification_mode VARCHAR(20) smart smart, all, none

Index: idx_opt_out (leaderboard_opt_out)


Engagement Tables

wb_gam_challenges

Individual challenge definitions.

Column Type Description
id BIGINT UNSIGNED PK AUTO_INCREMENT
title VARCHAR(255) Challenge display name
type VARCHAR(20) individual or team
team_group_id BIGINT UNSIGNED NULL BuddyPress group ID (for team challenges)
action_id VARCHAR(100) Action this challenge tracks
target INT UNSIGNED Target count to complete the challenge
bonus_points INT Bonus points awarded on completion
period VARCHAR(20) none, day, week, month
starts_at DATETIME NULL Challenge start time
ends_at DATETIME NULL Challenge end time
status VARCHAR(20) active, inactive, completed

Indexes: status (status), idx_status_action (status, action_id)

wb_gam_challenge_log

Per-user challenge progress tracking.

Column Type Description
id BIGINT UNSIGNED PK AUTO_INCREMENT
user_id BIGINT UNSIGNED
challenge_id BIGINT UNSIGNED
progress INT UNSIGNED Current progress count
completed_at DATETIME NULL When the challenge was completed
created_at DATETIME

Key: UNIQUE user_challenge (user_id, challenge_id)

wb_gam_kudos

Peer kudos log. One row per kudos transaction.

Column Type Description
id BIGINT UNSIGNED PK AUTO_INCREMENT
giver_id BIGINT UNSIGNED User who gave kudos
receiver_id BIGINT UNSIGNED User who received kudos
message VARCHAR(255) NULL Optional message
created_at DATETIME

Indexes: giver_date (giver_id, created_at), receiver_id (receiver_id)

wb_gam_community_challenges

Community-wide (Pokémon GO-style) challenges where all members contribute to a shared goal.

Column Type Description
id BIGINT UNSIGNED PK AUTO_INCREMENT
title VARCHAR(255)
description TEXT NULL
target_action VARCHAR(100) Action being counted site-wide
target_count BIGINT UNSIGNED Global target
global_progress BIGINT UNSIGNED Current community-wide count
bonus_points INT Points awarded to each contributor on completion
status VARCHAR(20) active, completed
starts_at DATETIME NULL
ends_at DATETIME NULL
completed_at DATETIME NULL

wb_gam_community_challenge_contributions

Per-user contribution counts for community challenges.

Column Type Description
challenge_id BIGINT UNSIGNED
user_id BIGINT UNSIGNED
contribution_count BIGINT UNSIGNED Number of qualifying actions this user performed

PK: (challenge_id, user_id)


Rules Tables

wb_gam_rules

All rule configurations: badge conditions, point multipliers, and other rule types.

Column Type Description
id BIGINT UNSIGNED PK AUTO_INCREMENT
rule_type VARCHAR(50) badge_condition, point_multiplier, etc.
target_id VARCHAR(100) NULL Badge ID (for badge_condition) or other target
rule_config LONGTEXT JSON-encoded rule parameters
is_active TINYINT(1) 1 = active, 0 = disabled
created_at DATETIME

Indexes: rule_type (rule_type), target_id (target_id)

Badge condition types stored in rule_config.condition_type:

  • point_milestone - fires when total_points >= config.points
  • action_count - fires when a specific action has been performed N times
  • admin_awarded - no automatic condition; admin awards manually

wb_gam_badge_defs

Badge definitions (catalog). Award conditions live in wb_gam_rules.

Column Type Description
id VARCHAR(100) PK Badge identifier slug (e.g. top_contributor)
name VARCHAR(255) Display name
description TEXT NULL
image_url VARCHAR(500) NULL Badge image URL
is_credential TINYINT(1) 1 = issued as an OpenBadges 3.0 credential
validity_days INT UNSIGNED NULL Badge expiry in days. NULL = never expires
closes_at DATETIME NULL Date after which the badge can no longer be earned
max_earners INT UNSIGNED NULL Maximum members who can hold this badge
category VARCHAR(50) points, wordpress, buddypress, special
created_at DATETIME

Advanced Tables

wb_gam_webhooks

Registered outbound webhook endpoints.

Column Type Description
id BIGINT UNSIGNED PK AUTO_INCREMENT
url VARCHAR(500) Webhook target URL
secret VARCHAR(255) HMAC-SHA256 signing secret
events TEXT JSON array of event types to forward
is_active TINYINT(1)
created_at DATETIME

wb_gam_redemption_items

Rewards catalog for the points redemption store.

Column Type Description
id BIGINT UNSIGNED PK AUTO_INCREMENT
title VARCHAR(255) Reward display name
description TEXT NULL
points_cost INT UNSIGNED Points required to redeem
reward_type VARCHAR(50) e.g. coupon, download, manual
reward_config LONGTEXT NULL JSON-encoded reward delivery config
stock INT UNSIGNED NULL Available quantity. NULL = unlimited
is_active TINYINT(1)
created_at DATETIME

wb_gam_redemptions

Redemption transaction log.

Column Type Description
id BIGINT UNSIGNED PK AUTO_INCREMENT
user_id BIGINT UNSIGNED
item_id BIGINT UNSIGNED
points_cost INT UNSIGNED Points deducted at time of redemption
status VARCHAR(30) pending, fulfilled, cancelled
coupon_code VARCHAR(100) NULL Generated coupon code if applicable
created_at DATETIME

wb_gam_cosmetics

Cosmetics catalog (profile frames, avatar overlays, etc.).

Column Type Description
id VARCHAR(100) PK Cosmetic identifier slug
name VARCHAR(255)
type VARCHAR(50) e.g. avatar_frame, profile_background
asset_url VARCHAR(500) NULL URL to the cosmetic asset
css_class VARCHAR(100) NULL CSS class applied to the member's profile
award_type VARCHAR(30) admin, milestone, purchase
cost INT UNSIGNED Points cost if award_type = purchase. 0 = free
is_active TINYINT(1)

wb_gam_user_cosmetics

Cosmetics owned by members.

Column Type Description
user_id BIGINT UNSIGNED
cosmetic_id VARCHAR(100)
is_active TINYINT(1) 1 = currently equipped
awarded_at DATETIME

PK: (user_id, cosmetic_id)

wb_gam_cohort_members

Cohort league tracking (Duolingo-style weekly leagues).

Column Type Description
user_id BIGINT UNSIGNED
cohort_id VARCHAR(50) Cohort group identifier
tier TINYINT UNSIGNED Current league tier
tier_end TINYINT UNSIGNED NULL Tier at end of week (set during resolution)
outcome VARCHAR(20) NULL promoted, demoted, retained
week VARCHAR(10) ISO week identifier (e.g. 2026-W14)
pts_start INT UNSIGNED Points at the start of the week

PK: (user_id, week)

wb_gam_leaderboard_cache

Leaderboard snapshot. Written by wb_gam_leaderboard_snapshot cron job; read by LeaderboardEngine. Note: rank is backtick-escaped because it is a MySQL 8.0 reserved word.

Column Type Description
id BIGINT UNSIGNED PK AUTO_INCREMENT
user_id BIGINT UNSIGNED
period VARCHAR(20) all, month, week, day
total_points BIGINT Points total for this period
rank INT UNSIGNED Position in the leaderboard
updated_at DATETIME Snapshot timestamp

Indexes: idx_period_rank (period, rank), idx_user_period (user_id, period)


Version Tracking

// Check current DB version.
$version = get_option( 'wb_gam_db_version', '0.0.0' );

// After Installer::install() or DbUpgrader, the version is set to WB_GAM_VERSION.
update_option( 'wb_gam_db_version', WB_GAM_VERSION );

Run wp wb-gamification doctor to check whether your database schema matches the installed plugin version.

Realtime transport - Heartbeat (default) vs Server-Sent Events

WB Gamification ships two realtime transports for toast notifications, live leaderboards, and other "push" events. WP Heartbeat is the shipped default and the only transport most sites should use. Server-Sent Events is an opt-in optimisation gated behind a filter (see below) because the SSE long-poll pins one PHP-FPM worker per connected member, which does not scale on a standard pool.

The transport is selected by the wb_gam_realtime_transport site option, but SSE only actually runs when the wb_gam_sse_allowed filter also returns true.

wp option get wb_gam_realtime_transport      # default: heartbeat
wp option update wb_gam_realtime_transport auto
Value What happens
heartbeat WP Heartbeat poll. Works everywhere. Default.
sse Server-Sent Events stream. Sub-second receiver-side latency. Only runs when wb_gam_sse_allowed returns true and the host supports it (see below); otherwise falls back to heartbeat.
auto Client tries SSE first (when wb_gam_sse_allowed permits it), falls back to heartbeat on connection error.

Heartbeat intervals

The Heartbeat transport (assets/js/heartbeat.js) adapts its polling rate so it feels live without flooding admin-ajax.php:

State Interval Why
Steady 15s (standard) One shared, throttled tick. Realtime feedback rarely matters between actions.
Burst 5s (fast) for ~30s Triggered right after the member takes a point-earning action, then eases back to steady.
Hidden tab 120s Near-suspend when the tab is backgrounded so a left-open tab stops costing ticks.

Override the steady-state interval client-side by setting window.wbGamRealtimeInterval to a Heartbeat speed string ('standard', 'fast', or a number of seconds) before heartbeat.js runs:

<script>window.wbGamRealtimeInterval = 'standard';</script>

Enabling SSE

SSE is off by default. To turn it on you need BOTH:

  1. The transport option set to sse or auto, AND
  2. The wb_gam_sse_allowed filter returning true:
// Only enable on infrastructure provisioned for long-lived streaming
// (dedicated worker pool, no proxy buffering).
add_filter( 'wb_gam_sse_allowed', '__return_true' );

When wb_gam_sse_allowed is false (the default), the stream endpoint declines and clients run on WP Heartbeat instead.

When to enable SSE / auto

  • Cross-user notifications matter - e.g. "Alice gave Bob kudos" should show on Bob's screen in <1 second, not on the next heartbeat tick.
  • Your host supports long-polling PHP - shared cPanel without PHP-FPM tuning usually doesn't. Managed WordPress hosts (Kinsta, WP Engine, Pressable) with a dedicated worker pool typically do.
  • No layer-7 proxy is buffering responses - see "Host requirements" below.

For most installs heartbeat is the right choice. SSE is an optimisation for community-heavy sites on infrastructure built for long-lived connections, where the sub-second receiver toast measurably improves engagement.

Host requirements (when using sse or auto)

Three host-level configurations can silently break SSE. The transport controller emits the correct headers but downstream proxies may buffer.

nginx

Add to the site's location block (or the entire server block):

location /wp-json/wb-gamification/v1/events/stream {
    proxy_buffering off;
    proxy_cache off;
    proxy_set_header X-Accel-Buffering no;
}

The plugin sends X-Accel-Buffering: no as a response header, which nginx honours when proxying - but it doesn't help if nginx is the ORIGIN. The above location block ensures buffering is off either way.

Cloudflare

Cloudflare will hold response bytes until the connection closes if "Auto Minify" is enabled for the stream URL. Either:

  1. Disable Auto Minify globally (Speed → Optimization → Auto Minify → uncheck HTML), OR
  2. Add a Page Rule for */wp-json/wb-gamification/v1/events/stream* with Cache Level set to "Bypass" and Auto Minify disabled.

PHP-FPM

The controller calls session_write_close() before the long-polling loop to release the session lock. If your host has aggressive output buffering enabled in php.ini (output_buffering = On with a non-zero buffer), the response can stall. The controller drains all buffers with ob_end_flush() + ob_implicit_flush(true) - but if buffering is enabled at the FastCGI level, drop a .htaccess or php.ini directive:

output_buffering = Off

Verifying SSE works on your install

Open the browser DevTools Network tab on any frontend page where the toast renderer is loaded. Look for a request to /wp-json/wb-gamification/v1/events/stream.

Healthy SSE:

  • Status: 200
  • Type: eventsource
  • Time: pending (connection stays open)
  • Response: bytes streaming in, including : keepalive comments every 2 seconds

Broken SSE - fallback active:

  • Status: 503 with Retry-After header → transport flag is set to heartbeat, no SSE attempted. Working as designed.
  • Status: 200 but EventSource emits an error within 10 seconds → one of the host issues above. Browser auto-falls back to heartbeat; check the Network tab for wp-admin/admin-ajax.php?action=heartbeat requests appearing instead.

What about WebSockets?

We don't ship a WebSocket transport. The short version: nothing in this plugin needs client-to-server messaging that REST + ping() can't already handle, and WebSocket adds two layers of host compatibility friction (mod proxy wstunnel, sticky sessions) that SSE doesn't.

Filters

// Gate the SSE long-poll transport (default false). SSE only runs when
// this returns true AND the transport option is 'sse' or 'auto'.
add_filter( 'wb_gam_sse_allowed', '__return_true' );

The steady-state Heartbeat polling interval is not a PHP filter - set the window.wbGamRealtimeInterval JavaScript global (see "Heartbeat intervals" above) to change it. The default is 'standard' (15s) with an automatic 5s burst for ~30s after each member action.

See the Filters reference for wb_gam_sse_allowed and the related toast-placement filter wb_gam_toast_position.

Cross-Site API

Overview

WB Gamification can act as a centralized gamification server. A dedicated WordPress site runs the plugin and holds all gamification data. Remote sites - BuddyPress communities, WooCommerce stores, headless frontends, mobile apps - authenticate via API keys and submit events to the central server.

This model is useful when you run multiple sites and want a single leaderboard, unified badge library, and one admin interface.

Deployment Modes

Mode How When to use
Local Plugin installed on the same site. Uses WordPress cookie/nonce auth Single-site installs, the default
Remote Plugin on a dedicated gamification center site. Remote clients authenticate via X-WB-Gam-Key Multi-site setups, mobile apps, external services

In remote mode the capabilities response includes "mode": "remote" and "site_id" is populated for all events.

Creating API Keys

API keys are created and managed at WP Admin → Gamification → API Keys. Each key is associated with a WordPress user (whose capabilities determine what the key can do) and optionally a site_id string for attribution.

You can also create keys programmatically:

use WBGam\API\ApiKeyAuth;

$key = ApiKeyAuth::create_key(
    label:   'My Remote Store',     // Human-readable label shown in admin.
    user_id: 1,                     // User whose capabilities the key inherits.
    site_id: 'my-store'             // Identifier embedded in all events from this key.
);

// $key = 'wbgam_AbCdEfGhIjKlMnOpQrStUvWxYz...' (40-char random string)

Keys start with wbgam_. Store them securely - they cannot be retrieved after creation.

Revoking and Deleting Keys

// Deactivate (keeps the key record for audit purposes).
ApiKeyAuth::revoke_key( 'wbgam_...' );

// Permanently delete.
ApiKeyAuth::delete_key( 'wbgam_...' );

Authenticating Requests

Include the API key in every request to the gamification center.

GET /wp-json/wb-gamification/v1/members/42
X-WB-Gam-Key: wbgam_AbCdEfGhIjKlMnOpQrStUvWxYz...

Option 2: Query Parameter

GET /wp-json/wb-gamification/v1/members/42?api_key=wbgam_AbCdEfGhIjKlMnOpQrStUvWxYz...

The header approach is preferred - query params can appear in server logs.

Authentication Priority

API key auth runs at rest_authentication_errors priority 20, after WordPress's own cookie/nonce auth. If a valid cookie session already exists, the API key is ignored. This means the same endpoint works for both browser sessions and remote API callers.

Site ID Tracking

When a request is authenticated via an API key that has a site_id set, that value is injected into every event's metadata under the _site_id key and stored in the wb_gam_events.site_id column.

You can filter by site_id when querying the event log to audit activity per remote site.

The site_id is also exposed in the capabilities response so remote clients can confirm their identity:

{
  "authenticated": true,
  "mode": "remote",
  "site_id": "my-store",
  "can": { "submit_events": true, "award_points": false }
}

CORS Headers

When a request is authenticated via API key, the plugin automatically adds CORS headers allowing cross-origin requests:

Access-Control-Allow-Origin: <request origin>
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: X-WB-Gam-Key, Content-Type, Authorization, X-WP-Nonce
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS

This enables browser-based JavaScript on remote origins to call the gamification center directly.

Capabilities Discovery

Before making calls, a remote site should fetch the capabilities endpoint to learn what it is allowed to do:

GET /wp-json/wb-gamification/v1/capabilities
X-WB-Gam-Key: wbgam_...

Response:

{
  "authenticated": true,
  "user_id": 1,
  "site_id": "my-store",
  "mode": "remote",
  "can": {
    "read_leaderboard": true,
    "read_badges": true,
    "read_own_profile": true,
    "read_any_profile": false,
    "award_points": false,
    "submit_events": true,
    "give_kudos": true
  },
  "features": { "cohort_leagues": false, "redemption_store": true },
  "version": "1.0.0",
  "endpoints": {
    "members":     "https://gam.example.com/wp-json/wb-gamification/v1/members",
    "leaderboard": "https://gam.example.com/wp-json/wb-gamification/v1/leaderboard",
    "badges":      "https://gam.example.com/wp-json/wb-gamification/v1/badges",
    "kudos":       "https://gam.example.com/wp-json/wb-gamification/v1/kudos",
    "capabilities":"https://gam.example.com/wp-json/wb-gamification/v1/capabilities"
  }
}

Use the endpoints map to resolve URLs dynamically rather than hardcoding paths.

Connecting a Remote Site

  1. On the gamification center site, go to WP Admin → Gamification → API Keys and create a key. Set the Site ID field to something that identifies your remote site (e.g. store-site-1).

  2. Copy the generated key.

  3. On the remote site, install WB Gamification and add the key to your wp-config.php or your plugin's settings:

define( 'WB_GAM_REMOTE_CENTER_URL', 'https://gam.example.com' );
define( 'WB_GAM_REMOTE_API_KEY',    'wbgam_...' );
  1. Use the helper functions or REST API to forward events:
// Forward a points event to the central server.
$response = wp_remote_post(
    WB_GAM_REMOTE_CENTER_URL . '/wp-json/wb-gamification/v1/points/award',
    [
        'headers' => [
            'X-WB-Gam-Key' => WB_GAM_REMOTE_API_KEY,
            'Content-Type' => 'application/json',
        ],
        'body' => wp_json_encode( [
            'user_id' => $user_id,
            'points'  => 10,
            'reason'  => 'remote_purchase',
        ] ),
    ]
);

Multi-Site Use Case

Example architecture:

                ┌─────────────────────────────────┐
                │  gamification.example.com        │
                │  (WB Gamification center site)   │
                │  - All points, badges, levels    │
                │  - Single leaderboard            │
                │  - Admin dashboard               │
                └───────────┬─────────────────────┘
                            │ REST API + API keys
            ┌───────────────┼────────────────────┐
            │               │                    │
     community.example.com  store.example.com   app.example.com
     (BuddyPress)           (WooCommerce)       (React Native)
     site_id: "community"   site_id: "store"    site_id: "mobile"

Each remote site uses its own API key with a distinct site_id. The gamification center can filter its event log and analytics by site_id to see which site generated which activity.

WP-CLI Commands

All commands use the wb-gamification command namespace:

wp wb-gamification <command> <subcommand> [options]

points award

Award points to a member. This is a direct admin award - it bypasses cooldown and daily-cap checks.

Syntax

wp wb-gamification points award --user=<id> --points=<n> [--action=<id>] [--message=<msg>]

Options

Option Required Description
--user=<id> Yes User ID, login name, or email address
--points=<n> Yes Number of points to award (positive integer)
--action=<id> No Action ID to record in the ledger. Default: manual
--message=<msg> No Optional admin note stored in event metadata

Examples

# Award 100 points to user ID 42.
wp wb-gamification points award --user=42 --points=100

# Award 50 points with a custom action ID and note.
wp wb-gamification points award --user=jane --points=50 --action=speaker_bonus --message="Community hero this month"

# Award by email address.
wp wb-gamification points award --user=jane@example.com --points=200

Expected Output

Success: Awarded 100 pts to Jane Smith. New total: 1350.
Success: Awarded 50 pts to Jane Smith (Community hero this month). New total: 1400.

member status

Show a member's full gamification profile: points, level, progress to the next level, and earned badges.

Syntax

wp wb-gamification member status --user=<id>

Options

Option Required Description
--user=<id> Yes User ID, login name, or email address

Examples

wp wb-gamification member status --user=42
wp wb-gamification member status --user=jane@example.com

Expected Output

User:    Jane Smith (ID: 42)
Points:  1350
Level:   Contributor
Next:    Regular (1500 pts) - 90% there
Badges:  4
         century_club, welcome, first_post, first_update

actions list

List all registered gamification actions with their current point values, daily cap, cooldown, and enabled state.

Syntax

wp wb-gamification actions list [--format=<format>] [--category=<cat>]

Options

Option Required Description
--format=<format> No Output format: table, csv, json, count. Default: table
--category=<cat> No Filter by category slug (e.g. buddypress, wordpress, commerce)

Examples

# Table output (default).
wp wb-gamification actions list

# JSON output for scripting.
wp wb-gamification actions list --format=json

# Filter to BuddyPress actions only.
wp wb-gamification actions list --category=buddypress

Expected Output (table)

+------------------------+-----------------------------+------------+--------+-----------+----------+---------+
| id                     | label                       | category   | points | daily_cap | cooldown | enabled |
+------------------------+-----------------------------+------------+--------+-----------+----------+---------+
| bp_activity_update     | Posted an activity update   | buddypress | 5      | 10        | -        | yes     |
| bp_friends_accepted    | Made a new friend           | buddypress | 10     | ∞         | -        | yes     |
| publish_post           | Published a post            | wordpress  | 15     | ∞         | -        | yes     |
+------------------------+-----------------------------+------------+--------+-----------+----------+---------+

logs prune

Remove old entries from the event log (wb_gam_events). The points ledger, badges, levels, and leaderboard are not affected - only the raw audit trail is trimmed.

Syntax

wp wb-gamification logs prune --before=<timespan> [--dry-run]

Options

Option Required Description
--before=<timespan> Yes Delete entries older than this. Formats: 6months, 1year, 90days
--dry-run No Show the row count that would be deleted without deleting anything

Examples

# Preview: how many rows would be deleted?
wp wb-gamification logs prune --before=6months --dry-run

# Delete entries older than one year.
wp wb-gamification logs prune --before=1year

# Delete entries older than 90 days.
wp wb-gamification logs prune --before=90days

Expected Output

[dry-run] Would delete 4,832 event log entries older than 2025-10-01 00:00:00.
Success: Deleted 4,832 event log entries older than 2025-10-01 00:00:00.

export user

Export all gamification data for a member as JSON. Use for GDPR data portability requests.

Syntax

wp wb-gamification export user --user=<id> [--format=<fmt>]

Options

Option Required Description
--user=<id> Yes User ID, login name, or email address
--format=<fmt> No Only json is supported. Default: json

Examples

# Print JSON to stdout.
wp wb-gamification export user --user=42

# Redirect to a file for delivery to the member.
wp wb-gamification export user --user=jane@example.com > export.json

Expected Output

{
  "user_id": 42,
  "display_name": "Jane Smith",
  "email": "jane@example.com",
  "exported_at": "2026-04-01T09:00:00+00:00",
  "points_total": 1350,
  "points_history": [...],
  "badges": [...],
  "level": { "id": 3, "name": "Contributor", "min_points": 500 }
}

doctor

Run a comprehensive system health check. Validates database tables, default levels, default badges, registered actions, settings, cron jobs, REST API routes, and pro addon compatibility. Reports pass/warn/fail for each check.

Syntax

wp wb-gamification doctor [--verbose] [--fix]

Options

Option Required Description
--verbose No Show details for passing checks, not just warnings and failures
--fix No Auto-fix issues that can be repaired (re-seed levels, badges; clean up orphaned options)

Examples

# Standard check.
wp wb-gamification doctor

# Show all check results including passing ones.
wp wb-gamification doctor --verbose

# Auto-fix what can be fixed.
wp wb-gamification doctor --fix

Expected Output

WB Gamification Doctor v1.0.0
────────────────────────────────────────────────────────────

► Database Tables
  ✓ 20 tables present
  ✓ DB version: 1.0.0

► Default Levels
  ✓ 5 levels defined
  ✓ Starting level (0 points) exists

► Default Badges
  ✓ 30 badges defined
  ✓ 23 badges with auto-award conditions

► Registered Actions
  ✓ 14 actions registered
  ✓ All actions enabled

► REST API
  ✓ 42 REST routes registered
  ✓ All core endpoints present

► Cron Jobs
  ⚠ Log pruner (wb_gam_prune_logs) not scheduled

────────────────────────────────────────────────────────────
Results: 18 pass, 1 warn, 0 fail
Warning: Plugin has warnings - review before release.

The --fix flag re-seeds missing levels and badges by running Installer::install(), and cleans up any orphaned option keys from previous plugin versions.

Hooks and Filters Overview

WB Gamification exposes action hooks and filter hooks so you can extend the engine, add custom logic, or integrate with third-party systems without forking the plugin.

What hooks are

A hook is a named extension point the plugin fires while it runs. There are two kinds:

  • Actions let you run your own code when something happens (points awarded, badge earned, streak broken). You react to the event but do not change it.
  • Filters let you modify a value before the engine uses it (the points for an action, a leaderboard result set, a toast payload). You receive a value and return a value.

Every hook is a no-op when nobody listens, so there is zero overhead by default.

Naming convention

Hooks prefixed wb_gam_ are the gamification hooks you extend. A small number of lifecycle hooks use the longer wb_gamification_ prefix and are treated as stable public API.

Most hooks fire regardless of configuration. A few hooks only fire when their optional engine's feature flag is enabled in wb_gam_features (every flag defaults to true); those are called out in the reference pages.

How to add a listener

Register an action with add_action() and a filter with add_filter(). Match the parameter count to the hook signature in the reference pages (the fourth argument to add_action / add_filter).

// Action: react after points are written to the ledger.
add_action( 'wb_gam_points_awarded', function ( int $user_id, $event, int $points ) {
    // Sync points to an external CRM.
    my_crm_update_points( $user_id, $points, $event->action_id );
}, 10, 3 );

// Filter: double points on weekends before they are written.
add_filter( 'wb_gam_points_for_action', function ( int $points, string $action_id, int $user_id, $event ) {
    if ( in_array( gmdate( 'l' ), array( 'Saturday', 'Sunday' ), true ) ) {
        return $points * 2;
    }
    return $points;
}, 10, 4 );

For an action you do not need to return anything. For a filter you must always return a value (return the value unchanged when your condition does not apply).

Reference index

Page Covers
Actions reference Every do_action hook: when it fires and the parameters it passes.
Filters reference Every apply_filters hook: what it filters, the parameters, and the value to return.

Both reference pages group hooks by domain: Points and awards, Badges and levels, Challenges and kudos, Submissions, Integrations, and Lifecycle.

Actions Reference

Every action hook (do_action) in WB Gamification, grouped by domain. Register a listener with add_action() and match the parameter count to the signature shown.

See Hooks and Filters Overview for how to add a listener, and the Filters reference for value-modifying hooks.

Points and awards

Hook When it fires Parameters
wb_gam_before_points_awarded Before points are written to the ledger. All checks have passed (enabled, rate limits, gate filter, multipliers). Last chance to inspect or log before it becomes permanent. int $user_id, Event $event, int $points
wb_gam_points_awarded After points are written to the ledger. The most-used hook; it triggers badge evaluation, level check, streak update, and notifications. int $user_id, Event $event, int $points
wb_gam_points_awarded_batch After a bulk award writes the same action to many users in one operation. array $user_ids, string $action_id, int $points, string $point_type, int $total
wb_gam_points_revoked When an admin revokes (deletes) a point award via the REST API. int $row_id, array $row, int $admin_id
wb_gam_points_redeemed When a member redeems points for a reward in the redemption store. int $redemption_id, int $user_id, array $item, ?string $coupon
wb_gam_point_type_converted After a member converts one point currency into another. Debit and credit ledger rows share an event_id. int $user_id, string $from, string $to, int $debit_amount, int $credit_amount, array $rule
wb_gam_award_skipped When the engine intentionally skips an award (cooldown, cap reached, self-action, veto). Use it to surface a contextual hint so silent skips do not feel broken. int $user_id, string $action_id, string $reason, array $context
wb_gam_points_decayed After each daily inactivity point-decay sweep (Settings > Points > Point expiry; off by default). $count is the number of members decayed this run. Added in 1.5.3. int $count

wb_gam_award_skipped reason taxonomy (closed set)

Reason Fired from Common context keys
cooldown PointsEngine::passes_rate_limits() cooldown branch cooldown_seconds, point_type
non_repeatable PointsEngine::passes_rate_limits() non-repeatable branch point_type
daily_cap PointsEngine::passes_rate_limits() daily-cap branch daily_cap_used, daily_cap_max, point_type
weekly_cap PointsEngine::passes_rate_limits() weekly-cap branch weekly_cap_used, weekly_cap_max, point_type
self_action Registry hook callback when user_callback returns 0 (none)
sandboxed Jetonomy adapter, wb_gam_sandboxed user meta veto delta, adapter
pre_change_veto Adapter *_pre_change filters that return 0 for non-sandbox reasons adapter-specific
insufficient_balance Future debit-balance check requested, balance

Badges and levels

Hook When it fires Parameters
wb_gam_badge_awarded After a badge is awarded to a member. int $user_id, array $badge_def, string $badge_id
wb_gam_after_badge_award After a badge is awarded (legacy alias, lighter signature). int $user_id, string $badge_id
wb_gam_credential_expired When a badge credential passes its expires_at date during the daily expiry check. int $user_id, string $badge_id, string $expires_at
wb_gam_level_assigned When a member is assigned a starter level (initial assignment). Toast/level-up overlays do not listen here, so new members are not congratulated for being a Newcomer. int $user_id, array $new_level
wb_gam_level_changed When a member moves to a different level (up or down). Does not fire on initial assignment. int $user_id, array|null $new_level, array|null $old_level
wb_gam_streak_milestone When a member reaches a streak milestone (7, 14, 30, 60, 100, 180, or 365 days). int $user_id, int $streak_days
wb_gam_streak_broken When a member's streak is reset to 1 after exceeding the grace period. int $user_id, int $old_streak, int $gap_days
wb_gam_personal_record When a member sets a new personal points record for a period. int $user_id, string $period, int $current, int $previous, string $message

Challenges and kudos

Hook When it fires Parameters
wb_gam_challenge_completed When a member completes a challenge (reaches the target count). int $user_id, array $challenge
wb_gam_community_challenge_completed When a community (team) challenge reaches its global target. int $challenge_id, int $bonus_points, int $contributor_count
wb_gam_community_challenge_created When an admin creates a community challenge via the REST API. int $id, array $data
wb_gam_community_challenge_updated When an admin updates a community challenge via the REST API. int $id, array $updates
wb_gam_community_challenge_deleted When an admin deletes a community challenge via the REST API. int $id
wb_gam_kudos_given After kudos are successfully recorded. int $giver_id, int $receiver_id, string $message, int $kudos_id

Submissions

Hook When it fires Parameters
wb_gam_submission_created After a member submits a user-generated-content achievement to the moderation queue. int $submission_id, int $user_id, string $action_id
wb_gam_submission_approved After an admin approves a queued submission. Approval routes through PointsEngine::award so badges/levels stay consistent. int $submission_id, int $user_id, string $action_id, int $reviewer_id
wb_gam_submission_rejected After an admin rejects a queued submission. int $submission_id, int $user_id, string $action_id, int $reviewer_id, string $notes

Login bonus

Hook When it fires Parameters
wb_gam_login_bonus_claimed After a member claims a daily login bonus for the day's streak tier. int $user_id, int $streak, int $bonus

Integrations

These optional-engine hooks fire only when their feature flag is enabled in wb_gam_features (defaults to true).

Hook When it fires Parameters
wb_gam_weekly_email_sent After a weekly recap email is sent. int $user_id, array $data
wb_gam_weekly_nudge_sent When a leaderboard nudge has been delivered to a member (after the BuddyPress notification and optional email). Renamed from wb_gam_weekly_nudge in 1.4.1. int $user_id, int $rank, int $points, ?int $points_to_next, string $message
wb_gam_cohort_outcome When a cohort league season ends with promotion or demotion results. $outcome is promoted, demoted, or stayed. int $user_id, int $old_tier, int $new_tier, string $outcome, int $points
wb_gam_retention_nudge When a status-retention nudge is dispatched to a member at risk of disengaging. int $user_id, array $level, array $next, int $pts_needed, string $message
wb_gam_rank_automation_action When a custom rank automation action type is executed. int $user_id, array $action, string $type

Admin CRUD (REST)

These fire from the REST controllers behind the admin CRUD screens. Each carries the WP_REST_Request so listeners can inspect the originating call.

Hook When it fires Parameters
wb_gam_after_create_badge After a badge is created via the REST API. array $created, WP_REST_Request $request
wb_gam_after_update_badge After a badge is updated via the REST API. int $badge_id, array $data, WP_REST_Request $request
wb_gam_after_create_level After a level is created via the REST API. array $row, WP_REST_Request $request
wb_gam_after_update_level After a level is updated via the REST API. array $fresh, array $current, WP_REST_Request $request
wb_gam_before_delete_level Before a level is deleted via the REST API. array $current, WP_REST_Request $request
wb_gam_after_delete_level After a level is deleted via the REST API. array $current, WP_REST_Request $request
wb_gam_after_create_community_challenge After a community challenge is created via the REST API. array $row, WP_REST_Request $request
wb_gam_after_update_community_challenge After a community challenge is updated via the REST API. array $fresh, array $current, WP_REST_Request $request
wb_gam_before_delete_community_challenge Before a community challenge is deleted via the REST API. array $current, WP_REST_Request $request
wb_gam_after_delete_community_challenge After a community challenge is deleted via the REST API. array $current, WP_REST_Request $request
wb_gam_after_create_api_key After an API key is created via the REST API. int $id, array $row, WP_REST_Request $request
wb_gam_after_revoke_api_key After an API key is revoked via the REST API. int $id, array $row, WP_REST_Request $request
wb_gam_after_delete_api_key After an API key is deleted via the REST API. int $id, array $row, WP_REST_Request $request
wb_gam_after_save_cohort_settings After cohort settings are saved via the REST API. array $settings, bool $enabled, WP_REST_Request $request
wb_gam_cohort_settings_saved After cohort settings are saved (lighter signature, no request). array $settings, bool $enabled

Event pipeline and engine internals

Hook When it fires Parameters
wb_gam_event_processed After an event has been normalized and run through rule evaluation. array $metadata, int $user_id
wb_gam_unknown_action When an incoming event references an action slug that no manifest registered. $suggestions holds the closest known slugs. string $action_id, Event $event, array $suggestions
wb_gam_leaderboard_cache_invalidated After the leaderboard snapshot cache is cleared. (none)
wb_gam_manifests_loaded After all action manifests are auto-discovered. $loaded_actions is the full registry of discovered actions. array $loaded_actions
wb_gam_as_cleaned After the Action Scheduler cleaner sweeps completed/failed rows. array $results, string $cutoff, bool $panic_mode
wb_gam_as_runaway_detected When the Action Scheduler cleaner detects a runaway queue and enters panic mode. array $payload

Site-owner controls

Added in 1.5.3 (Settings > Tools).

Hook When it fires Parameters
wb_gam_progress_reset After an admin resets all member progress (Settings > Tools danger zone). The progress tables and per-user progress meta are wiped while all configuration and definitions are kept. Adapters can clear their own derived state (transients, etc.) here. Added in 1.5.3. (none)

Lifecycle

Hook When it fires Parameters
wb_gam_engines_booted After all engines have initialized. Third-party extensions hook here to register additional engines. (none)
wb_gam_register After the Registry is initialized. Last chance to register actions via the manual API. (none)
wb_gamification_setup_wizard_started When the setup wizard begins applying a starter template. string $template
wb_gamification_setup_wizard_completed After the setup wizard finishes applying a starter template. string $template
wb_gam_log_pruned After the daily points-ledger pruner runs (one fire per cron tick). int $deleted, string $cutoff
wb_gam_events_pruned After the daily event-log pruner runs (one fire per cron tick). int $deleted, string $cutoff
wb_gam_user_data_erased After all gamification data for a user is erased (GDPR). int $user_id

Block extension actions

Every server-rendered block fires two universal action hooks (on all 15 blocks) for HTML injection.

Hook When it fires Parameters
wb_gam_block_before_render Immediately before a block emits any HTML. Use to inject UI above the block, log impressions, or short-circuit via output capture. string $slug, array $attributes, array $context
wb_gam_block_after_render Immediately after the block finishes its HTML. Use to append UI (share button, CTA), inject analytics beacons, or react to the render. string $slug, array $attributes, array $context

Filters Reference

Every filter hook (apply_filters) in WB Gamification, grouped by domain. Register a listener with add_filter(), match the parameter count to the signature shown, and always return a value (return it unchanged when your condition does not apply).

See Hooks and Filters Overview for how to add a listener, and the Actions reference for event hooks.

Points and awards

Filter What it filters Parameters Return
wb_gam_points_for_action Points before they are written. Called after admin option lookup, before multipliers. int $points, string $action_id, int $user_id, Event $event int final points
wb_gam_before_evaluate Gate filter. Return false to silently block an event from being processed. bool $proceed, Event $event bool whether to proceed
wb_gam_event_metadata Event metadata before rule evaluation. Enrich it with computed fields. array $metadata, Event $event array metadata
wb_gam_rule_condition Resolves a custom rule condition type the core engine does not recognize. Return true to mark the condition met. bool $met, array $condition, Event $event bool whether the condition is met
wb_gam_leaderboard_results Leaderboard data before it is returned to blocks, shortcodes, or the REST API. array $results, array $raw_rows array results
wb_gam_leaderboard_scope_user_ids The set of user IDs included in a scoped leaderboard. Return an explicit list to define a custom scope. array $user_ids, string $scope_type, int $scope_id array user IDs
wb_gam_toast_data Toast notification content before it is queued. Return an empty array to suppress. array $event, int $user_id array toast data (empty to suppress)
wb_gam_heartbeat_payload The realtime heartbeat payload before it is returned to the browser. array $out, int $user_id, array $boards array payload

Badges and levels

Filter What it filters Parameters Return
wb_gam_should_award_badge Gate filter. Return false to prevent a specific badge from being awarded. bool $should, int $user_id, string $badge_id, array $def bool whether to award
wb_gam_badge_condition Resolves a custom badge condition type the core badge engine does not recognize. Return true to mark the condition met. bool $met, string $type, array $config, int $user_id, Event $event, int $total bool whether the condition is met
wb_gam_badge_share_respects_privacy Whether the public badge-share page should honor the member's privacy setting. Default false. bool $respects_privacy bool
wb_gam_streak_grace_days The grace period (days before a streak breaks) per user. int $days, int $user_id int grace days
wb_gam_credential_document The OpenBadges 3.0 JSON-LD credential before it is returned. array $credential, string $badge_id, int $user_id array credential document

Challenges and kudos

Filter What it filters Parameters Return
wb_gam_before_kudos Validate or block kudos before they are recorded. Return a WP_Error to reject. mixed $result, int $giver_id, int $receiver_id, string $message $result unchanged, or a WP_Error to reject
wb_gam_kudos_per_receiver_cooldown_seconds Cooldown (seconds) before the same giver can send kudos to the same receiver again. Default one hour; return 0 to disable. int $seconds, int $giver_id, int $receiver_id int cooldown seconds

Submissions

Filter What it filters Parameters Return
wb_gam_submission_daily_cap The per-user daily cap on user-generated-content submissions. Default 5. int $cap int daily cap

Emails and nudges

Filter What it filters Parameters Return
wb_gam_email_enabled Whether a given transactional email type should be sent to a user. bool $enabled, string $slug, int $user_id bool whether to send
wb_gam_email_burst_cap The maximum number of transactional emails of one type sent in a burst window. Default 5. int $cap, string $slug int burst cap
wb_gam_email_from_header The From header used for plugin emails. string $from, string $name, string $email, string $name_option_key string from header
wb_gam_weekly_email_body The rendered body of the weekly summary email before it is sent. string $body, WP_User $user, array $data string email body
wb_gam_should_send_weekly_nudge Whether a weekly leaderboard nudge should be sent to a specific user. bool $should, int $user_id, array $rank_data bool whether to send
wb_gam_nudge_message The leaderboard nudge message before delivery. string $message, int $user_id, int $rank, int $points, ?int $points_to_next string message
wb_gam_recap_data The year-in-review recap data before display. array $recap, int $user_id, int $year array recap data

Integrations

Filter What it filters Parameters Return
wb_gam_as_retention_days Number of days the daily Action Scheduler cleanup keeps actionscheduler_actions rows for, regardless of status. Default 7, minimum 1. Added in 1.4.0. int $days int retention days
wb_gam_activity_context_label The BuddyPress activity context-group label for a gamification activity type. Default is the per-type human label. Added in 1.4.0. string $context, string $key string context label
wb_gam_rank_automation_rules Rank automation rules before they are evaluated. array $rules array rules
wb_gam_activitypub_activity The ActivityPub activity object before it is dispatched for a badge award. array $activity, int $user_id array activity object
wb_gam_grant_member_uploads Whether to bridge the WordPress upload_files capability to logged-in members so the achievement editor's Add Media button works for subscribers/contributors. Default true. bool $grant, WP_User $user bool whether to grant
wb_gam_wpmediaverse_free_triggers The WPMediaVerse free trigger definitions. array $free_triggers array triggers
wb_gam_wpmediaverse_pro_triggers The WPMediaVerse Pro trigger definitions (only when WPMediaVerse Pro is active). array $pro_triggers array triggers
wb_gam_wpmediaverse_triggers The combined WPMediaVerse trigger definitions. array $triggers, bool $pro_active array triggers
wb_gam_defer_leaderboard_to_jetonomy Whether wb-gam suppresses its own leaderboard + top-members blocks/shortcodes (and the Hub leaderboard card) so Jetonomy's reputation ranking is the single leaderboard. Default true when JETONOMY_VERSION is defined, otherwise false. Added in 1.5.2. bool $defer bool whether to defer
wb_gam_learndash_profile_link Whether to add the opt-in "My Achievements" link to the LearnDash profile (links to the mapped Hub page). Default false - return true to enable. Added in 1.5.2. bool $enabled bool whether to show the link
wb_gam_member_surface_html The wrapped member achievements surface markup (BuddyPress Achievements tab, WooCommerce My Account endpoint, etc.) before output, so a host can wrap or augment the surface without duplicating the renderer. Added in 1.5.2. string $html, int $user_id string surface markup

Realtime and notifications

Filter What it filters Parameters Return
wb_gam_sse_allowed Whether the Server-Sent Events long-poll transport may run on this host. Default false - SSE pins a PHP-FPM worker per connection, so it stays off unless the host is provisioned for long-lived streaming. When false, realtime falls back to WP Heartbeat. Added in 1.5.2. bool $allowed bool whether SSE is permitted
wb_gam_toast_position The on-screen corner reward toasts slide in from. Filters the stored wb_gam_toast_position option (Settings > Realtime). One of bottom-right (default), bottom-left, top-right, top-center. Added in 1.5.2. string $position string toast position

Access and modules

Site-owner controls added in 1.5.3 (Settings > Access and Settings > Modules).

Filter What it filters Parameters Return
wb_gam_user_can_earn Whether a user may earn points at all. Fires after the admin earning-exclusion settings (excluded roles, excluded accounts, and the per-user wb_gam_sandboxed veto) are applied, so code can extend or override the owner's choices. Enforced at the single award choke point, so it covers both the sync and async award paths. Added in 1.5.3. bool $can, int $user_id bool whether the user may earn
wb_gam_module_enabled Whether an optional module is enabled. Modules: kudos, streaks, challenges, community_challenges, cohort_leagues, redemption. Default ON; only an explicit '0' in the wb_gam_modules option disables one. A disabled module's blocks and shortcodes render nothing and its admin page is removed (data is preserved). Added in 1.5.3. bool $enabled, string $slug bool whether the module is on

Two related event hooks are actions, not filters. wb_gam_progress_reset (fires after a member-progress reset wipes the progress tables, keeping config) and wb_gam_points_decayed (fires after each inactivity point-decay sweep, with the number of members decayed) are documented in the Actions reference. Listen with add_action(), not add_filter().

Public profiles

Filter What it filters Parameters Return
wb_gam_profile_publicly_visible Whether a member's /u/{user_login} profile page is publicly visible. Default ON (opt-out model): a member is visible unless they set the per-user flag to 0, and the site-wide kill switch still wins. Added in 1.5.2. bool $visible, int $user_id bool whether the profile is public

Admin CRUD (REST)

These fire from the REST controllers behind the admin CRUD screens. Each carries the WP_REST_Request so listeners can inspect or modify the payload before the write.

Filter What it filters Parameters Return
wb_gam_before_create_badge The badge row before it is inserted. array $row, WP_REST_Request $request array row
wb_gam_before_update_badge The badge update payload before it is applied. array $data, array $def, WP_REST_Request $request array data
wb_gam_before_create_level The level payload before it is inserted. array $payload, WP_REST_Request $request array payload
wb_gam_before_update_level The level update payload before it is applied. array $updates, array $current, WP_REST_Request $request array updates
wb_gam_before_create_community_challenge The community challenge payload before it is inserted. array $data, WP_REST_Request $request array data
wb_gam_before_update_community_challenge The community challenge update payload before it is applied. array $updates, array $current, WP_REST_Request $request array updates
wb_gam_before_create_api_key The API key payload before it is created. array $payload, WP_REST_Request $request array payload
wb_gam_before_save_cohort_settings The cohort settings before they are saved. array $settings, bool $enabled, WP_REST_Request $request array settings

Block data filters

Every block exposes a per-block data filter that fires on the data the block is about to render, so extensions can reorder, remove, or add fields without forking the render PHP. Each filter is named wb_gam_block_<slug>_data (or _currencies for the hub). All per-block data filters also receive the block attributes and the resolving user ID as later arguments where the render needs them.

Filter Block What it filters Return
wb_gam_block_leaderboard_data leaderboard Array of {rank, user_id, display_name, points} rows array rows
wb_gam_block_top_members_data top-members Same shape as leaderboard array rows
wb_gam_block_points_history_data points-history Array of {action_id, points, point_type, created_at} rows array rows
wb_gam_block_member_points_data member-points {points, label, level, next_level, progress_pct} map array map
wb_gam_block_hub_currencies hub Array of {slug, label, icon, balance, is_default, convert_rules} tiles array tiles
wb_gam_block_badge_showcase_data badge-showcase Array of {id, name, icon_url, earned, ...} badges array badges
wb_gam_block_challenges_data challenges Array of active challenges for the user array challenges
wb_gam_block_cohort_rank_data cohort-rank Array of cohort standings rows array rows
wb_gam_block_community_challenges_data community-challenges Array of active community challenges array challenges
wb_gam_block_daily_bonus_data daily-bonus Login-bonus state map merged with {today_claimed} array map
wb_gam_block_earning_guide_data earning-guide Category-keyed action map [ category => [{label,icon,points}, ...] ] array map
wb_gam_block_kudos_feed_data kudos-feed Array of recent kudos rows array rows
wb_gam_block_level_progress_data level-progress {points, level, next, pct} map array map
wb_gam_block_redemption_store_data redemption-store Array of reward items array items
wb_gam_block_streak_data streak {streak, heatmap} map array map
wb_gam_block_year_recap_data year-recap Yearly recap aggregates map array map

Universal block filters

These fire on every block, not just one slug.

Filter What it filters Parameters Return
wb_gam_block_data The resolved data array for any block, after the per-block filter. array $data, string $slug, array $attributes array data
wb_gam_block_css The per-instance scoped CSS emitted for a block instance. string $css, string $unique_id, array $attrs string CSS

Lifecycle

Filter What it filters Parameters Return
wb_gam_template_path The resolved template path before a plugin-shipped template is loaded. Return your own path to override a template entirely. string $path, string $relative, array $ctx string template path
wb_gam_manifest_paths The directories scanned for *.php action manifest files. Add a path to register custom action manifests. string[] $paths array directory paths
wb_gam_block_manifests The absolute paths to block.json files discovered during block registration. array $manifests array manifest paths

Usage examples (1.5.2 filters)

// Force-show wb-gam's own leaderboard even when Jetonomy is active
// (default is to defer to Jetonomy's reputation ranking).
add_filter( 'wb_gam_defer_leaderboard_to_jetonomy', '__return_false' );

// Opt the LearnDash profile "My Achievements" link in (default off).
add_filter( 'wb_gam_learndash_profile_link', '__return_true' );

// Add a heading above every member achievements surface.
add_filter(
	'wb_gam_member_surface_html',
	static function ( string $html, int $user_id ): string {
		return '<h2>' . esc_html__( 'Your progress', 'my-textdomain' ) . '</h2>' . $html;
	},
	10,
	2
);

// Enable the SSE long-poll transport (only on a host built for it).
add_filter( 'wb_gam_sse_allowed', '__return_true' );

// Move reward toasts to the top-right corner for everyone, ignoring the
// admin Settings > Realtime selection.
add_filter(
	'wb_gam_toast_position',
	static function (): string {
		return 'top-right';
	}
);

// Hide a specific member's public /u/ profile regardless of their flag.
add_filter(
	'wb_gam_profile_publicly_visible',
	static function ( bool $visible, int $user_id ): bool {
		return 42 === $user_id ? false : $visible;
	},
	10,
	2
);

REST API Overview

WB Gamification ships a full REST API under a single namespace. Every endpoint in this guide lives beneath that base URL.

Base URL

/wp-json/wb-gamification/v1/

A full machine-readable spec is served at the namespace root:

curl https://example.com/wp-json/wb-gamification/v1/

Authentication

Two authentication methods are supported. Public read endpoints (catalogs, leaderboard, OG share pages, OpenBadges credentials, the capabilities discovery endpoint) need no credentials at all.

Method How When to use
Cookie + nonce Standard X-WP-Nonce header Same-site JavaScript requests
API key X-WB-Gam-Key header or ?api_key= query param Remote sites, mobile apps, Zapier/Make

See Cross-Site API for API key creation and remote site setup.

curl https://example.com/wp-json/wb-gamification/v1/members/42 \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

API key (remote)

curl https://example.com/wp-json/wb-gamification/v1/leaderboard \
  -H "X-WB-Gam-Key: YOUR_API_KEY"

Or as a query parameter:

curl "https://example.com/wp-json/wb-gamification/v1/leaderboard?api_key=YOUR_API_KEY"

List Envelope Shape

Paginated list endpoints return a count plus the rows for the current page. The total count is also exposed in response headers so clients can build pagination without parsing the body.

Header Meaning
X-WP-Total Total number of rows across all pages
X-WP-TotalPages Total number of pages at the current per_page

Standard list query parameters:

Parameter Type Default Description
page int 1 Page number
per_page int 20 Rows per page (max 100)

Example list body (points history):

{
  "total": 1250,
  "history": [
    {
      "id": 99,
      "event_id": "uuid",
      "action_id": "publish_post",
      "points": 10,
      "object_id": 55,
      "created_at": "2026-03-18 12:00:00"
    }
  ]
}

Error Format

All errors use the standard WordPress REST error envelope.

{
  "code": "rest_forbidden",
  "message": "You do not have permission to manage points.",
  "data": { "status": 403 }
}
Status Meaning
400 Bad request. Missing or invalid parameters
401 Not authenticated
403 Insufficient capability
404 Resource not found
410 Gone. Credential has expired
422 Unprocessable. Business rule violation (e.g. kudos daily limit)

Making a Request

A complete authenticated read against a member profile:

curl https://example.com/wp-json/wb-gamification/v1/members/42 \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."
{
  "id": 42,
  "display_name": "Jane Smith",
  "points": 1250,
  "level": { "id": 3, "name": "Contributor", "progress_pct": 75 },
  "badges_count": 8
}

From here, the API is split across focused reference pages:

Members and Points

Endpoints for member profiles, the points ledger, point types, and currency conversions. Base URL is /wp-json/wb-gamification/v1/. See REST API Overview for authentication and error formats.

Members

Method Endpoint Permission
GET /members/{id} Public (full private data for self or admin)
GET /members/{id}/points Self or admin
GET /members/{id}/level Public
GET /members/{id}/badges Public
GET /members/{id}/events Self or admin
GET /members/{id}/streak Public
GET /members/me/toasts Must be logged in

GET /members/{id}

Full gamification profile for one member. Unauthenticated requests return public data only; self or admin returns full private data.

curl https://example.com/wp-json/wb-gamification/v1/members/42 \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."
{
  "id": 42,
  "display_name": "Jane Smith",
  "avatar_url": "https://...",
  "points": 1250,
  "points_by_type": { "default": 1250 },
  "level": {
    "id": 3,
    "name": "Contributor",
    "min_points": 500,
    "progress_pct": 75,
    "next_threshold": 1500,
    "next_level_name": "Regular"
  },
  "badges_count": 8,
  "preferences": {
    "show_rank": true,
    "leaderboard_opt_out": false,
    "notification_mode": "smart"
  }
}

GET /members/{id}/points

Paginated points history for a member.

Parameter Type Default Description
page int 1 Page number
per_page int 20 Rows per page (max 100)

Response headers: X-WP-Total, X-WP-TotalPages.

curl "https://example.com/wp-json/wb-gamification/v1/members/42/points?per_page=20" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."
{
  "total": 1250,
  "history": [
    {
      "id": 99,
      "event_id": "uuid",
      "action_id": "publish_post",
      "points": 10,
      "object_id": 55,
      "created_at": "2026-03-18 12:00:00"
    }
  ]
}

GET /members/{id}/level

Current level and full level ladder with progress.

GET /members/{id}/badges

All badges earned by the member, ordered by earned_at descending.

GET /members/{id}/events

Paginated raw event log.

Parameter Type Default Description
page int 1 Page number
per_page int 20 Rows per page (max 100)

GET /members/{id}/streak

Streak data with an optional contribution heatmap.

Parameter Type Default Description
heatmap_days int 0 Include N days of contribution data. 0 = skip

GET /members/me/toasts

Read and flush pending toast notifications for the current user. Requires authentication.

curl https://example.com/wp-json/wb-gamification/v1/members/me/toasts \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

Points

Method Endpoint Permission
POST /points/award manage_options or wb_gam_award_manual
DELETE /points/{id} manage_options

POST /points/award

Manually award points to a member. Bypasses cooldown and cap checks.

Field Type Required Description
user_id int Yes Target user ID
points int Yes Points to award (1 to 100,000)
reason string No Action ID label. Default manual_award
note string No Admin note stored in event metadata
curl -X POST https://example.com/wp-json/wb-gamification/v1/points/award \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "user_id": 42, "points": 100, "reason": "manual_award" }'
{ "awarded": true, "user_id": 42, "points": 100, "reason": "manual_award" }

Returns HTTP 201 on success.

DELETE /points/{id}

Revoke a specific points ledger row. The event record is preserved (events are immutable); only the points side-effect is removed.

curl -X DELETE https://example.com/wp-json/wb-gamification/v1/points/99 \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."
{ "deleted": true, "id": 99, "user_id": 42, "points": 10 }

Point Types

Multi-currency support. Each site can define several point types (e.g. XP, coins, gems) with one default.

Method Endpoint Permission
GET /point-types Public
POST /point-types manage_options
POST PUT PATCH /point-types/{slug} manage_options
DELETE /point-types/{slug} manage_options
POST /point-types/{from}/convert Must be logged in

POST /point-types

Create a point type.

Field Type Required Description
slug string Yes Machine slug for the currency
label string Yes Display label
description string No Description shown in admin
icon string No Icon identifier
is_default boolean No Mark as the site default currency
position int No Sort order
curl -X POST https://example.com/wp-json/wb-gamification/v1/point-types \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "slug": "coins", "label": "Coins", "is_default": false }'

POST /point-types/{from}/convert

Convert a member's balance from one currency to another. The conversion is atomic: a debit and a credit ledger row share one event ID.

Field Type Required Description
to_type string Yes Target currency slug
amount int Yes Amount of the source currency to convert
curl -X POST https://example.com/wp-json/wb-gamification/v1/point-types/coins/convert \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "to_type": "gems", "amount": 100 }'

Point Type Conversions

Conversion rules that define exchange rates and limits between point types.

Method Endpoint Permission
GET /point-type-conversions Public
POST /point-type-conversions manage_options
POST PUT PATCH /point-type-conversions/{id} manage_options
DELETE /point-type-conversions/{id} manage_options

POST /point-type-conversions

Define a conversion rate between two currencies.

Field Type Required Description
from_type string Yes Source currency slug
to_type string Yes Target currency slug
from_amount int Yes Source units in the exchange ratio
to_amount int Yes Target units in the exchange ratio
min_convert int No Minimum amount per conversion
cooldown_seconds int No Minimum seconds between conversions
max_per_day int No Daily conversion cap per user
is_active boolean No Whether the rule is enabled
curl -X POST https://example.com/wp-json/wb-gamification/v1/point-type-conversions \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "from_type": "coins", "to_type": "gems", "from_amount": 100, "to_amount": 1 }'

Badges, Levels, Leaderboard, Recap

Endpoints for badge definitions, the level ladder, leaderboards, and year-in-review recap data. Base URL is /wp-json/wb-gamification/v1/. See REST API Overview for authentication and error formats.

Badges

Method Endpoint Permission
GET /badges Public
POST /badges manage_options
GET /badges/{id} Public
PUT PATCH /badges/{id} manage_options
DELETE /badges/{id} manage_options
POST /badges/{id}/award manage_options

GET /badges

All badge definitions with optional earned status and rarity scores.

Parameter Type Default Description
user_id int current user Include earned status for this user. 0 = skip
category string (none) Filter by category slug
curl "https://example.com/wp-json/wb-gamification/v1/badges?category=writing"

GET /badges/{id}

Single badge definition with rarity percentage and earner count.

curl https://example.com/wp-json/wb-gamification/v1/badges/top_contributor

PUT /badges/{id}

Update badge definition fields (name, description, image_url, category).

curl -X PUT https://example.com/wp-json/wb-gamification/v1/badges/top_contributor \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "name": "Top Contributor", "description": "Earned for outstanding contributions." }'

DELETE /badges/{id}

Delete a badge definition. Cascades to wb_gam_user_badges and associated rules.

POST /badges/{id}/award

Manually award a badge to a user.

Field Type Required Description
user_id int Yes Target user ID
curl -X POST https://example.com/wp-json/wb-gamification/v1/badges/top_contributor/award \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "user_id": 42 }'
{
  "awarded": true,
  "badge_id": "top_contributor",
  "user_id": 42,
  "message": "Badge awarded successfully."
}

Levels

Method Endpoint Permission
GET /levels Public
POST /levels manage_options
PUT PATCH /levels/{id} manage_options
DELETE /levels/{id} manage_options

GET /levels

All configured levels with thresholds and icons.

curl https://example.com/wp-json/wb-gamification/v1/levels

POST /levels

Create a level. Requires manage_options.

curl -X POST https://example.com/wp-json/wb-gamification/v1/levels \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "name": "Regular", "threshold": 1500 }'

Leaderboard

Method Endpoint Permission
GET /leaderboard Public (opt-out members excluded)
GET /leaderboard/group/{group_id} Public
GET /leaderboard/me Must be logged in

GET /leaderboard

Top-N members for a given period. Opt-out members are excluded from results.

Parameter Type Default Description
period string all all, month, week, day
limit int 10 1 to 100
scope_type string (none) Scope type (e.g. bp_group)
scope_id int 0 Scope object ID
curl "https://example.com/wp-json/wb-gamification/v1/leaderboard?period=week&limit=10"
{
  "period": "week",
  "scope": { "type": "", "id": 0 },
  "rows": [
    {
      "rank": 1,
      "user_id": 42,
      "display_name": "Jane Smith",
      "avatar_url": "https://...",
      "points": 320
    }
  ]
}

GET /leaderboard/group/{group_id}

BuddyPress group-scoped leaderboard. Accepts the same period and limit parameters.

curl "https://example.com/wp-json/wb-gamification/v1/leaderboard/group/7?period=month"

GET /leaderboard/me

Current user's private rank, visible even when opted out of public display. Requires login.

curl https://example.com/wp-json/wb-gamification/v1/leaderboard/me \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

Recap

Method Endpoint Permission
GET /members/{id}/recap Self or admin

GET /members/{id}/recap

Year-in-review recap data for a member: points earned, badges unlocked, top actions, and milestones over the period.

curl https://example.com/wp-json/wb-gamification/v1/members/42/recap \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

Challenges, Kudos, Submissions, Redemption

Endpoints for individual challenges, community challenges, peer kudos, the UGC submission queue, and the rewards redemption store. Base URL is /wp-json/wb-gamification/v1/. See REST API Overview for authentication and error formats.

Challenges

Individual, per-member challenges that track progress toward a target action.

Method Endpoint Permission
GET /challenges Public
POST /challenges manage_options
GET /challenges/{id} Public
PUT PATCH /challenges/{id} manage_options
DELETE /challenges/{id} manage_options
POST /challenges/{id}/complete Must be logged in

POST /challenges

Create a challenge.

Field Type Required Description
title string Yes Challenge title
description string No Description shown to members
action_id string Yes Action that advances the challenge
target int No Number of action occurrences to complete
bonus_points int No Points awarded on completion
starts_at string No ISO start datetime
ends_at string No ISO end datetime
curl -X POST https://example.com/wp-json/wb-gamification/v1/challenges \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "title": "Week of Learning", "action_id": "ld_lesson_complete", "target": 5, "bonus_points": 100 }'

PUT /challenges/{id}

Update a challenge. Accepts title, action_id, target, bonus_points, starts_at, ends_at, status.

POST /challenges/{id}/complete

Mark a challenge complete for the current user.

Field Type Required Description
id int Yes Challenge ID
curl -X POST https://example.com/wp-json/wb-gamification/v1/challenges/7/complete \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "id": 7 }'

Community Challenges

Group-wide challenges where members contribute toward a shared target count.

Method Endpoint Permission
GET /community-challenges Public
POST /community-challenges manage_options
GET /community-challenges/{id} Public
PUT PATCH /community-challenges/{id} manage_options
DELETE /community-challenges/{id} manage_options

POST /community-challenges

Create a community challenge.

Field Type Required Description
title string Yes Challenge title
description string No Description shown to members
target_count int Yes Total contributions needed to complete
target_action string No Action that contributes to the count
bonus_points int No Bonus awarded to participants on completion
starts_at string No ISO start datetime
ends_at string No ISO end datetime
status string No Challenge status
curl -X POST https://example.com/wp-json/wb-gamification/v1/community-challenges \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "title": "1000 Posts Together", "target_count": 1000, "target_action": "publish_post", "bonus_points": 50 }'

Kudos

Peer-to-peer recognition with a per-user daily limit.

Method Endpoint Permission
GET /kudos Public
POST /kudos Must be logged in
GET /kudos/me Must be logged in

GET /kudos

Recent kudos feed.

Parameter Type Default Description
limit int 20 Max entries (1 to 50)
curl "https://example.com/wp-json/wb-gamification/v1/kudos?limit=20"

POST /kudos

Give kudos to another member. One of receiver_id or recipient_login is required.

Field Type Required Description
receiver_id int conditional User ID of recipient
recipient_login string conditional Added in 1.4.0. User login (username) or email of recipient, resolved server-side. Use this when the giver does not know the recipient's user ID (e.g. the [wb_gam_give_kudos] shortcode)
message string No Optional message (max 255 chars)
curl -X POST https://example.com/wp-json/wb-gamification/v1/kudos \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "receiver_id": 55, "message": "Great work on the docs!" }'
{ "success": true, "receiver_id": 55, "daily_remaining": 4 }

Returns HTTP 201 on success.

GET /kudos/me

Current user's kudos stats: received_total, daily_limit, sent_today, daily_remaining.

curl https://example.com/wp-json/wb-gamification/v1/kudos/me \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

Submissions

The user-generated-content submission queue. Members submit evidence of an achievement; admins approve or reject. Approval routes through the points engine so badges, levels, and totals stay consistent.

Method Endpoint Permission
GET /submissions manage_options
POST /submissions Must be logged in
POST /submissions/{id}/approve manage_options
POST /submissions/{id}/reject manage_options

POST /submissions

Submit an achievement for review. A daily cap applies per user.

Field Type Required Description
action_id string Yes Action the submission claims
evidence string No Text description of the evidence
evidence_url string No URL pointing to evidence
curl -X POST https://example.com/wp-json/wb-gamification/v1/submissions \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "action_id": "external_talk", "evidence": "Spoke at WordCamp", "evidence_url": "https://..." }'

GET /submissions

List submissions for review.

Parameter Type Default Description
status string (all) Filter by status
per_page int 50 Rows per page (max 100)

POST /submissions/{id}/approve

Approve a submission. Optional notes field is stored with the decision.

curl -X POST https://example.com/wp-json/wb-gamification/v1/submissions/12/approve \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "notes": "Verified against the conference schedule." }'

POST /submissions/{id}/reject

Reject a submission. Optional notes field is stored with the decision.

curl -X POST https://example.com/wp-json/wb-gamification/v1/submissions/12/reject \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "notes": "Could not verify the claim." }'

Redemption

The rewards store. Members spend points on catalog items; admins manage the catalog.

Method Endpoint Permission
POST /redemptions Must be logged in
GET /redemptions/items Public
POST /redemptions/items manage_options
GET POST PUT PATCH DELETE /redemptions/items/{id} manage_options (write), public (read)
GET /redemptions/me Must be logged in

POST /redemptions

Redeem a catalog item with the current user's points.

Field Type Required Description
item_id int Yes Catalog item to redeem
curl -X POST https://example.com/wp-json/wb-gamification/v1/redemptions \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "item_id": 3 }'

POST /redemptions/items

Create a catalog item.

Field Type Required Description
title string Yes Item title
description string No Item description
points_cost int Yes Points required to redeem
point_type string No Currency slug the cost is charged in
reward_type string Yes Reward fulfilment type
reward_config object No Type-specific reward configuration
stock int No Available stock
is_active boolean No Whether the item is purchasable
curl -X POST https://example.com/wp-json/wb-gamification/v1/redemptions/items \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "title": "Sticker Pack", "points_cost": 500, "reward_type": "manual", "stock": 100 }'

GET /redemptions/me

Current user's redemption history.

curl https://example.com/wp-json/wb-gamification/v1/redemptions/me \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

Admin: Rules, Webhooks, API Keys, Actions, Capabilities

Administrative endpoints for managing rules, outbound webhooks, API keys, action configuration, and the capabilities discovery endpoint. Base URL is /wp-json/wb-gamification/v1/. See REST API Overview for authentication and error formats. Most endpoints here require the manage_options capability.

Actions

Registered gamification actions with their labels, point values, and rate-limit configuration.

Method Endpoint Permission
GET /actions manage_options
GET /actions/{id} Public
POST /actions/{id}/overrides manage_options
PUT DELETE /actions/{id}/overrides manage_options

GET /actions

All registered gamification actions with labels, categories, point values, and enabled state.

curl https://example.com/wp-json/wb-gamification/v1/actions \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

GET /actions/{id}

A single action by ID, with all admin overrides applied to cooldown, daily_cap, and weekly_cap.

curl https://example.com/wp-json/wb-gamification/v1/actions/bp_activity_update

POST /actions/{id}/overrides

Added in 1.4.0. Set per-action overrides for cooldown, daily_cap, and weekly_cap without touching the manifest. Stored in the wb_gam_action_overrides site option, keyed by action ID. The engine reads these on every rate-limit check, so the override takes effect immediately for new awards. All fields are optional; omit a field to leave it unchanged.

Field Type Description
cooldown int (>= 0) Minimum seconds between awards. 0 disables the cooldown
daily_cap int (>= 0) Daily cap per user per action. 0 allows unlimited
weekly_cap int (>= 0) Weekly cap per user per action. 0 allows unlimited
curl -X POST https://example.com/wp-json/wb-gamification/v1/actions/bp_activity_update/overrides \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "cooldown": 120, "daily_cap": 5 }'
{
  "action_id": "bp_activity_update",
  "overrides": { "cooldown": 120, "daily_cap": 5 },
  "effective": { "cooldown": 120, "daily_cap": 5, "weekly_cap": 0 }
}

DELETE /actions/{id}/overrides

Added in 1.4.0. Reset overrides for one action. The next read falls back to the manifest values.

curl -X DELETE https://example.com/wp-json/wb-gamification/v1/actions/bp_activity_update/overrides \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."
{ "action_id": "bp_activity_update", "reset": true }

Rules

Stored rule configurations (badge conditions, point multipliers, level thresholds).

Method Endpoint Permission
GET /rules manage_options
POST /rules manage_options
GET POST PUT PATCH DELETE /rules/{id} manage_options
curl https://example.com/wp-json/wb-gamification/v1/rules \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

Webhooks

Outbound webhook registrations. See the Webhooks Overview for payload shapes, signing, and retries.

Method Endpoint Permission
GET /webhooks manage_options
POST /webhooks manage_options
GET PUT DELETE /webhooks/{id} manage_options
GET /webhooks/{id}/log manage_options
DELETE /webhooks/{id}/log manage_options

POST /webhooks

Register a new webhook. The response includes the generated secret, which is only returned on creation. Store it securely.

Field Type Required Description
url string Yes Destination URL for delivery
events array Yes Event names to subscribe to
secret string No Custom signing secret. Generated if omitted
curl -X POST https://example.com/wp-json/wb-gamification/v1/webhooks \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{
    "url": "https://hooks.zapier.com/hooks/catch/123/abc/",
    "events": ["points_awarded", "badge_earned", "level_changed"]
  }'

GET /webhooks/{id}/log

Inspect delivery attempts for a webhook. A status_code of 0 indicates a connection-level failure (DNS, timeout).

curl https://example.com/wp-json/wb-gamification/v1/webhooks/1/log \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."
{
  "webhook_id": 1,
  "entries": [
    { "event": "points_awarded", "status_code": 200, "success": true, "timestamp": "2026-04-12 14:30:05" },
    { "event": "badge_earned", "status_code": 0, "success": false, "timestamp": "2026-04-12 14:29:58" }
  ],
  "count": 2
}

API Keys

Keys for remote-site and mobile-app authentication. See Cross-Site API for the full remote setup flow.

Method Endpoint Permission
GET /api-keys manage_options
POST /api-keys manage_options
DELETE /api-keys/{id} manage_options
POST PUT PATCH /api-keys/{id}/revoke manage_options

POST /api-keys

Create an API key. The full key value is returned only once on creation.

Field Type Required Description
label string Yes Human-readable key label
site_id string No Identifier for the remote site this key serves
curl -X POST https://example.com/wp-json/wb-gamification/v1/api-keys \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "label": "Mobile app", "site_id": "ios-prod" }'

POST /api-keys/{id}/revoke

Revoke a key without deleting its record. Revoked keys stop authenticating immediately.

curl -X POST https://example.com/wp-json/wb-gamification/v1/api-keys/5/revoke \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

Capabilities

Discovery endpoint for mobile apps and remote sites. Returns authentication status, a permissions map, feature flags, plugin version, and all endpoint URLs.

Method Endpoint Permission
GET /capabilities Public
curl https://example.com/wp-json/wb-gamification/v1/capabilities \
  -H "X-WB-Gam-Key: YOUR_API_KEY"
{
  "authenticated": true,
  "user_id": 42,
  "site_id": "",
  "mode": "local",
  "can": {
    "read_leaderboard": true,
    "award_points": false,
    "give_kudos": true
  },
  "features": { "cohort_leagues": false },
  "version": "1.0.0",
  "endpoints": {
    "members": "https://example.com/wp-json/wb-gamification/v1/members",
    "leaderboard": "https://example.com/wp-json/wb-gamification/v1/leaderboard"
  }
}

Events

Site-wide raw event log with filtering.

Method Endpoint Permission
POST /events manage_options
GET /events/stream manage_options

The /events/stream endpoint is a Server-Sent Events stream of live events for admin dashboards.

curl https://example.com/wp-json/wb-gamification/v1/events/stream \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

Members roster

Site-owner member management (Gamification > Members). Added in 1.5.3. All admin-only.

Method Endpoint Permission
GET /members manage_options
POST /members/{id}/exclude manage_options
POST /members/{id}/reset-points manage_options

GET /members

A paginated, searchable roster of every member with their points, level, and badges. The query primes points and badges per page so the listing stays N+1-free. Each row reports whether the member is currently excluded from earning.

Field Type Description
page int Page number. Default 1
per_page int Rows per page. Default 20, max 100
search string Match against username, display name, email, and nicename
curl "https://example.com/wp-json/wb-gamification/v1/members?search=jane&per_page=20" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

POST /members/{id}/exclude

Toggle the per-user earning veto (wb_gam_sandboxed meta). An excluded member keeps their points but stops earning and is hidden from leaderboards.

Field Type Required Description
excluded boolean No true to exclude (default), false to include
curl -X POST https://example.com/wp-json/wb-gamification/v1/members/42/exclude \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "excluded": true }'

POST /members/{id}/reset-points

Zero a member's balance. The reset is recorded as a balancing debit so the points ledger keeps a full audit trail.

curl -X POST https://example.com/wp-json/wb-gamification/v1/members/42/reset-points \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."
{ "user_id": 42, "reset_from": 1200, "new_balance": 0 }

Bulk award

Award the same points to a whole role or to all members at once. Added in 1.5.3.

Method Endpoint Permission
POST /points/bulk manage_options

POST /points/bulk

Routes through the exclusion-aware batch award, so accounts excluded in Settings > Access are skipped automatically. Points must be positive.

Field Type Required Description
target string Yes all for every member, or a role slug
points int Yes Points to grant each member (1 to 100000)
point_type string No Currency slug. Defaults to the primary currency
curl -X POST https://example.com/wp-json/wb-gamification/v1/points/bulk \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "target": "all", "points": 50 }'
{ "awarded": 318, "target": "all", "points": 50 }

Tools

Settings portability and maintenance (Settings > Tools). Added in 1.5.3. All admin-only.

Method Endpoint Permission
GET /tools/export-settings manage_options
POST /tools/import-settings manage_options
POST /tools/recompute-leaderboard manage_options
POST /tools/reset-progress manage_options

GET /tools/export-settings

Download the plugin configuration as a JSON document of every wb_gam_* configuration option. Runtime, derived, and schema state (database version, feature schema gates, caches, snapshots, flush markers, wizard flags) is deliberately excluded so an import never corrupts the target site.

curl https://example.com/wp-json/wb-gamification/v1/tools/export-settings \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

POST /tools/import-settings

Apply a document produced by export-settings. Only keys that start with wb_gam_ and are not on the exclusion list are written.

Field Type Required Description
document object Yes A document produced by export-settings

POST /tools/recompute-leaderboard

Rebuild the leaderboard snapshot and clear its caches. This is the admin equivalent of wp wb-gamification doctor --recompute-leaderboard.

curl -X POST https://example.com/wp-json/wb-gamification/v1/tools/recompute-leaderboard \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

POST /tools/reset-progress

Permanently clear all member progress (points, events, totals, earned badges, streaks, kudos, leaderboard cache, challenge logs, cohort membership, community-challenge contributions, redemptions, submissions, and per-user progress meta) while keeping every configuration and definition. Requires confirm: true on top of the admin capability check; the call is rejected without it.

Field Type Required Description
confirm boolean Yes Must be true. The reset is rejected otherwise
curl -X POST https://example.com/wp-json/wb-gamification/v1/tools/reset-progress \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{ "confirm": true }'

Outbound Webhooks Overview

WB Gamification can notify external services whenever gamification events occur. Configure a destination URL, subscribe to the events you care about, and the plugin sends an HMAC-signed JSON POST for every matching event.

Webhooks are ideal for connecting to automation platforms like Zapier, Make (Integromat), or n8n.

Registering a Webhook

Webhooks are managed through the REST API under /wp-json/wb-gamification/v1/webhooks. All webhook endpoints require the manage_options capability. See Admin REST endpoints for the full endpoint table.

Method Endpoint Description
GET /webhooks List all webhooks
POST /webhooks Register a new webhook
GET /webhooks/{id} Get a single webhook
PUT /webhooks/{id} Update a webhook
DELETE /webhooks/{id} Delete a webhook
GET /webhooks/{id}/log View delivery log
DELETE /webhooks/{id}/log Clear delivery log

Create a webhook

curl -X POST https://example.com/wp-json/wb-gamification/v1/webhooks \
  -H "Content-Type: application/json" \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..." \
  -d '{
    "url": "https://hooks.zapier.com/hooks/catch/123/abc/",
    "events": ["points_awarded", "badge_earned", "level_changed"]
  }'

The response includes the secret. Store it securely. It is only returned on creation.

Field Type Required Description
url string Yes Destination URL for delivery
events array Yes Event names to subscribe to
secret string No Custom signing secret. Generated if omitted

For the full list of subscribable events and their payload fields, see the Webhook Events Reference.

Payload Shape

Every webhook delivery is an HTTP POST with Content-Type: application/json. The body follows this structure:

{
  "event": "points_awarded",
  "site_url": "https://community.example.com",
  "timestamp": "2026-04-12T14:30:00Z",
  "user_id": 42,
  "user_email": "jane@example.com",
  "data": {
    "action_id": "bp_new_activity",
    "event_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "points": 10
  }
}
Field Type Description
event string The event type that fired
site_url string Origin site URL
timestamp string ISO 8601 UTC timestamp of the event
user_id int ID of the user the event concerns
user_email string Email of that user
data object Event-specific fields. See the events reference

Headers Sent

Every webhook delivery includes these custom headers:

Header Value Purpose
Content-Type application/json Payload format
X-WB-Gam-Signature sha256=<hex> HMAC-SHA256 signature for verification
X-WB-Gam-Site https://your-site.com Origin site URL, useful for multi-site setups

Signing and Verification

Every delivery includes an X-WB-Gam-Signature header:

X-WB-Gam-Signature: sha256=<hex-encoded HMAC-SHA256>

The HMAC is computed over the raw JSON body using the webhook secret as the key. Always verify the signature before processing the payload.

PHP

$secret    = 'your_webhook_secret_here';
$payload   = file_get_contents( 'php://input' );
$header    = $_SERVER['HTTP_X_WB_GAM_SIGNATURE'] ?? '';
$expected  = 'sha256=' . hash_hmac( 'sha256', $payload, $secret );

if ( ! hash_equals( $expected, $header ) ) {
    http_response_code( 401 );
    exit( 'Invalid signature.' );
}

$data = json_decode( $payload, true );
// Process $data...

Node.js

const crypto = require('crypto');

function verifyWebhook(req, secret) {
  const payload   = JSON.stringify(req.body);
  const signature = req.headers['x-wb-gam-signature'] || '';
  const expected  = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload, 'utf8')
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

// Express middleware example
app.post('/webhook', express.json({ verify: (req, res, buf) => {
  req.rawBody = buf;
}}), (req, res) => {
  const payload   = req.rawBody.toString('utf8');
  const signature = req.headers['x-wb-gam-signature'] || '';
  const expected  = 'sha256=' + crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(payload, 'utf8')
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
    return res.status(401).send('Invalid signature');
  }

  console.log('Event:', req.body.event, 'User:', req.body.user_id);
  res.status(200).send('OK');
});

Python

import hmac
import hashlib

def verify_webhook(body: bytes, header: str, secret: str) -> bool:
    expected = 'sha256=' + hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)

Retries

Failed deliveries (HTTP errors or status codes >= 400) are retried automatically up to 3 times using exponential back-off.

Attempt Delay
1st retry 2 minutes
2nd retry 4 minutes
3rd retry 8 minutes

Retries are scheduled via Action Scheduler, so they survive page loads and cron interruptions. After 3 failed retries the delivery is abandoned and logged.

Delivery Log

Every delivery attempt (success or failure) is recorded. Inspect it via the REST API:

curl https://example.com/wp-json/wb-gamification/v1/webhooks/1/log \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."
{
  "webhook_id": 1,
  "entries": [
    { "event": "points_awarded", "status_code": 200, "success": true, "timestamp": "2026-04-12 14:30:05" },
    { "event": "badge_earned", "status_code": 0, "success": false, "timestamp": "2026-04-12 14:29:58" }
  ],
  "count": 2
}

A status_code of 0 indicates a connection-level failure (DNS, timeout). To clear the log:

curl -X DELETE https://example.com/wp-json/wb-gamification/v1/webhooks/1/log \
  -H "X-WP-Nonce: YOUR_NONCE" \
  --cookie "wordpress_logged_in_xxx=..."

Platform Setup Guides

Zapier

  1. Create a new Zap and choose Webhooks by Zapier as the trigger.
  2. Select Catch Hook and copy the webhook URL (starts with https://hooks.zapier.com/).
  3. In WordPress admin, go to Gamification > Settings > API and register the webhook URL with your desired events.
  4. Copy the returned secret for signature verification (optional in Zapier but recommended).
  5. Send a test event from WB Gamification and check the Zap trigger for the payload.
  6. Add your action steps (send email, update Google Sheet, post to Slack, etc.).

Make (Integromat)

  1. Create a new Scenario and add a Webhooks > Custom Webhook module.
  2. Click Add to create a new webhook and copy the URL.
  3. Register the URL in WB Gamification with the events you want.
  4. Click Run once in Make, then trigger an event from your site.
  5. Make detects the payload structure automatically. Map the fields to your next module.
  6. To verify signatures, use a Tools > Set variable module with sha256= plus the HMAC-SHA256 of the body, then compare with the X-WB-Gam-Signature header.

n8n

  1. Add a Webhook node to your workflow.
  2. Set the HTTP Method to POST and copy the production webhook URL.
  3. Register the URL in WB Gamification with your desired event subscriptions.
  4. To verify signatures, add a Code node after the Webhook node:
const crypto = require('crypto');
const secret  = $env.WEBHOOK_SECRET;
const payload = JSON.stringify($input.first().json);
const sig     = $input.first().headers['x-wb-gam-signature'];
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(payload).digest('hex');

if (sig !== expected) {
  throw new Error('Invalid webhook signature');
}

return $input.all();
  1. Connect subsequent nodes to process the event data (send notifications, update CRM, trigger workflows, etc.).

Webhook Events Reference

Every event type WB Gamification can deliver to a registered webhook, with the fields carried in the data object. For the envelope shape, signing, and retry behaviour, see the Webhooks Overview.

Event Summary

Event Fired When Key data Fields
points_awarded A user earns points from any action action_id, event_id, points
badge_earned A badge rule is satisfied and awarded badge_id, badge_name
level_changed A user's level increases after earning points new_level_id, new_level_name, old_level_id, old_level_name
streak_milestone A user hits a streak milestone (7, 14, 30... days) streak_days
challenge_completed A user finishes an individual challenge challenge_id, challenge_name
kudos_given A user sends peer kudos receiver_id, message

Subscribe to any combination of these event names when registering a webhook via POST /webhooks.

points_awarded

Fired whenever a user earns points from any action.

data Field Type Description
action_id string The action that triggered the award
event_id string UUID of the immutable event record
points int Points awarded
{
  "event": "points_awarded",
  "site_url": "https://community.example.com",
  "timestamp": "2026-04-12T14:30:00Z",
  "user_id": 42,
  "user_email": "jane@example.com",
  "data": {
    "action_id": "bp_new_activity",
    "event_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "points": 10
  }
}

badge_earned

Fired when a badge rule is satisfied and the badge is awarded.

data Field Type Description
badge_id string Slug of the earned badge
badge_name string Display name of the badge
{
  "event": "badge_earned",
  "site_url": "https://community.example.com",
  "timestamp": "2026-04-12T14:30:00Z",
  "user_id": 42,
  "user_email": "jane@example.com",
  "data": {
    "badge_id": "first_post",
    "badge_name": "First Post"
  }
}

level_changed

Fired when a user's level increases after earning points.

data Field Type Description
new_level_id int ID of the level just reached
new_level_name string Name of the new level
old_level_id int ID of the previous level
old_level_name string Name of the previous level
{
  "event": "level_changed",
  "site_url": "https://community.example.com",
  "timestamp": "2026-04-12T14:31:00Z",
  "user_id": 42,
  "user_email": "jane@example.com",
  "data": {
    "new_level_id": 3,
    "new_level_name": "Expert",
    "old_level_id": 2,
    "old_level_name": "Contributor"
  }
}

streak_milestone

Fired when a user hits a streak milestone (7, 14, 30... days).

data Field Type Description
streak_days int Number of consecutive days reached
{
  "event": "streak_milestone",
  "site_url": "https://community.example.com",
  "timestamp": "2026-04-12T08:00:00Z",
  "user_id": 42,
  "user_email": "jane@example.com",
  "data": {
    "streak_days": 30
  }
}

challenge_completed

Fired when a user finishes an individual challenge.

data Field Type Description
challenge_id int ID of the completed challenge
challenge_name string Name of the challenge
{
  "event": "challenge_completed",
  "site_url": "https://community.example.com",
  "timestamp": "2026-04-12T16:45:00Z",
  "user_id": 42,
  "user_email": "jane@example.com",
  "data": {
    "challenge_id": 7,
    "challenge_name": "Week of Learning"
  }
}

kudos_given

Fired when a user sends peer kudos. Here user_id is the giver and data.receiver_id is the recipient.

data Field Type Description
receiver_id int User ID of the kudos recipient
message string Optional message attached to the kudos
{
  "event": "kudos_given",
  "site_url": "https://community.example.com",
  "timestamp": "2026-04-12T12:00:00Z",
  "user_id": 15,
  "user_email": "bob@example.com",
  "data": {
    "receiver_id": 42,
    "message": "Great contribution to the forum!"
  }
}

Something unclear? Open a support ticket →

Buy WB Gamification