Abuja Digital Studio · Est. 2018
Start a Project
Docs
OMobile
The control panel for your WordPress-powered mobile app — JWT auth, push notifications (Expo, FCM, APNS), crash reporting, telemetry, device management, feature flags, remote config, announcements, deep links, and 10+ REST controllers in one admin panel.
omobile
Developer documentation

OMobile v2.1.0

Turns your WordPress site into a full-featured mobile app backend with JWT + social auth, remote config, feature flags, push notifications via Expo + FCM + APNS, push campaigns with frequency capping, crash reporting, telemetry, an app builder (brand, navigation, homescreen), deep links, content sync, and cross-plugin bridges.

WordPress plugin WP 6.0 · PHP 7.4+ Namespace: omobile/v1 v2.1.0
01 · Overview

What OMobile does

A complete mobile backend as a WordPress plugin: 19 database tables, 73 REST endpoints across 10 controllers, 30 admin tabs, three push drivers, an app builder, and cross-plugin bridges. No external service accounts needed beyond your push provider credentials.

🔐
JWT + Social Auth
HS256 JWT, refresh token rotation, Google + Apple sign-in, password reset
🚩
Feature Flags
Boolean, string, number, JSON with per-device rollout percentages
⚙️
Remote Config
Server-controlled key/value pairs, no app deploy needed
🔔
Push Drivers
FCM HTTP v1, APNS token-based (p8), Expo push API
📢
Push Campaigns
Composer, dispatch, A/B variants, frequency caps, triggers, analytics
📱
App Versioning
Force-update, deprecation, and blocking rules per platform
💥
Crash Reporting
SHA-256 fingerprint grouping, deduplication, resolution tracking
📊
Telemetry + Sessions
Batch ingestion, hourly rollup, session start/end/heartbeat
🎯
Segments
Target pushes by platform, version, locale, timezone
📣
Announcements
Banners, modals, and toasts delivered via the config endpoint
🎨
App Builder
Brand, navigation, homescreen, deep-link registry, universal links, QR
🔔
Notification Prefs
Per-user GET/PATCH endpoints so users can opt out of channels
🔗
Webhooks
HMAC-signed outbound events for crash, push, flags, devices
📷
Config Snapshots
Point-in-time flag + remote config captures for rollback
📦
Postman Export
Generate a ready-to-import Postman collection of all endpoints
🧩
Cross-Plugin Bridges
Modules for WooCommerce, OMailer, OForms, OEngage, OForum
⌨️
WP-CLI
10 commands: status, rollup, sweep, dispatch-push, snapshot, seed-demo, analytics, ...
02 · Installation

Getting installed

1
Upload the omobile folder to /wp-content/plugins/.
2
Activate via Plugins → Installed Plugins. All 19 database tables are created via dbDelta; no data is written until setup is complete.
3
Navigate to OMobile in the WordPress admin menu.
4
Complete the Setup Wizard (Onboarding tab): generate JWT secret, verify REST API, configure push credentials.

wp-config.php constant

PHP// Override the JWT secret (takes precedence over the wp_options stored secret)
define( 'OMOBILE_JWT_SECRET', 'your-256-bit-secret-here' );

// Keep all data when deleting the plugin
define( 'OMOBILE_KEEP_DATA_ON_UNINSTALL', true );
03 · Database Tables

19 database tables

All tables use the WordPress table prefix (default wp_). Created on activation via dbDelta.

TableDescription
omobile_devicesRegistered mobile installs (platform, version, push token, locale, timezone)
omobile_sessionsActive app sessions with start/end timestamps
omobile_api_logEvery REST request logged (method, path, status, duration)
omobile_telemetryRaw event stream from the app
omobile_telemetry_rollupDaily rollup: date, platform, version, event name, count
omobile_crashesCrash reports with SHA-256 fingerprints and occurrence counters
omobile_flagsFeature flags with type, value, rollout percentage
omobile_announcementsIn-app messages (banner, modal, toast) with expiry
omobile_push_queueOutbound push jobs awaiting cron dispatch
omobile_content_healthPosts flagged for missing image, excerpt, or content
omobile_snapshotsPoint-in-time captures of flags + remote config
omobile_webhooksRegistered outbound webhook URLs and their event subscriptions
omobile_refresh_tokensActive refresh token records with rotation chain state
omobile_login_attemptsPer-identifier throttle event log
omobile_segmentsDevice targeting rules in JSON
omobile_auditAdmin action audit trail
omobile_api_keysAPI key store: prefix + SHA-256 hash only (raw key never persisted)
omobile_app_versionsVersion status and force-update rules per platform
omobile_remote_configKey/value remote config store
04 · Authentication

