OEngage v1.0.0
Comprehensive WordPress user registration, authentication, and engagement — custom auth pages, social login, magic links, 2FA, gamification, badges, and a persistent utility bar.
What OEngage does
Replaces the default WordPress login and register system with a modern, fully-featured alternative — and layers gamification and community features on top.
Getting installed
oengage folder to /wp-content/plugins/.Requirements
Plugin architecture
10 database tables
All prefixed with {prefix}or_. Created on activation.
| Table | Purpose |
|---|---|
or_activity | Every XP-earning action per user — action key, object ID, XP earned, JSON data, timestamp |
or_xp | Denormalized XP totals for leaderboard performance — total_xp, level, updated_at (PK = user_id) |
or_badges | Admin-defined badges — name, description, icon, condition_type, condition_value, xp_reward |
or_user_badges | Join table: which users earned which badges. UNIQUE KEY on (user_id, badge_id) |
or_sessions | Active login sessions — SHA-256 token hash, device info (UA), IP, last_active (auto-updated) |
or_login_attempts | Brute force protection — tracks failed attempts by IP + email |
or_notifications | In-plugin notification bell entries — type, message, read_at, JSON data |
or_follows | Follow/unfollow relationships between users |
or_messages | Direct user-to-user messages |
or_2fa | Per-user 2FA config — secret, method, trusted devices |
Admin interface
Takes over the full browser viewport (position: fixed) so the WordPress sidebar never interferes. Matches the Orravo design system used across all Orravo plugins.
| Tab | URL param | Purpose |
|---|---|---|
| Users | tab=users | User list with stats, search, filter, CSV export |
| Badges | tab=badges | Badge list + create/edit |
| Gamification | tab=gamification | XP actions, levels, naming configuration |
| Emails | tab=email-templates | Per-template visual email editor |
| Settings | tab=settings | All plugin configuration |
Single user view
Click any user row to open a full profile card: XP, level, streak, level progress bar, profile completeness. From this view admins can award XP (amount + reason), award a badge from a dropdown, view earned badges grid, see recent activity, manage active sessions, impersonate the user, or delete the account.
Settings reference
All settings stored in wp_options under key oe_settings.
Page assignments
| Key | Type | Description |
|---|---|---|
login_page | int | WP page ID for login |
register_page | int | WP page ID for registration |
profile_page | int | WP page ID for user profiles |
dashboard_page | int | WP page ID for user dashboard |
profile_slug | string | URL prefix e.g. members → /members/username |
Authentication features
| Key | Default | Description |
|---|---|---|
enable_magic_link | true | Passwordless email login |
enable_2fa | false | TOTP + email code 2FA |
brute_force_limit | 5 | Max failed attempts before lockout |
brute_force_window | 15 | Lockout window in minutes |
Registration
| Key | Description |
|---|---|
registration_approval | Require admin approval before account activates |
enable_invitation_codes | Require invite code to register |
email_whitelist | Allowed email domains (newline-separated) |
enable_captcha | Enable CAPTCHA on registration form |
captcha_type | recaptcha_v3 or hcaptcha |
Utility bar
| Key | Default | Description |
|---|---|---|
utility_bar_enabled | true | Show utility bar on frontend |
utility_bar_show_xp | true | Show XP counter |
utility_bar_show_streak | true | Show streak counter |
utility_bar_show_notif | true | Show notification bell |
utility_bar_bg_color | #0b0b0c | Bar background colour |
utility_bar_text_color | #ececed | Bar text colour |
Shortcodes
[oengage_login]
[oengage_register]
?user=username from the URL to show other users' profiles.[oengage_profile]
[oengage_dashboard]
[oengage_leaderboard type="xp" limit="10"]
| Attribute | Default | Options |
|---|---|---|
type | xp | xp |
limit | 10 | 1–50 |
[oengage_badges user_id="123"]
[oengage_member_only]
This content is for members only.
[/oengage_member_only]
Auth system
AJAX-powered login flow with brute force protection, 2FA gate, and automatic session + gamification hooks on success.
or_login action).BruteForce::is_locked() checks for too many recent failed attempts.wp_authenticate() verifies credentials.wp_set_auth_cookie(), session created, XP awarded for daily login, streak recorded, oengage_login action fired.AJAX actions
| Action | Handler | Auth required |
|---|---|---|
or_login | AuthHandler::ajax_login | nopriv |
or_forgot_password | AuthHandler::ajax_forgot_password | nopriv |
or_reset_password | AuthHandler::ajax_reset_password | nopriv |
or_logout_session | AuthHandler::ajax_logout_session | logged-in |
Magic link login
Passwordless sign-in via a secure single-use email link. Tokens expire in 15 minutes.
or_send_magic_link fires — a secure 48-character token is stored in a transient (15-minute expiry).https://yoursite.com/?or_magic={token}init hook — no dedicated page required.Two-factor auth
TOTP (Google Authenticator)
- Standard RFC 6238 TOTP — compatible with Google Authenticator, Authy, 1Password
- Pure PHP implementation — no external library dependency
- 32-character base32 secret stored per user in
or_2fatable - ±1 code window (30-second tolerance)
Email code
6-digit numeric code sent to user's email address. 10-minute expiry via WordPress transient.
Setup flow (user-side)
or_setup_2fa generates a secret and returns an otpauth:// QR URI.oe_2fa_enabled and oe_2fa_secret user meta. 2FA status is visible in the single user view.Brute force protection
Tracks failed login attempts in or_login_attempts by both IP address and email simultaneously.
| Trigger | Default | Configurable |
|---|---|---|
| Failed attempts before lockout | 5 | Settings → brute_force_limit |
| Lockout window | 15 minutes | Settings → brute_force_window |
On successful login, all login attempts for that email are cleared from the table.
Session management
Every login session is tracked in or_sessions with a SHA-256 hashed token, device info, IP address, and auto-updating last-active timestamp.
- Admins can view all sessions for a user in the single user view
- Sessions can be revoked individually (or all at once) from the admin
- Users can revoke their own sessions via AJAX (
or_revoke_session) - Programmatic revocation:
SessionManager::revoke_all( $user_id )
Registration system
or_register with email, password, first/last name.wp_insert_user() creates the account.register action. oengage_user_registered action fired.Default registration fields
| Key | Type | Required |
|---|---|---|
first_name | text | Yes |
last_name | text | Yes |
email | Yes | |
password | password | Yes |
Fields configured in wp_options key oe_registration_fields. Custom fields can be added programmatically or via a future admin UI.
User profiles
Profiles are at the page assigned to profile_page in settings. Pass ?user=username to view another user's profile.
User meta keys
| Meta key | Description |
|---|---|
oe_email_verified | bool — email verified |
oe_avatar_id | Attachment ID for custom avatar |
oe_profile_privacy | public / members / private |
oe_login_streak | Current login streak count |
oe_longest_streak | All-time longest streak |
oe_last_login_date | Y-m-d format |
oe_last_active | Datetime |
oe_2fa_enabled | bool |
oe_2fa_secret | TOTP secret |
Profile completeness & privacy
ProfileRepository::get_completeness() returns 0–100% based on four checks: display name set, bio filled in, custom avatar uploaded, email verified. Prompts shown on dashboard if < 100%.
| Privacy value | Who can see the profile |
|---|---|
public | Everyone including logged-out visitors |
members | Logged-in users only |
private | Only the user themselves |
Gamification engine
XP is stored in or_xp (not user meta) for leaderboard query performance. Level is recalculated and synced every time XP is awarded.
Default XP actions
| Action key | Label | Default XP |
|---|---|---|
register | Register | 50 |
login | Daily Login | 5 |
fill_profile | Complete Profile | 30 |
post_comment | Comment | 10 |
create_post | Publish Post | 25 |
follow_user | Follow a User | 5 |
send_message | Send a Message | 3 |
Daily login XP is only awarded once per calendar day, checked via oe_last_xp_login user meta.
Default levels
Level names and XP thresholds are fully configurable in Gamification → Levels.
Streak system
StreakEngine::record_login() is called on every successful login. Streak increments if last login was yesterday; resets to 1 if the gap is more than 1 day. Longest streak is tracked separately in oe_longest_streak user meta.
Badge system
| Condition type | Description |
|---|---|
manual | Admin awards only — no automatic trigger |
xp_threshold | Automatically awarded when user's total XP reaches the condition value |
login_streak | Awarded when streak count reaches the condition value |
BadgeEngine::check_conditions() is called every time XP is awarded — it queries all active non-manual badges and awards any the user now qualifies for. Duplicate prevention: or_user_badges has a UNIQUE KEY on (user_id, badge_id).
Utility bar
A persistent position: fixed bar rendered at the top of every frontend page via wp_body_open. Uses z-index: 99990 — below the WP admin bar (99999) but above all site content.
| State | What's shown |
|---|---|
| Logged in | XP counter (configurable) · Streak counter (configurable) · Notification bell with unread badge + dropdown · User avatar + name with dropdown (Dashboard, My Profile, Sign Out) |
| Logged out | Sign In link · Get Started button (links to register page) |
Email templates
| Template key | When sent |
|---|---|
welcome | On new account creation |
verify_email | On registration — email verification link |
password_reset | On forgot password request |
admin_approval | When account approval is required |
account_approved | When admin approves a pending account |
social_connected | When user connects a social provider |
new_device_login | On login from unrecognized device |
magic_link | On magic link request |
2fa_code | On email 2FA code request |
Template variables
| Variable | All templates |
|---|---|
{{user_name}} | User's display name |
{{user_email}} | User's email address |
{{site_name}} | Blog name |
{{site_url}} | Home URL |
{{year}} | Current year |
Template-specific extras: verify_email → {{verify_link}} · password_reset → {{reset_link}} · magic_link → {{magic_link}} · 2fa_code → {{code}} · social_connected → {{provider}}
In-plugin notifications
Stored in or_notifications. The utility bar bell shows unread count and a dropdown of the 10 most recent notifications.
| Type | Trigger |
|---|---|
xp_earned | XP awarded to user |
badge_earned | Badge awarded |
new_follower | Someone followed the user |
| AJAX action | Description |
|---|---|
or_get_notifications | Returns recent 10 + unread count |
or_read_notification | Marks a single notification as read |
or_read_all_notifs | Marks all notifications as read |
Social features
Follow system
Users can follow/unfollow each other. Relationships stored in or_follows. Follow button appears on other users' profile pages. Following awards XP (follow_user action). Followed user receives a new_follower notification. Follower/following counts shown on profile stats bar.
Direct messaging
Basic user-to-user messaging via or_messages.
| AJAX action | Description |
|---|---|
or_send_message | Send a message to another user |
or_get_messages | Load conversation thread between two users |
or_get_inbox | Load all conversation threads for current user |
REST API endpoints
Base namespace: /wp-json/oengage/v1/
GET /profile/{user_id}
Returns a user's public profile data. Returns 403 if profile is private, 404 if user not found. Email is never returned for privacy.
JSON{
"user_id": 42,
"display_name": "Jane Doe",
"bio": "WordPress developer",
"avatar_url": "https://example.com/wp-content/uploads/avatar.jpg",
"total_xp": 1500,
"level": 5,
"login_streak": 7,
"privacy": "public",
"registered": "2024-01-15 10:30:00",
"last_active": "2025-04-20 14:22:00"
}
GET /leaderboard
Returns top users by XP. Query params: ?type=xp · ?limit=1-50 (default 10).
JSON[
{
"rank": 1,
"user_id": 42,
"display_name": "Jane Doe",
"avatar_url": "...",
"value": 12500,
"level": "Legend"
}
]
GET /user/{user_id}/xp
Returns XP and level data for a user.
JSON{
"level": 5,
"level_name": "Veteran",
"total_xp": 1500,
"next_threshold": 3000,
"progress": 53
}
Developer hooks
Action hooks
PHP// After user registers (before email verification)
do_action( 'oengage_user_registered', $user_id );
// After successful login
do_action( 'oengage_login', $user_id );
// When XP is awarded
do_action( 'oengage_xp_awarded', $user_id, $amount, $action );
// When a badge is earned
do_action( 'oengage_badge_earned', $user_id, $badge_id );
// When a user follows another
do_action( 'oengage_user_followed', $follower_id, $following_id );
// When a streak is updated
do_action( 'oengage_streak_updated', $user_id, $current_streak );
// When a direct message is sent
do_action( 'oengage_message_sent', $sender_id, $receiver_id );
// When a user's profile is updated
do_action( 'oengage_profile_updated', $user_id );
Usage examples
PHP// Slack notification on registration
add_action( 'oengage_user_registered', function( $user_id ) {
$user = get_userdata( $user_id );
// ... send Slack notification
} );
// Award XP on WooCommerce order completion
add_action( 'woocommerce_order_status_completed', function( $order_id ) {
$order = wc_get_order( $order_id );
$user_id = $order->get_user_id();
if ( $user_id ) {
\OEngage\Gamification\XPEngine::award( $user_id, 100, 'woo_purchase' );
}
} );
// Custom logic when a badge is earned
add_action( 'oengage_badge_earned', function( $user_id, $badge_id ) {
// Webhook, push notification, etc.
}, 10, 2 );
Helper functions
Static methods available anywhere in your theme or plugin code.
PHP// XP
$xp = \OEngage\Gamification\XPEngine::get_total( $user_id );
\OEngage\Gamification\XPEngine::award( $user_id, 50, 'custom_action' );
// Badges
\OEngage\Gamification\BadgeEngine::award( $user_id, $badge_id );
// Level data
$level = \OEngage\Gamification\LevelEngine::get_user_level( $user_id );
// Returns: [ 'level', 'level_name', 'total_xp', 'next_threshold', 'progress' ]
$name = \OEngage\Gamification\LevelEngine::get_level_name( 5 );
// Streaks
$streak = \OEngage\Gamification\StreakEngine::get_streak( $user_id );
$longest = \OEngage\Gamification\StreakEngine::get_longest_streak( $user_id );
// Leaderboard (cached, 5-min TTL)
$board = \OEngage\Gamification\Leaderboard::get( 'xp', 10 );
// Profile
$profile = \OEngage\Profile\ProfileRepository::get_user_profile( $user_id );
$avatar = \OEngage\Profile\ProfileRepository::get_avatar_url( $user_id, 80 );
$pct = \OEngage\Profile\ProfileRepository::get_completeness( $user_id );
$can_view = \OEngage\Profile\ProfileRepository::can_view_profile( $profile_uid, $viewer_id );
// Follow system
$following = \OEngage\Social\FollowSystem::is_following( $follower_id, $following_id );
$follower_count = \OEngage\Social\FollowSystem::get_follower_count( $user_id );
$following_count = \OEngage\Social\FollowSystem::get_following_count( $user_id );
// Notifications
\OEngage\Notifications\NotificationEngine::create( $user_id, 'custom_type', 'Your message.' );
$count = \OEngage\Notifications\NotificationEngine::get_unread_count( $user_id );
// Email
\OEngage\Notifications\EmailNotifier::send( $user_id, 'welcome', [] );
\OEngage\Notifications\EmailNotifier::send( $user_id, 'magic_link', [ 'magic_link' => $url ] );
// Sessions
\OEngage\Auth\SessionManager::create_session( $user_id );
\OEngage\Auth\SessionManager::revoke_all( $user_id );
$sessions = \OEngage\Auth\SessionManager::get_user_sessions( $user_id );
How OEngage stacks up
| Feature | OEngage | Ultimate Member | ProfilePress | WP User Manager | MemberPress |
|---|---|---|---|---|---|
| Custom login/register pages | ✓ | ✓ | ✓ | ✓ | ✓ |
| Social login (Google) | ✓ | Extension | ✓ | Extension | Extension |
| Social login (Apple) | ✓ | — | — | — | — |
| Social login (GitHub) | ✓ | — | — | — | — |
| Magic link login | ✓ | — | — | — | — |
| Two-factor auth | ✓ | Extension | — | — | — |
| Session management | ✓ | — | — | — | — |
| XP / Points system | ✓ | Extension | — | Extension | — |
| Levels | ✓ | Extension | — | Extension | — |
| Login streaks | ✓ | — | — | — | — |
| Badge system | ✓ | Extension | — | Extension | — |
| Leaderboard | ✓ | Extension | — | Extension | — |
| Utility bar (XP on every page) | ✓ | — | — | — | — |
| Activity tracking | ✓ | ✓ | — | ✓ | — |
| Follow/unfollow | ✓ | ✓ | ✓ | ✓ | — |
| Direct messaging | ✓ | Extension | Extension | Extension | — |
| Email template editor | ✓ | Extension | ✓ | — | ✓ |
| REST API | ✓ | — | — | — | — |
| Brute force protection | ✓ | ✓ | ✓ | ✓ | ✓ |
| Price | $79/yr | $249/yr+ | $99–299/yr | $149/yr | $179–399/yr |
Plans & pricing
- Custom login and register pages
- Email verification
- Google social login
- Basic user profile
- Admin user list
- Brute force protection
- Password reset
- All Core features
- Apple, GitHub, LinkedIn social login
- Two-factor authentication (TOTP + email)
- Magic link passwordless login
- Session management
- Full gamification: XP, levels, streaks, badges, leaderboard
- Utility bar with live XP and streak
- Custom profile fields
- Email template editor with visual preview
- Invitation codes + account approval
- Follow/unfollow + direct messaging
- REST API
- All Pro features
- WordPress Multisite support
- White-label (remove Orravo branding)
- Priority email support
What's shipped
- Custom login, register, forgot-password, profile, dashboard pages
- Social auth: Google, GitHub (Apple and LinkedIn configurable)
- Magic link passwordless login (15-min expiry, single-use)
- Two-factor authentication (TOTP RFC 6238 + email code)
- Brute force protection with configurable limits
- Session management with device tracking
- Registration: reCAPTCHA v3 + hCaptcha, invitation codes, email domain whitelist, admin approval
- Configurable registration field builder
- XP engine with configurable actions and values
- Level system with configurable thresholds (8 defaults)
- Login streak tracking + longest streak record
- Badge system: manual + automatic conditions (XP threshold, streak)
- Leaderboard shortcode (5-min cached transient)
- Persistent utility bar: XP, streak, notification bell, profile dropdown
- In-plugin notification system (
xp_earned,badge_earned,new_follower) - Email template editor with 9 templates and
{{variable}}system - User profile with avatar upload, bio, privacy controls, completeness indicator
- Follow/unfollow users
- Direct messaging (basic)
- REST API:
/profile/{id},/leaderboard,/user/{id}/xp - Admin: user list with stats, single user view, award XP/badge, impersonate
- Full Orravo design system (dark/light, matches OMailer/OForum)
- 10 custom DB tables, full uninstall cleanup
- Developer action hooks and static helper methods
Got a question about OEngage?
Reach out directly — Kenneth replies within 24 hours.

Social login
Four OAuth providers — configure credentials in Settings → Social Authentication.
OAuth callback URL
Email already exists
If the email from a social provider already exists as a WP user: OEngage logs in that user automatically (no error), stores the provider's user ID in user meta (
oe_social_google, etc.), and sends a "Social login added" notification email.