Orravo Core v2.3.0
The licensing and activation backbone every Orravo plugin needs. License validation, per-site activations, a unified suite shell with a Cmd+K command palette, REST API, and a Mini-Core fallback so paid plugins keep booting even when Core is not installed. Free forever.
What Orravo Core does
Orravo Core is the runtime that every other Orravo plugin talks to. It owns the license key, tracks per-site activations, ships shared admin chrome, and exposes a clean public API so each plugin can stay small and focused on its own job.
Get it running
Install Core like any standard WordPress plugin. It self-installs its database tables on activation and schedules its own cron events.
orravo-core.zip from your Orravo account or from orravo.com/plugins/orravo-core.orravo.com/api/licenses and caches the result for six hours.Five-minute setup
The fastest path to a fully wired Orravo install with one license key powering every paid plugin.
wp-cli# 1. Install Core
wp plugin install orravo-core --activate
# 2. Activate your license (one key covers every paid plugin in your tier)
wp orravo license activate ORV-9F3K-7T2X-RV4N-8KQ2
# 3. Install the paid plugins you bought, all at once
wp plugin install omailer oforms oads ofeedback --activate
# 4. Verify Core picked them all up
wp orravo product list
# omailer 3.3.2 stable licensed
# oforms 1.2.0 stable licensed
# oads 4.0.1 stable licensed
# ofeedback 1.4.0 stable licensed
# 5. Run doctor to confirm everything is healthy
wp orravo doctor
# tables ✓ · cron ✓ · license ✓ · 4/4 products active
What ships in the zip
Orravo Core is a small plugin (~280KB unzipped). One bootstrap file, twelve include classes, one admin class, and a handful of view templates.
Seven tables, all prefixed
Core installs seven tables, all named {prefix}orravo_*. None of them touch wp_users, wp_posts, or any other Orravo plugin’s data.
| Table | Purpose | Typical row count |
|---|---|---|
| orravo_licenses | Active license payload (one row per active install) | 1 |
| orravo_notifications | Per-user inbox items pushed by any Orravo plugin | tens to hundreds |
| orravo_snapshots | Settings snapshots for one-click rollback | up to ~20 |
| orravo_activity_log | Recent activity events. Auto-trims to last 500 | up to 500 |
| orravo_webhooks | Configured outbound webhook endpoints | 0 to ~10 |
| orravo_webhook_log | Delivery log (status, latency, retries) | per dispatch |
| orravo_api_keys | Scoped API keys for the REST API | 0 to ~10 |
In addition to the tables above, Core uses a small set of wp_options keys: orravo_license_key, orravo_license_cache, orravo_license_verification_log, orravo_grace_expires, orravo_mini_license_key, orravo_mini_license_data, and oc_db_version. Mini-Core options are mirrored so the fallback shim sees the same payload as the full Core.
Six tabs, one menu
Core registers a single top-level wp-admin menu (orravo-core) with six tabs. Submenu links deep-link straight to a tab.
| Tab | URL | What it does |
|---|---|---|
| Overview | ?page=orravo-core | License health, detected products, recent activity |
| License | ?page=orravo-core&tab=license | Activate / deactivate / refresh the license key |
| Products | ?page=orravo-core&tab=products | Detected Orravo plugins, version, channel, status |
| Tools | ?page=orravo-core&tab=tools | Settings export / import, snapshots, debug log |
| Developer | ?page=orravo-core&tab=developer | API keys, webhooks, REST docs |
| System Status | ?page=orravo-core&tab=status | PHP, WP, cron, table integrity, last revalidation |
One key, every plugin
A single license key covers every product in your purchase tier. The license payload is cached in orravo_license_cache for six hours; helper functions return from cache for fast, repeated checks.
| Tier | Sites | Products covered |
|---|---|---|
| single | 1 production | The product you bought |
| studio | up to 10 production | Bundle: every plugin in the studio pack |
| unlimited | unlimited | Every Orravo plugin, including future releases |
orravo_tier_at_least('studio') in your own code to gate features that should only run for the studio or unlimited tier.Per-site seats
Every site that activates the license consumes one seat. Dev-site mode marks staging or local installs so they don’t use a production seat.
Toggle dev-site mode from the License tab or programmatically:
php// Mark this install as a dev/staging site (no production seat consumed)
update_option('oc_is_dev_site', true);
// Transfer the active license off this site (frees the seat)
OC_License::deactivate();
Auto-detected plugins
Core scans every installed plugin for the Orravo namespace marker (a known slug from OC_KNOWN_PRODUCTS) and registers any matches.
Currently recognised slugs:
| Slug | Display name |
|---|---|
omailer | Omailer |
oforms | OForms |
oads | OAds |
ofeedback | OFeedback |
oforum | OForum |
ointel | OIntel |
omobile | OMobile |
onav | ONav |
oonboard | OOnboard |
opwa | oPWA |
oengage | OEngage |
ocodeinsert | OCodeInsert |
oamazon | Oamazon |
Plugins keep working
Every paid Orravo plugin ships a 40-line PHP shim called Mini-Core. It reads the cached license payload from orravo_mini_license_data and answers the four helper functions even when the full Orravo Core is not installed.
mini-core.php// Drop into includes/mini-core.php in your plugin and require it from your bootstrap.
if (! function_exists('orravo_is_licensed')) {
function orravo_is_licensed(string $slug): bool {
$data = get_option('orravo_mini_license_data', []);
if (empty($data)) return false;
if (($data['status'] ?? '') !== 'active') return false;
return in_array($slug, $data['products'] ?? [], true);
}
}
if (! function_exists('orravo_license_status')) {
function orravo_license_status(): string {
$data = get_option('orravo_mini_license_data', []);
return $data['status'] ?? 'inactive';
}
}
orravo_mini_license_data, so the shim stays in sync. If Core is later deactivated, the shim still reads the cached state and your plugin keeps working.Stable, beta, nightly
Core ships a custom updater that hooks into WordPress’s native plugin updates UI. Pick a release channel per plugin from the Tools tab.
- stable the default. Releases tagged
vX.Y.Zwith no suffix. - beta early access (typically a release candidate). Releases tagged
vX.Y.Z-beta.N. - nightly latest commit on
main. Useful for bug fixes you need to confirm before a stable cuts.
Roll back to any previous version from the Products tab. Core keeps the last three versions of each plugin in wp-content/orravo-rollbacks/ for offline rollback.
Capture everything
A snapshot bundles every Orravo plugin’s settings into one JSON blob. Restore in one click. Useful before plugin upgrades, demos, or staging-to-production handoffs.
php// Create a snapshot programmatically
OC_Export::snapshot('Pre Q2 release');
// List all snapshots
$rows = OC_Export::snapshots();
// [ ['id' => 1, 'name' => 'Pre Q2 release', 'created_at' => ...], ... ]
// Restore by id
OC_Export::restore_snapshot(1);
Shared admin chrome
Every Orravo plugin opts into the same topbar: a unified breadcrumb, a notifications bell, an activity drawer, and the command palette trigger. Plugins drop in, the chrome stays consistent.
Register your screen with one line:
phpif (class_exists('OC_Shell')) {
OC_Shell::register_screen('omailer', 'Omailer');
}
From that point on, your plugin’s admin pages render inside the suite shell, with a breadcrumb that says Orravo › Omailer › (current page).
Press Cmd+K
The palette is a filter-as-you-type list of every command registered by every Orravo plugin on the site. Hidden until you press ⌘K (or Ctrl+K on Windows). Default Core commands include Activate license, Refresh license status, Open System Status, and Create snapshot.
Add commands from your own plugin:
phpOC_Shell::register_commands([
[
'id' => 'omailer.compose',
'label' => 'Omailer · Compose campaign',
'section' => 'Omailer',
'href' => admin_url('admin.php?page=omailer&view=compose'),
'shortcut' => 'g c',
],
]);
// Or use the filter:
add_filter('orravo_command_palette_items', function (array $items) {
$items[] = [ 'id' => 'studio.deploy', 'label' => 'Studio · Deploy', 'section' => 'Studio' ];
return $items;
});
Inbox + log
Two surfaces: a per-user notifications inbox (the bell icon) and a site-wide activity log (the drawer). Push items from any plugin.
php// Push a notification visible to all admin users
orravo_notify([
'plugin' => 'omailer',
'level' => 'info', // info | warning | success | error
'title' => 'Campaign sent',
'message' => 'April newsletter delivered to 4,820 subscribers',
'link_url' => admin_url('admin.php?page=omailer&view=campaigns'),
]);
// Append to the activity log (no inbox, just an audit trail)
orravo_activity('omailer', 'Imported 318 subscribers from CSV', '/wp-admin/admin.php?page=omailer');
Six functions cover most of it
Defined in includes/class-oc-helper.php. All are namespace-free and idempotent (function_exists guarded), so they work alongside the Mini-Core shim.
| Function | Returns | Notes |
|---|---|---|
orravo_is_licensed($slug) | bool | True if active license covers the given product slug |
orravo_license_data() | ?array | Full cached payload (key, status, tier, products, sites, expiry) |
orravo_license_status() | string | active | expired | invalid | inactive |
orravo_license_tier() | string | single | studio | unlimited |
orravo_tier_at_least($tier) | bool | Tier comparison (single < studio < unlimited) |
orravo_is_staging() | bool | True if dev-site mode is on for this install |
orravo_notify($data) | int | Push a notification, returns the notification id |
orravo_activity($plugin, $msg, $link) | void | Append to the activity log |
orravo_log($level, $message) | void | Write to the Orravo debug log when enabled |
orravo_fire_event($event, $data) | void | Dispatch to any subscribed webhook endpoints |
Suite-shell facade
Use OC_Shell instead of reimplementing your own topbar, command palette, or breadcrumb. Idempotent (last write wins).
| Method | Signature |
|---|---|
register_screen | OC_Shell::register_screen(string $plugin_slug, string $label) |
register_command | OC_Shell::register_command(array $command) |
register_commands | OC_Shell::register_commands(array $commands) |
commands | OC_Shell::commands(): array (returns all registered, post-filter) |
Command shape:
php[
'id' => 'unique.id', // required, dot-namespaced
'label' => 'Visible label', // required
'section' => 'Plugin name', // groups commands in the palette
'href' => '/wp-admin/...', // optional, navigate on enter
'callback' => fn() => do_action(...) // optional, run on enter
'icon' => 'rocket', // optional, icon slug
'shortcut' => 'g c', // optional, e.g. 'g c' or 'cmd k'
]
Namespace orravo-core/v1
Every route lives under /wp-json/orravo-core/v1/. Logged-in admins skip token auth so the wp-admin UI can call these directly. External callers send X-OC-API-Key.
| Method | Route | Returns |
|---|---|---|
| GET | /license | Active license payload |
| GET | /products | Detected Orravo plugins on this install |
| GET | /system/status | PHP, WP, cron, table integrity, last revalidation |
| GET, POST, DELETE | /webhooks | List, create, remove webhook endpoints |
| GET, POST, DELETE | /api-keys | List, create, revoke scoped API keys |
curl$ curl -H "X-OC-API-Key: oc_live_..." https://yoursite.com/wp-json/orravo-core/v1/license
{
"key": "ORV-9F3K-7T2X-...",
"status": "active",
"tier": "studio",
"products": ["omailer","oforms","oads","ofeedback"],
"sites_used": 2,
"sites_max": 10,
"expires_at": 1762358400
}
Scoped access
Create per-integration API keys with one of three scopes: read (GET only), write (PUT, POST, DELETE on owned resources), admin (full surface). Hashes are stored, never the raw key.
Generate from the Developer tab or via WP-CLI:
wp-cli$ wp orravo api-key create "CRM integration" --scopes=read,write
oc_live_8K3F2X9TJ7RV4N8KQ2HF1...
HMAC-signed events
Outbound webhooks fire on suite-wide events (license_renewed, product_updated, snapshot_created, plus anything plugins push via orravo_fire_event()). Each dispatch is HMAC-SHA256 signed with the endpoint secret, headered as X-OC-Signature.
Verify on your end:
php$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_OC_SIGNATURE'] ?? '';
$secret = getenv('OC_WEBHOOK_SECRET');
if (! hash_equals(hash_hmac('sha256', $payload, $secret), $signature)) {
http_response_code(401);
exit;
}
$event = json_decode($payload, true);
// $event['type'] e.g. 'license_renewed'
// $event['site'] the originating site URL
// $event['data'] payload specific to the event
Failed dispatches are queued (table orravo_webhook_log) and retried via the orravo_webhook_retry cron with exponential backoff up to five attempts.
Extension points
| Hook | Type | Notes |
|---|---|---|
orravo_command_palette_items | filter | Add custom palette commands suite-wide |
orravo_command_items | filter | Legacy alias kept for back-compat |
orravo_license_activated | action | Fires after a successful license activation |
orravo_license_deactivated | action | Fires after deactivation |
orravo_license_revalidated | action | Daily cron, after the license payload refreshes |
orravo_webhook_retry | action | Cron target for failed dispatch retries |
orravo_core_revalidate | action | Daily cron tick (revalidates the license) |
orravo_core_update_check | action | Twice-daily cron (refreshes update channels) |
Scriptable everything
Loaded only under WP-CLI. Useful from CI, deploy hooks, and one-shot maintenance.
wp-cli$ wp orravo license activate ORV-9F3K-7T2X-RV4N-8KQ2
license activated · studio tier · 4 products · expires 2027-04-18
$ wp orravo license status
active · studio · sites 2/10 · last validated 4h ago
$ wp orravo product list
omailer 3.3.2 stable licensed
oforms 1.2.0 stable licensed
ofeedback 1.4.0 stable licensed
$ wp orravo snapshot create "Pre release"
snapshot #4 created
$ wp orravo doctor
tables ✓ · cron ✓ · license ✓ · 4/4 products active
vs. the alternatives
| Freemius | EDD Software Licensing | Custom-built | Orravo Core | |
|---|---|---|---|---|
| License key validation | paid tier | $199 yr | manual | ✓ |
| Per-site activation tracking | ✓ | $199 yr | manual | ✓ |
| Auto-detect installed products | no | no | no | ✓ |
| Unified suite shell + Cmd+K palette | no | no | no | ✓ |
| REST API + WP-CLI + scoped API keys | paid tier | ✓ | manual | ✓ |
| Snapshots + rollback | no | no | no | ✓ |
| Mini-Core fallback (works without Core) | no | no | no | ✓ |
| Pricing | $99 + 20% rev share | $199 yr | time + risk | Free forever |
Free. Forever.
Orravo Core is the licensing client itself. Charging for it would mean charging twice for the same plugin. Premium plugins fund the work.
- License client + per-site activations
- Suite shell + Cmd+K command palette
- REST API + WP-CLI + scoped API keys
- Outbound HMAC-signed webhooks
- Snapshots + one-click rollback
- Channel-aware updater (stable / beta / nightly)
- Mini-Core fallback for offline use
Recent releases
- Self-healing license table on version mismatch (Audit P0-002)
- System Status surfaces stale-cron warnings via
orravo_core_revalidate_last_run - Sibling plugins merge into the palette via
orravo_command_palette_items(Audit P1-007 / F6) - De-duplicated submenu entries; one submenu per tab (Audit P0-004)
- Added scoped API keys with per-key revocation
- Outbound webhooks moved to a queued retry model (exponential backoff)
- Snapshots now bundle every Orravo plugin’s settings, not just Core
- Cmd+K command palette ships across the entire suite
OC_Shellfacade introduced for screen and command registration- Mini-Core fallback shim documented and adopted by every paid plugin
Power the whole Orravo suite.
One install, one set of tables, one shared admin chrome. Every other Orravo plugin gets thinner because of it.
