StoreEngine Architecture Overview
StoreEngine is layered: a small bootstrap boots the engine, an addon framework loads features on demand, a PSR-4 autoloader wires up classes, and everything sits on a custom-table data layer with a REST API, hooks system, and a template-driven frontend. This page explains each layer and how they connect.
The layers
Bootstrap: the StoreEngine singleton
The main file storeengine.php defines a final class StoreEngine singleton. Its constructor drives startup in a deliberate order:
- Define constants — paths, URLs, version, and table names.
- Load dependencies — pull in the autoloader and Composer's vendor autoload. If core files are missing (e.g. an interrupted update), it bails with an admin notice rather than fataling.
- Register lifecycle hooks —
register_activation_hook,register_deactivation_hook, and a shutdown error logger. - Boot settings and installer —
Settings::load_settings()andStoreEngine\Installer::init()create/upgrade tables and register options. - Initialize subsystems on WordPress hooks — addons, REST API, admin, AJAX, frontend, hooks, integrations, schedules, shortcodes, and blocks.
final class StoreEngine {
protected static ?StoreEngine $instance = null;
public ?Customer $customer = null;
public ?Cart $cart = null;
// …
}
The singleton is the composition root: it is the object other subsystems reach for the current cart, customer, and shared services.
The addon framework
The defining architectural choice: core features and commerce features ship as addons that can be toggled. Payment gateways (Stripe, PayPal, Razorpay, Paddle), subscriptions, memberships, affiliates, multi-currency, invoicing, and more are all addons living under addons/.
\StoreEngine\Addons loads them. Its addons_loader() reads a slug → class map through the storeengine/addons/loader_args filter, then for each addon:
- registers the addon's namespace and directory with the autoloader,
- initializes the addon's main class (which extends
\StoreEngine\Classes\AbstractAddon) and callsrun(), - tracks active addons so their schema is kept in sync.
Only active addons participate in schema syncing. Every addon declares a get_db_version(); the manager compares it against the single storeengine_addons_db_version option and reruns install_tables() on a mismatch — no per-addon option or bespoke upgrade hook required.
Because the addon map runs through storeengine/addons/loader_args, a third-party plugin can register its own addon into StoreEngine's framework by filtering that array. See Building Addons.
Pro reuses this exact machinery via its own storeengine_pro/addons/loader_args filter and shares the core's \StoreEngine\Addons::sync_schema_for(). See Free vs Pro.
PSR-4 autoloading
Classes load through includes/autoload.php (StoreEngine\Autoload), a lightweight PSR-4 resolver kept as a singleton via Autoload::get_instance(). It maps namespaces to directories:
private array $autoload_directories = [
'StoreEngine' => STOREENGINE_ROOT_DIR_PATH . 'includes/',
'StoreEngine\Payment\Gateways' => STOREENGINE_INCLUDES_DIR_PATH . 'payment-gateways/',
];
Class names are transformed to lowercase, hyphenated file paths (e.g. StoreEngine\Classes\Cart → includes/classes/cart.php). Addons extend the map at runtime:
Autoload::get_instance()->add_namespace_directory(
'StoreEnginePro\\Addons\\Subscription',
STOREENGINE_PRO_ADDONS_DIR_PATH . 'subscription/'
);
Third-party Composer packages are vendored and Strauss-prefixed to avoid collisions with other plugins, loaded via Composer's own autoloader.
Data layer: custom tables + CPTs
StoreEngine splits persistence by access pattern:
- Custom tables (
wp_storeengine_*) back high-volume, relational data — orders, order items, order meta, addresses, carts, subscriptions, payment tokens, product prices/variations, shipping zones, and more. Schemas live ascreate-*.phpfiles underincludes/database/. - Custom post types back editable catalog entities —
storeengine_productandstoreengine_coupon— so they use the standard WordPress editor and taxonomy machinery.
Domain classes (includes/classes/) and models (includes/models/) provide the object API over this storage. Read and write orders through these, never through WP_Query.
Orders and subscriptions are rows in storeengine_orders, discriminated by a type column. Treat post-based order queries from other plugins as inapplicable here. See Data & Objects.
REST API
The REST layer (includes/api/, bootstrapped by \StoreEngine\API) registers controllers under the storeengine/v1 namespace — cart, checkout, orders, products, customers, payments, payment methods, settings, shipping, coupons, analytics, and storefront auth, among others. It powers the admin React app, the storefront, and external integrations alike. See REST API.
Hooks system
StoreEngine exposes an extensive set of actions and filters namespaced under storeengine/…. Addons and integrations hook the commerce lifecycle — cart changes, checkout, order status transitions, payments — to add behavior without patching core. The addon loader map itself (storeengine/addons/loader_args) is a filter. See Actions and Filters.
Frontend
The storefront is rendered through three cooperating mechanisms:
- Templates — PHP partials in
templates/, overridable from a theme atyourtheme/storeengine/{template}.php. See Templates. - Shortcodes —
includes/shortcode/renders store surfaces (checkout, account, product listings) that can be dropped into any page. - Blocks —
includes/blocks/bridges shortcodes into Gutenberg blocks so the same surfaces are available in the block editor.
Where to go next
- Plugin Structure — an annotated map of the directories referenced above.
- Building Addons — apply the addon framework in practice.
- Data & Objects — the domain object API over the data layer.