OCart v1.0.0-alpha
A WooCommerce conversion and funnel engine: custom checkout layouts, order bumps, one-click post-purchase upsells, abandoned-cart recovery sequences, and native Bayesian A/B testing. Twelve database tables, idempotent gateway charges, REST + WP-CLI surface, native suite integration with OMailer, OConvert, OIntel.
What OCart does
OCart sits on top of WooCommerce. It replaces the default checkout with configurable funnel layouts, layers order bumps and post-purchase upsells on top, recovers abandoned carts through email and SMS sequences, and ships native A/B testing for every surface.
Getting installed
general.replace_woo_checkout = false.ocart folder to /wp-content/plugins/ and activate via Plugins → Installed Plugins.{prefix}ocart_), registers capabilities, declares HPOS and cart-checkout-blocks compatibility via WooCommerce's FeaturesUtil.Requirements
First funnel in 5 minutes
From fresh activation to a live two-step checkout with one bump and one post-purchase upsell.
two_step layout.fixed_addon pricing of $24, save.discount_pct: 50, save. The default branch fires after parent capture.[ocart_checkout funnel="your-slug"] into a page, or set the funnel as the default checkout in Settings.wp ocart cart list --status=active to confirm carts are flowing in.Plugin architecture
12 database tables
All prefixed with {prefix}ocart_. Created on activation through dbDelta. Hot queries are indexed: find active funnel for cart, find pending recovery runs, look up idempotency keys for in-flight charges.
| Table | Purpose |
|---|---|
ocart_funnels | Funnel records: name, status (draft / active / archived), trigger_rules, settings (theme + layout) |
ocart_funnel_steps | Per-funnel steps: type (checkout / bump / upsell / downsell / thank_you / custom), position, branch (default / accepted / declined) |
ocart_carts | Cart sessions: session_token (UNIQUE), email, phone, items + totals JSON, status (active / abandoned / converted / expired) |
ocart_recovery_sequences | Recovery sequence templates: trigger_type (cart_abandoned / checkout_abandoned / browse_abandoned), steps JSON |
ocart_recovery_runs | One row per cart entering a sequence: current_step, status (pending / running / converted / stopped), revenue_recovered |
ocart_offers | Bump / upsell / downsell records: pricing_rule, targeting_rules, display_config (all JSON) |
ocart_offer_events | Every offer surface event. idempotency_key CHAR(36) is UNIQUE; gateway charges replay-safe |
ocart_tests | A/B tests: surface (checkout / bump / upsell / recovery_email / recovery_sms), method (frequentist / bayesian / bandit), winner_variant |
ocart_test_assignments | Per-cart variant assignment with conversion + revenue, used to compute results |
ocart_suppression | Email + phone suppression list. Reasons: bounce / complaint / unsubscribe / manual / winback_failed |
ocart_deliverability_events | Send / open / click / bounce / complaint events for email + SMS recovery |
ocart_audit_log | Every admin action with diff, user, object, IP, timestamp |
Admin interface
Top-level menu OCart with eleven submenus. Built with wp-element (React) and wp-api-fetch for first-party WordPress feel.
| Submenu | Slug | Capability |
|---|---|---|
| Dashboard | ocart | ocart_manage |
| Funnels | ocart-funnels | ocart_manage_funnels |
| Checkout | ocart-checkout | ocart_manage_funnels |
| Bumps | ocart-bumps | ocart_manage_offers |
| Upsells | ocart-upsells | ocart_manage_offers |
| Recovery | ocart-recovery | ocart_manage_recovery |
| Tests | ocart-tests | ocart_manage_tests |
| Templates | ocart-templates | ocart_manage_funnels |
| Migration | ocart-migration | ocart_run_migration |
| Reports | ocart-reports | ocart_view_reports |
| Integrations | ocart-integrations | ocart_manage |
| Settings | ocart-settings | ocart_manage |
Settings reference
All settings stored in wp_options under key ocart_settings as a single nested array. Access via OCart_Settings::get('group.key').
general
| Key | Default | Description |
|---|---|---|
enabled | true | Master kill-switch |
replace_woo_checkout | false | Force-replace the Woo checkout. Default false (shadow mode) |
log_level | warning | debug / info / warning / error |
recovery
| Key | Default | Description |
|---|---|---|
capture_email_debounce_ms | 800 | Debounce for capturing checkout email keystrokes |
consent_required | true | Require explicit consent for recovery dispatch |
cart_retention_days | 90 | Cart row retention window |
test_assignment_days | 365 | Assignment row retention |
deliverability_days | 180 | Deliverability events retention |
upsells
| Key | Default | Description |
|---|---|---|
one_click_token_ttl_min | 30 | One-click token lifetime, in minutes |
order_strategy_default | A | A = child order, B = merge (with fallback) |
merge_cutoff_min | 5 | Strategy B falls back to A after this many minutes |
sca_modal_enabled | true | Render SCA modal inline when 3DS challenge fires |
tests
| Key | Default | Description |
|---|---|---|
method_default | bayesian | frequentist / bayesian / bandit |
mde_relative | 0.10 | Default minimum detectable effect |
power_target | 0.80 | Default statistical power |
significance | 0.95 | Default significance threshold |
srm_threshold | 0.02 | Sample-ratio mismatch alert threshold |
Checkout layouts
Drop-in replacement for the Woo checkout. Three layouts ship in alpha (one_step, two_step, three_step) and the layout is a per-funnel setting, not a per-site setting.
FeaturesUtil::declare_compatibility(). OCart works with classic shortcode checkout, the cart-checkout blocks, and HPOS.Render
[ocart_checkout funnel="holiday-2026"]
// or pick the layout explicitly
[ocart_checkout funnel="holiday-2026" layout="two_step"]
Order bumps
Add-on offers shown on the checkout page itself. Position is configurable (above payment, in shipping, in summary) and targeting rules accept cart total, product-in-cart, and category-in-cart predicates.
Pricing rule shapes
| type | Fields | Example |
|---|---|---|
fixed_addon | amount | Add $24 once |
percent_addon | value | Add 10% of cart subtotal |
free_gift | product_id | Free product if cart_min_total met |
Post-purchase upsells
After the parent order is captured, OCart issues a one-click upsell. If accepted, an idempotent charge fires against the saved gateway token. The idempotency_key column on ocart_offer_events is UNIQUE; replays of the same key never double-bill.
payment_intent.succeeded or PayPal capture). OCart mints an idempotency key for this customer + offer pair.POST /upsells/issue-token.POST /upsells/{id}/accept writes the offer_event row inside a transaction. UNIQUE constraint on idempotency_key returns 409 on replay.parent_order_id set. Strategy B: the parent order is amended (with a 5-minute cutoff that falls back to A).Cart recovery
Sequences fire when carts hit the abandoned threshold. Email and SMS channels with full delivery tracking, suppression list, and DKIM / SPF deliverability checks built in.
Sequence step shape
{
"channel": "email", // email | sms
"delay_min": 30, // minutes after trigger
"template": "cart_nudge_1",
"discount": 10, // optional, percent
"ab_test": 123 // optional, bind to test id
}
Trigger types
- cart_abandoned: cart sits idle past
recovery.abandoned_threshold_min - checkout_abandoned: cart reached checkout step but did not complete
- browse_abandoned: viewed product, did not add to cart (requires browse capture)
Native A/B testing
Tests bind to any surface (checkout / bump / upsell / recovery_email / recovery_sms). Three methods: frequentist (z-test), Bayesian (Beta-Binomial posterior), or multi-armed bandit (Thompson sampling).
Test record fields
| Field | Type | Notes |
|---|---|---|
method | enum | frequentist / bayesian / bandit |
mde_relative | decimal(5,4) | Minimum detectable effect, e.g. 0.05 = 5% relative lift |
power_target | decimal(3,2) | Statistical power target (default 0.80) |
significance | decimal(3,2) | Significance threshold (default 0.95) |
winner_variant | varchar(64) | Set on conclusion; null while running |
WooCommerce integration hooks
OCart is a WooCommerce-first plugin. The bootstrap guards on WooCommerce being loaded; if missing, OCart self-disables with an admin notice.
| WC hook | OCart usage |
|---|---|
before_woocommerce_init | Declare HPOS + cart-checkout-blocks compatibility |
woocommerce_checkout_order_processed | Capture parent order, mint idempotency keys, queue upsell render |
woocommerce_thankyou | Render post-purchase upsell page |
woocommerce_payment_complete | Write recovery_run conversion if cart was in active sequence |
woocommerce_cart_updated | Snapshot cart to ocart_carts for recovery |
HPOS + blocks
High-Performance Order Storage and the cart-checkout blocks are both declared compatible via WooCommerce's FeaturesUtil. OCart writes to wp_wc_orders through Woo's data store layer, never raw SQL on order tables.
add_action('before_woocommerce_init', function () {
if (class_exists(\Automattic\WooCommerce\Utilities\FeaturesUtil::class)) {
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
'custom_order_tables', __FILE__, true
);
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility(
'cart_checkout_blocks', __FILE__, true
);
}
});
Gateways & idempotency
Stripe and PayPal in alpha. The gateway adapter exposes capture_with_token($order, $amount, $idempotency_key). The UNIQUE column on ocart_offer_events.idempotency_key enforces replay safety at the database layer.
Shortcodes
[ocart_checkout funnel="holiday-2026"]
[ocart_checkout funnel="holiday-2026" layout="two_step"]
[ocart_cart_count]
[ocart_cart_icon]
REST API
All routes namespaced under ocart/v1. The OpenAPI spec is served at /wp-json/ocart/v1/openapi.
| Method | Route | Purpose |
|---|---|---|
| GET | /ocart/v1/ping | Health check |
| GET | /ocart/v1/info | Plugin version + active engines |
| GET | /ocart/v1/openapi | OpenAPI 3.1 spec |
| GET | /ocart/v1/reports/dashboard | Dashboard rollups (orders, AOV, conv, recovery) |
| GET / POST / PATCH / DELETE | /ocart/v1/bumps + /{id} | Bump CRUD |
| POST | /ocart/v1/bumps/{id}/accept | Record bump acceptance + write offer_event |
| POST | /ocart/v1/bumps/{id}/decline | Record bump decline |
| GET | /ocart/v1/bumps/eligible | Bumps eligible for the current cart |
| GET / POST / PATCH / DELETE | /ocart/v1/upsells + /{id} | Upsell CRUD |
| POST | /ocart/v1/upsells/{id}/accept | One-click accept; idempotent |
| POST | /ocart/v1/upsells/{id}/decline | Decline; triggers downsell branch if configured |
| POST | /ocart/v1/upsells/issue-token | Mint a one-click upsell token |
| POST | /ocart/v1/upsells/confirm | SCA / 3DS confirmation callback |
| GET | /ocart/v1/gateways | Active gateway adapters |
| GET / POST | /ocart/v1/recovery/sequences | Recovery sequence CRUD |
| GET | /ocart/v1/recovery/runs | Recovery runs list |
| POST | /ocart/v1/recovery/runs/{id}/stop | Stop a running recovery |
| GET | /ocart/v1/recovery/deliverability | Deliverability events feed |
| POST | /ocart/v1/recovery/dns-check | DKIM + SPF check for sender domain |
| GET / POST / DELETE | /ocart/v1/recovery/suppression | Suppression list management |
| GET / POST / PATCH / DELETE | /ocart/v1/tests + /{id} | A/B test CRUD |
| POST | /ocart/v1/tests/{id}/start | Start a test |
| POST | /ocart/v1/tests/{id}/stop | Stop a test |
| GET | /ocart/v1/tests/{id}/results | Live test results (variant conv, prob_b_wins) |
| GET | /ocart/v1/tests/{id}/sample-size | Sample-size calculator output |
| POST | /ocart/v1/checkout/capture | Capture checkout email + cart for recovery |
Developer hooks
OCart routes every event through OCart_Events::dispatch(), which mirrors to do_action. Hook with the standard add_action; payload reaches you regardless of whether the dispatcher or the WP action wakes first.
| Hook | Args | Fired |
|---|---|---|
ocart/booted | (none) | After every engine has registered |
ocart/cart/created | $cart | New cart row written |
ocart/cart/abandoned | $cart | Cart crossed the abandoned threshold |
ocart/cart/converted | $cart, $order_id | Cart marked converted on order capture |
ocart/bump/shown | $offer_event | Bump rendered to a shopper |
ocart/bump/accepted | $offer_event | Bump accepted |
ocart/upsell/before_charge | $ctx | Just before idempotent gateway charge fires |
ocart/upsell/accepted | $offer_event | Upsell accepted, child order written |
ocart/upsell/declined | $offer_event | Upsell declined; downsell branch evaluates next |
ocart/recovery/dispatched | $run, $step | Recovery channel dispatched (email or SMS) |
ocart/recovery/converted | $run, $order_id | Recovery sequence converted |
ocart/test/assigned | $test_id, $variant, $cart_id | Variant chosen for a cart |
ocart/test/concluded | $test_id, $winner | Test reached significance + winner set |
Helper functions
A small global surface for the most-used reads and writes. Everything else is on the namespaced OCart\\ classes.
| Function | Returns | Notes |
|---|---|---|
ocart_log($msg, $ctx = []) | void | Structured log at info level |
ocart_user_has_purchased($user_id, $product_id) | bool | Checks Woo orders + ocart child orders |
ocart_active_funnel_for_cart($cart_id) | ?Funnel | Resolves a cart to its active funnel |
ocart_get_setting($path, $default = null) | mixed | Sugar over OCart_Settings::get() |
ocart_dispatch($event, ...$args) | void | Sugar over OCart_Events::dispatch() |
WP-CLI
Eight namespaced commands. Useful in CI, deploys, and for quick spot checks during incident response.
| Command | Purpose |
|---|---|
wp ocart funnel | Funnel CRUD + activate / archive |
wp ocart cart | List, show, mark converted / abandoned |
wp ocart recovery | Sequence CRUD, dispatch, suppression |
wp ocart test | Test CRUD + start / stop / results |
wp ocart migration | Import from CartFlows / FunnelKit |
wp ocart gateway | Gateway adapter status + token rotation |
wp ocart template | Funnel template install / list |
wp ocart export | Export funnels, offers, sequences as JSON |
wp ocart cart list --status=abandoned --since=24h
wp ocart test 7 results
wp ocart recovery dispatch --dry-run
wp ocart migration import --from=cartflows
Capabilities
Five area capabilities so OCart areas can be split between roles. Granted to administrator on activation. Other roles inherit nothing.
| Capability | Grants |
|---|---|
ocart_manage | Top-level access; settings, integrations |
ocart_manage_funnels | Funnel + checkout + templates CRUD |
ocart_manage_offers | Bump + upsell + downsell CRUD |
ocart_manage_recovery | Recovery sequences, suppression, deliverability |
ocart_manage_tests | A/B tests CRUD + start / stop |
ocart_view_reports | Read-only access to reports |
ocart_run_migration | Run migration importers (destructive) |
Suite integration
First-party bridges to the rest of the Orravo suite. Each bridge auto-detects the partner plugin; if missing, it stays inert.
| Plugin | What OCart sends |
|---|---|
| OMailer | Recovery sequence dispatch goes through OMailer's transactional queue with full deliverability events. |
| OConvert | Cart events feed OConvert's CRO triggers (exit-intent on checkout, progress nudges). |
| OIntel | Every commerce event mirrors to OIntel's event sink for warehouse export. |
| OEngage | Optional XP awards on conversion; opt-in per funnel. |
Comparison
CartFlows, FunnelKit, and the WooCommerce add-on stack each cover a slice of OCart's scope. OCart is the whole funnel and recovery layer in one install.
| Capability | CartFlows | FunnelKit | WC + add-ons | OCart |
|---|---|---|---|---|
| Custom checkout layouts | ✓ | ✓ | no | ✓ |
| Order bumps | ✓ | ✓ | no | ✓ |
| Post-purchase upsells | ✓ | ✓ | no | ✓ |
| Idempotent gateway charges | partial | partial | no | ✓ |
| Email + SMS recovery | paid add-on | paid add-on | no | ✓ |
| Bayesian + bandit A/B | no | no | no | ✓ |
| Suppression + deliverability | no | no | no | ✓ |
| HPOS + blocks declared | ✓ | ✓ | ✓ | ✓ |
| REST + WP-CLI surface | partial | partial | no | ✓ |
| Audit log | no | no | no | ✓ |
| Price | $249/yr | $249+/yr stack | free + addons | $99 once |
Plans & pricing
One-time alpha pricing locks in lifetime updates through the v1.0 stable release and every release after.
- 1 production WooCommerce store
- All 12 tables, all surfaces
- Full REST + WP-CLI
- Email support · 48hr
- Up to 10 production sites
- All features
- Priority support · 24hr
- White-label admin labels
- Free onboarding call
- Unlimited production sites
- All features
- Same-day priority support
- Recovery + A/B starter pack
- Custom integration sprint
What's shipped
- Custom checkout layouts: one_step, two_step, three_step
- Visual funnel builder with steps + branches (default / accepted / declined)
- Order bumps with cart_min_total, product_in_cart, category_in_cart targeting
- Post-purchase upsells with idempotent gateway charges (Stripe + PayPal)
- Post-purchase downsells on upsell decline
- Cart recovery sequences (email + SMS) with delivery tracking
- Suppression list (bounce / complaint / unsubscribe / manual / winback_failed)
- Deliverability events log with DKIM + SPF check endpoint
- A/B testing: frequentist, Bayesian (Beta-Binomial), multi-armed bandit (Thompson)
- Sample-size calculator endpoint per test
- HPOS + cart-checkout blocks compatibility declared via FeaturesUtil
- Typed event bus (
OCart_Events) over do_action - Capability-scoped admin (5 area capabilities)
- REST surface under
ocart/v1with OpenAPI spec - WP-CLI: 8
wp ocartcommands - Audit log of every admin action
- CartFlows + FunnelKit migration importer (alpha quality)
- Suite bridges: OMailer (transactional), OConvert (CRO), OIntel (analytics)
- 12 custom DB tables, full uninstall cleanup
- Visual funnel builder polish
- CartFlows + FunnelKit importer hardening (round-trip safe)
- Apple Pay + Google Pay one-click
- Subscription-aware recovery (works alongside OSubscribe)
- Multi-currency pricing rules
- Per-funnel role assignment
- Documentation: full PHP-Doc surface coverage
Got a question about OCart?
Reach out directly. Kenneth replies within 24 hours.