Auth overview

Three authentication methods: JWT (for mobile users), Social login (Google + Apple ID tokens), and API Keys (for server-to-server and CI). All mobile endpoints also require the X-Om-Install-Id header.

Access token TTL
1h
filterable
Refresh token TTL
30d
rotated on use
Reuse window
30s
Lock after failures
5×
then 15 min lockout
4.1 · JWT Flow

JWT authentication

OMobile uses HS256 JWTs implemented in pure PHP with base64url encoding, no external library.

Login

HTTPPOST /wp-json/omobile/v1/auth/token
Content-Type: application/json
X-Om-Install-Id: <your-device-uuid>

{
  "username": "user@example.com",
  "password": "secret"
}
RESPONSE{
  "access_token":  "eyJ…",
  "refresh_token": "eyJ…",
  "user": {
    "id":           1,
    "display_name": "Jane Doe",
    "email":        "user@example.com"
  }
}

Authenticated requests

HTTPAuthorization: Bearer <access_token>
X-Om-Install-Id: <your-device-uuid>

Token refresh

HTTPPOST /wp-json/omobile/v1/auth/refresh
Content-Type: application/json

{ "refresh_token": "eyJ…" }

Returns a new access_token and a rotated refresh_token.

4.2 · Refresh Tokens

Refresh token rotation

Refresh tokens use a rotation + reuse detection pattern designed to catch token theft in real time.

  • Each refresh issues a new token and invalidates the old one immediately.
  • A 30-second reuse window tolerates race conditions where two requests use the same token near-simultaneously.
  • If a consumed token is presented outside the reuse window, the entire chain is revoked: all sessions for that user on that device are ended immediately, indicating the old token was stolen and replayed.
4.3 · Login Throttling

Login throttling

Failed login attempts are rate-limited per identifier (username/email) and per IP simultaneously.

ThresholdActionDuration
5 failed attemptsIdentifier locked15 minutes

Implemented with WordPress transients. The omobile_login_attempts table records the events for the audit log; the transient drives the actual blocking logic.

4.4 · API Keys

API keys

An alternative to JWT for server-to-server or CI integrations. Only the SHA-256 hash is ever stored; the raw key is shown once at creation and never again.

PropertyDetail
Formatomk_ prefix + 40 hex characters
StorageSHA-256 hash + first 8 chars (prefix) only
AuthenticationAuthorization: Bearer omk_…
Rate limit120 req/min per key (configurable)
IP whitelistOptional, one IP per line
ExpiryOptional expiry date
BASHwp omobile create-api-key --name="My App"
05 · REST API Reference

REST API reference

Base URL: https://yoursite.com/wp-json/omobile/v1/. All mobile endpoints require X-Om-Install-Id with a unique per-install UUID.

Auth endpoints

MethodPathAuthDescription
POST/auth/tokenPublicAuthenticate with username/password, receive JWT pair
POST/auth/registerPublicSelf-serve signup (when enabled in settings)
POST/auth/refreshPublicRotate refresh token, receive new pair
POST/auth/revokeBearerRevoke a single refresh token
POST/auth/revoke-allBearerRevoke all refresh tokens for the current user
GET/auth/meBearerCurrent user profile
POST/auth/googlePublicSign in with a Google ID token
POST/auth/applePublicSign in with an Apple ID token
POST/auth/password-reset/requestPublicRequest a password reset email
POST/auth/password-reset/confirmPublicConfirm reset with token + new password

Config endpoint

MethodPathAuthDescription
GET/configBearerApp config, flags, remote config, announcements, version check

Cached per platform+version for 60 seconds. Cache invalidated automatically whenever a flag or remote config is updated. Query params: ?platform=ios|android and ?version=2.1.0.

RESPONSE{
  "flags": {
    "new_checkout_flow": {
      "value": true, "rollout_pct": 50, "in_rollout": true
    }
  },
  "remote_config": {
    "min_cart_value": 10,
    "support_email": "help@example.com"
  },
  "announcements": [],
  "version_check": {
    "status": "supported", "force_update": false, "message": ""
  }
}

Device, session, telemetry & crash endpoints

MethodPathDescription
POST/devices/registerRegister or update device (platform, version, push token, locale, timezone, model)
POST/devices/updateUpdate an existing device record
POST/devices/pingLightweight liveness ping that updates last_seen
POST/sessions/startStart a new app session
POST/sessions/endEnd the current session
POST/sessions/heartbeatKeep a session alive across foreground/background transitions
POST/telemetrySubmit a single named event with properties
POST/telemetry/batchSubmit a batch of events in one request
POST/crashesSubmit crash (message, stack trace, platform, version, OS)
GET/postsPaginated posts feed
GET/posts/{id}Single post
GET/pagesPaginated pages feed
GET/sync/contentIncremental content sync since a given timestamp
GET/configApp config: flags, remote config, announcements, version check
GET/healthBackend health probe
GET/manifestApp manifest (brand, navigation, homescreen, deep-link table)
GET/deep-linkResolve a deep link to its target post or screen

User notification preferences

MethodPathDescription
GET/me/notification-preferencesRead the current user's per-channel opt-in state
PATCH/me/notification-preferencesUpdate opt-in/out for transactional, marketing, alerts

Admin REST endpoints

Require a logged-in admin or a valid API key with manage_omobile capability.

MethodPathDescription
GET POST DEL/admin/flagsFeature flag CRUD
GET POST DEL/admin/remote-configRemote config CRUD
GET POST DEL/admin/announcementsIn-app announcements CRUD
GET/admin/push-queueInspect push queue
POST/admin/push/sendOne-shot push from the composer
GET POST DEL/admin/campaignsPush campaign CRUD
POST/admin/campaigns/{id}/dispatchDispatch a saved campaign now
GET/admin/push-analyticsPer-campaign delivery and open stats
GET POST DEL/admin/segmentsSegment CRUD
GET/admin/devicesList registered devices
GET/admin/crashesList captured crashes
GET/admin/api-logREST request log
GET/admin/auth-logLogin attempts + token issuance log
GET/admin/auth-log/sessionsActive mobile sessions
GET/admin/auditAdmin action audit trail
GET POST DEL/admin/api-keysAPI key management
GET POST DEL/admin/app-versionsVersion rule management
GET POST DEL/admin/deep-linksDeep link registry
GET POST/admin/brandBrand assets and tokens
GET POST/admin/navigationApp navigation tree
GET POST/admin/homescreenHomescreen layout builder
GET POST/admin/universal-linksiOS / Android universal link config
GET/admin/qrGenerate a QR code for a deep link
GET/admin/export/postman-collectionDownload a Postman collection of every endpoint
06 · Feature Flags

Feature flags

Key/value pairs returned under flags in the /config response. Support gradual rollouts down to individual devices.

TypeDescription
booleantrue / false
stringArbitrary text value
numberInteger or float
jsonParsed JSON object or array

Rollout percentage

Set rollout_pct to 1–100. Each device is assigned a random number (1–100) on first config fetch. If the device's number ≤ rollout_pct, the flag appears in their response as in_rollout: true. A flag at 10% reaches approximately 10% of devices, gradually ratcheting up.

Cache invalidation

When a flag is toggled or updated, OMobile_REST_Config::invalidate_cache() deletes all omobile_config_* transients. The next request regenerates the cache fresh.

07 · Remote Config

Remote config

Arbitrary key/value pairs returned under remote_config in the /config response. Change values without a new app release.

  • Feature toggles without code deploys
  • Store URLs, support emails, deep-link URIs
  • Minimum cart values, discount thresholds
  • Any server-controlled constant

Supports the same 4 types as feature flags: string, number, boolean, json.

08 · Push Notifications

Push notifications

Three push drivers; choose one based on your app stack.

FCM HTTP v1
Android apps + Firebase iOS. Uses service account JSON + OAuth2 token exchange.
APNS Token-based
Native iOS apps. Uses .p8 key file, so no certificate renewal is needed.
Expo Push
React Native / Expo apps. Routes via the Expo Push API with no credentials required.

Push payload fields

FieldDescription
titleNotification title
bodyNotification body text
image_urlRich notification image
deep_linkIn-app navigation URL
campaign_nameFor analytics attribution
ab_variantA/B testing variant label

Push queue

Pushes are queued in omobile_push_queue and dispatched every minute by the omobile_dispatch_push cron event. To dispatch immediately:

BASHwp omobile dispatch-push
8.1 · FCM v1 Setup

FCM HTTP v1

OMobile uses the FCM HTTP v1 API. Credentials are exchanged for an OAuth2 access token and cached for 55 minutes.

1
In Firebase Console → Project Settings → Service Accounts → Generate New Private Key, then download the JSON file.
2
In OMobile → Settings → FCM: paste the full JSON content and your Firebase project ID.
3
The plugin exchanges the service account for an RS256 JWT → https://oauth2.googleapis.com/token, caching the resulting token for 55 minutes.
8.2 · APNS Token-Based

APNS token-based

Uses .p8 key files; token-based auth never expires like certificates do. The ES256 JWT is cached for 55 minutes (Apple allows up to 1 hour).

1
In Apple Developer Portal → Certificates, Identifiers & Profiles → Keys → Create new key.
2
Enable Apple Push Notifications service (APNs) and download the .p8 file (it is shown once only).
3
Note your Team ID (top-right in developer portal) and the Key ID.
4
In OMobile → Settings → APNS: paste the p8 key content, team ID, key ID, and your app's bundle ID.
8.3 · Expo Push

Expo push setup

Select Expo as the push driver. No credentials needed; OMobile posts to the Expo Push API at https://exp.host/--/api/v2/push/send.

Devices must use the expo-notifications SDK and register their Expo push token via POST /devices/register.

09 · App Versioning & Force Update

Versioning & force update

Define version rules in the Versions tab. Each rule controls how the app behaves based on the version and platform reported in the /config request.

FieldDescription
versionApp version string (e.g. 2.1.0)
platformios, android, or all
statussupported, deprecated, or blocked
force_updateIf true, app must update before continuing
min_requiredMinimum version still supported
messageUser-facing message shown on update prompt
store_urlLink to App Store / Play Store

The /config response includes a version_check object based on the requesting app's version and platform query params.

10 · Crash Reporting & Grouping

Crash reporting & grouping

Crashes are submitted by the app and de-duplicated server-side using SHA-256 fingerprinting, so duplicate crashes never create new rows.

Crash report payload

JSONPOST /omobile/v1/crashes
{
  "message":     "NullPointerException in CartScreen",
  "stack_trace": "...",
  "platform":    "android",
  "app_version": "2.1.0",
  "os_version":  "14"
}

Fingerprinting

The fingerprint is a SHA-256 hash of the first 3 lines of the normalised stack trace. When a crash matches an existing fingerprint, only count and last_seen_at are updated; no new row is inserted.

Resolution

Crashes can be marked resolved in the Crashes tab. Resolved crashes optionally store a GitHub issue URL for traceability.

11 · Analytics

Analytics methods

Computed from omobile_sessions, omobile_telemetry_rollup, and omobile_devices. All methods available from WP-CLI via wp omobile analytics.

MethodReturns
OMobile_Analytics::dau( $days )Daily Active Users for last N days
OMobile_Analytics::retention()D1 / D7 / D30 retention cohorts
OMobile_Analytics::top_screens( $limit )Most-visited screens
OMobile_Analytics::top_events( $limit )Most-fired events
OMobile_Analytics::platform_split()iOS vs Android device count
OMobile_Analytics::version_distribution()Devices per app version
OMobile_Analytics::avg_session_duration()Mean session length in seconds
OMobile_Analytics::crash_rate(){ rate_pct, crashes, sessions } for last 30 days
12 · Telemetry

Event telemetry

Apps submit events in batches. Raw events are rolled up daily into omobile_telemetry_rollup.

JSONPOST /omobile/v1/telemetry/batch
{
  "events": [
    { "name": "product_view", "properties": { "sku": "ABC123" } },
    { "name": "add_to_cart",  "properties": { "sku": "ABC123", "qty": 2 } }
  ]
}

Each rollup row contains: date, platform, app_version, event_name, event_count. Run the rollup manually:

BASHwp omobile rollup
13 · Devices & Segments

Devices & segments

Device registration

Every app install gets a unique install ID (UUID v4, generated on first launch) passed with every request via X-Om-Install-Id. Device records track: platform, app version, OS version, device model, push token, locale, timezone, last seen, active status.

Segments

Segments are JSON rule objects used to target push notifications to a subset of devices.

JSON{ "platform": "ios" }
{ "platform": "android", "min_app_version": "2.0.0" }
{ "locale": "en-US" }
14 · Announcements

In-app announcements

Returned in the /config response. Displayed client-side as banners, modals, or toasts.

TypeDescription
bannerPersistent top or bottom bar
modalFull-screen overlay
toastEphemeral notification, auto-dismisses

Announcements support title, body, an active flag, and an optional expires_at timestamp that auto-hides the announcement.

15 · Content Health

Content health

A cron-scheduled checker that flags WordPress posts with content issues, surfaced in the Content Health tab with direct edit links.

  • Missing featured image
  • Empty excerpt
  • Empty post content
16 · Webhooks

Outbound webhooks

Register webhook URLs to receive real-time HMAC-signed events from OMobile.

EventFires when
crash.newNew crash report received
push.sentPush notification dispatched successfully
push.failedPush delivery failure
flag.updatedFeature flag value changed
device.registeredNew device registered for the first time

Payload & signature

JSON{
  "event":     "crash.new",
  "timestamp": "2026-04-25T10:00:00Z",
  "data": { ... }
}

Each request includes an X-OMobile-Signature header for verification:

HTTPX-OMobile-Signature: sha256=<HMAC-SHA256 of raw body using webhook secret>
17 · Snapshots

Config snapshots

Snapshots capture the current state of all feature flags and remote config at a point in time. Use them as a safety net before releases.

1
Create a "before" snapshot before deploying new flag configuration.
2
Deploy the new flag/config changes.
3
If something breaks, restore flags manually to the snapshot state from the admin UI.
BASHwp omobile snapshot --label="Before v2.1 release"
18 · Onboarding Wizard

Onboarding wizard

Guides new installations through 6 steps. Progress stored in wp_options under omobile_onboarding_step.

StepDescription
welcomeIntro screen
jwtGenerate and store a JWT secret
test-connectionVerify REST API is reachable from the internet
push-configConfigure FCM / APNS / Expo credentials
test-pushSend a test push notification
doneSetup complete; dashboard unlocked
PHP// Reset the wizard (also available in Setup tab)
OMobile_Onboarding::reset();
19 · Demo Mode

Demo mode

One-click demo data seeding for exploring the plugin without a connected app.

Seeded dataCount
Registered devices (iOS + Android mix)20
Feature flags4
Remote config keys3
In-app announcements1
API log entries50
Crash reports5
App version rules2
BASHwp omobile seed-demo   # seed demo data
wp omobile clear-demo  # remove all demo data

Both operations are also available in the admin UI under the Demo tab.

20 · WP-CLI Reference

WP-CLI commands

10 subcommands, all using the wp omobile prefix.

# Show plugin status and diagnostics wp omobile status   # Generate + store a new JWT secret wp omobile generate-secret   # Create an API key wp omobile create-api-key --name="My App"   # Demo data wp omobile seed-demo wp omobile clear-demo   # Run telemetry rollup immediately wp omobile rollup   # Delete logs beyond retention period wp omobile sweep   # Dispatch pending push notifications immediately wp omobile dispatch-push   # Print analytics summary (last 30 days) wp omobile analytics   # Create a config snapshot wp omobile snapshot --label="Before release"
21 · SDK Quick Start

SDK quick start

Copy-paste integration for the two most common mobile stacks. Store tokens in secure storage; never in plain AsyncStorage or shared preferences.

JSimport * as SecureStore from 'expo-secure-store';
import { Platform } from 'react-native';
import Constants from 'expo-constants';

const BASE_URL  = 'https://yoursite.com/wp-json/omobile/v1/';
const INSTALL_ID = Constants.installationId; // stable UUID per install

async function authHeaders() {
  const token = await SecureStore.getItemAsync('access_token');
  return {
    'Authorization': `Bearer ${token}`,
    'X-Om-Install-Id': INSTALL_ID,
    'Content-Type': 'application/json',
  };
}

// Login
export async function login(username, password) {
  const res  = await fetch(`${BASE_URL}auth/token`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'X-Om-Install-Id': INSTALL_ID },
    body: JSON.stringify({ username, password }),
  });
  const data = await res.json();
  if (data.access_token) {
    await SecureStore.setItemAsync('access_token',  data.access_token);
    await SecureStore.setItemAsync('refresh_token', data.refresh_token);
  }
  return data;
}

// Get config (flags + remote config)
export async function getConfig() {
  const res = await fetch(
    `${BASE_URL}config?platform=${Platform.OS}&version=${Constants.expoConfig.version}`,
    { headers: await authHeaders() }
  );
  return res.json();
}

// Register device + push token
export async function registerDevice(pushToken) {
  const res = await fetch(`${BASE_URL}devices/register`, {
    method: 'POST',
    headers: await authHeaders(),
    body: JSON.stringify({
      platform:    Platform.OS,
      app_version: Constants.expoConfig.version,
      push_token:  pushToken,
      locale:      'en-US',
      timezone:    Intl.DateTimeFormat().resolvedOptions().timeZone,
    }),
  });
  return res.json();
}

// Submit telemetry events
export async function trackEvents(events) {
  await fetch(`${BASE_URL}telemetry/batch`, {
    method: 'POST',
    headers: await authHeaders(),
    body: JSON.stringify({ events }),
  });
}

// Report crash
export async function reportCrash(error) {
  await fetch(`${BASE_URL}crashes`, {
    method: 'POST',
    headers: await authHeaders(),
    body: JSON.stringify({
      message:     error.message,
      stack_trace: error.stack,
      platform:    Platform.OS,
      app_version: Constants.expoConfig.version,
      os_version:  Platform.Version.toString(),
    }),
  });
}
DARTimport 'package:http/http.dart' as http;
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'dart:convert';
import 'dart:io';

const baseUrl  = 'https://yoursite.com/wp-json/omobile/v1/';
final _storage = FlutterSecureStorage();
const installId = 'YOUR-UUID-HERE'; // generate once, store persistently

Future<Map<String, String>> authHeaders() async {
  final token = await _storage.read(key: 'access_token') ?? '';
  return {
    'Authorization': 'Bearer $token',
    'X-Om-Install-Id': installId,
    'Content-Type': 'application/json',
  };
}

// Login
Future<Map<String, dynamic>> login(String username, String password) async {
  final res = await http.post(
    Uri.parse('${baseUrl}auth/token'),
    headers: { 'Content-Type': 'application/json', 'X-Om-Install-Id': installId },
    body: jsonEncode({ 'username': username, 'password': password }),
  );
  final data = jsonDecode(res.body) as Map<String, dynamic>;
  if (data['access_token'] != null) {
    await _storage.write(key: 'access_token',  value: data['access_token']);
    await _storage.write(key: 'refresh_token', value: data['refresh_token']);
  }
  return data;
}

// Get config
Future<Map<String, dynamic>> getConfig(String version) async {
  final platform = Platform.isIOS ? 'ios' : 'android';
  final res = await http.get(
    Uri.parse('${baseUrl}config?platform=$platform&version=$version'),
    headers: await authHeaders(),
  );
  return jsonDecode(res.body);
}

// Register device
Future<void> registerDevice(String pushToken, String version) async {
  final platform = Platform.isIOS ? 'ios' : 'android';
  await http.post(
    Uri.parse('${baseUrl}devices/register'),
    headers: await authHeaders(),
    body: jsonEncode({ 'platform': platform, 'app_version': version, 'push_token': pushToken }),
  );
}

// Track events
Future<void> trackEvents(List<Map<String, dynamic>> events) async {
  await http.post(
    Uri.parse('${baseUrl}telemetry/batch'),
    headers: await authHeaders(),
    body: jsonEncode({ 'events': events }),
  );
}

// Report crash
Future<void> reportCrash(Object error, StackTrace stack) async {
  final platform = Platform.isIOS ? 'ios' : 'android';
  await http.post(
    Uri.parse('${baseUrl}crashes'),
    headers: await authHeaders(),
    body: jsonEncode({
      'message':     error.toString(),
      'stack_trace': stack.toString(),
      'platform':    platform,
    }),
  );
}
22 · Admin UI

Admin UI

Accessed via OMobile in the WordPress admin menu. Single page at admin.php?page=omobile with no WP sidebar sub-items.

Layout

  • Row 1, Brand bar: OMobile logo + name + version badge + light/dark toggle
  • Row 2, Nav: Horizontal scrollable tabs grouped by dividers

Theme preference is persisted in localStorage as omobile_theme. Dark mode adds the class omobile-dark to <body>.

Navigation groups (30 tabs total)

GroupTabs
OverviewDashboard, Onboarding
AppDevices, Segments, Analytics, App Versions
App BuilderBranding, Navigation, Homescreen, Deep Links
PushPush Composer, Campaigns, Push Analytics, Announcements
BackendFeature Flags, Remote Config
MonitoringAPI Monitor, Crashes, Telemetry, Content Health
AuthAuth Settings, Auth Log, API Keys, Audit
SystemSettings, Webhooks, Snapshots, Demo, Diagnostics, SDK Docs
23 · Filters & Actions

Filters & actions

Filters

PHP// Override the storage adapter (default: transients)
add_filter( 'omobile_storage_adapter', function( $adapter ) {
    return new My_Redis_Adapter(); // must implement OMobile_Storage_Interface
} );

// Modify config payload before it's returned to the app
add_filter( 'omobile_config_payload', function( $payload, $install_id ) {
    $payload['custom_key'] = 'custom_value';
    return $payload;
}, 10, 2 );

// Control which capability manages OMobile (default: 'manage_omobile')
add_filter( 'omobile_admin_cap', function() {
    return 'manage_options';
} );

Actions

PHP// Fires after a crash is reported
add_action( 'omobile_crash_reported', function( $crash_id, $data ) {
    // notify Slack, create GitHub issue, etc.
}, 10, 2 );

// Fires after a push notification is dispatched
add_action( 'omobile_push_dispatched', function( $queue_id, $result ) {
    // log result, update campaign stats, etc.
}, 10, 2 );

// Fires after a feature flag is updated
add_action( 'omobile_flag_updated', function( $flag_key, $new_value ) {
    // trigger downstream cache invalidation, etc.
}, 10, 2 );
24 · Uninstall & Cleanup

Uninstall & cleanup

Deactivating leaves all data intact for a clean reactivation. Deleting the plugin via the WordPress UI runs uninstall.php and removes everything.

What uninstall.php removes

1
Drops all 19 omobile_* tables.
2
Deletes all omobile_* options from wp_options.
3
Removes the manage_omobile capability from all users and deletes the omobile_manager role.
4
Deletes all omobile_* cron events.
5
Removes all omobile_* transients.
💡To keep all data on deletion, add define( 'OMOBILE_KEEP_DATA_ON_UNINSTALL', true ); to wp-config.php before deleting the plugin.
✦ Need help?

Got a question about OMobile?

Reach out directly. Kenneth replies within 24 hours.