Architecture Overview
Domain-Driven Design
Both the plugin and theme follow DDD principles with clear layer separation. The plugin has the deeper stack (it carries the full commerce + ERP domain); the theme uses a lighter DDD bootstrap around its module and builder systems.
Plugin Layers
The plugin source tree (wp-ecommerce-core/src/) has 8 top-level layers:
wp-ecommerce-core/src/
├── Application/
│ ├── Sanitization/ # Input sanitization
│ └── Services/ # Use-case orchestration (OrderService, StockService, CartService, …)
│ └── Marketplace/ # Skroutz / BestPrice feed services
├── Domain/
│ └── Entities/ # Domain entities (Product, Order, Customer, Invoice, Address, …)
├── Erp/
│ ├── Integration/ # Cross-module sync listeners (*Sync)
│ └── Onboarding/ # ERP setup / onboarding flow
├── Gateways/ # ← top-level (NOT under Infrastructure)
│ ├── Contracts/ # Gateway interfaces
│ ├── Drivers/ # Payment gateway drivers
│ ├── Shipping/ # Couriers: Acs, Elta, Geniki
│ ├── MyData/ # AADE myDATA transmission
│ └── Ergani/ # ΕΡΓΑΝΗ II (HR) integration
├── Infrastructure/
│ ├── Database/ # Schema / migrations
│ ├── Repositories/ # ← Repository implementations live HERE
│ └── Security/ # Encryption, capability helpers
├── Licensing/ # Tiered feature-gating (LicenseGate + traits)
│ └── Traits/
├── Presentation/
│ ├── Admin/ # Admin screens
│ ├── Api/ # REST controllers (ec/v1) + Traits/
│ └── Storefront/ # Front-end rendering
└── Support/ # Shared utilities / helpers
Two structural facts that trip people up:
- Gateways are a top-level layer (
src/Gateways/), not a sub-folder of Infrastructure. Payment drivers, couriers, myDATA and Ergani all live here. - Repository implementations live in
Infrastructure/Repositories/— the namespace isWPECommerce\Core\Infrastructure\Repositories, not…\Persistence.
The Erp/, Licensing/ and Support/ layers are first-class — the ERP domain
(Invoicing/myDATA, Inventory/WMS, Purchasing, Accounting/GL, CRM, HR) is a large
part of the plugin, not an add-on.
Theme Layers
flavor-starter/inc/
├── core/
│ ├── Bootstrap.php # Flavor_Bootstrap singleton, DDD boot
│ ├── Container.php # Flavor_Container (DI)
│ └── helpers.php # Infrastructure helpers (flavor_app, flavor_container, …)
├── infrastructure/ # Theme infrastructure services
├── modules/ # Module System 2.0 (ModuleManager, AbstractModule)
├── builder/ # Page-builder block registry + block renderers
├── flavor-builder/ # Builder admin / Puck integration
├── theme-options/ # Flavor Options (settings)
└── translations/ # Translation system (flavor_t / flavor_te)
Dependency Injection
Both products ship a custom DI container. The plugin container supports
bind()/singleton()/instance() and reflection-based auto-wiring; the theme
container is lighter (singleton()/instance() only, no auto-wiring). Both
resolve services with resolve() — see the Dependency Injection
page for the exact API and accessor helpers.
// Plugin — register a singleton with a closure, then resolve it
$container->singleton(OrderService::class, function ($c) {
return new OrderService(
$c->resolve(OrderRepository::class),
$c->resolve(PaymentGateway::class)
);
});
$orderService = $container->resolve(OrderService::class);
Database Architecture
Flavor owns its data in purpose-built custom tables — dozens of them, grouped
by domain — never the wp_options blob or EAV post-meta. See
Data Sovereignty for the access rules.
Plugin tables ({prefix}ec_*) — grouped by domain
The plugin ships ~50 custom tables across these domain groups (representative
tables shown; the full enumerated list is maintained in the internal
ARCHITECTURE_REFERENCE.md):
| Domain group | Example tables |
|---|---|
| Infrastructure | ec_options, ec_cache, ec_migrations |
| Catalog — products | ec_products, ec_product_variants, ec_brands |
| Catalog — taxonomy | ec_categories, ec_attributes, ec_attribute_terms |
| Customers | ec_customers, ec_addresses |
| Orders | ec_orders, ec_order_items |
| Payments | ec_payments |
| Shipping | ec_shipments, ec_shipping_zones, ec_shipping_methods |
| Tax | ec_tax_classes, ec_tax_rates |
| Coupons | ec_coupons, ec_coupon_usage |
| Reviews | ec_reviews, ec_review_images |
| ERP — Invoicing/myDATA | ec_invoice_series, ec_invoices, ec_invoice_lines, ec_mydata_log |
| ERP — Inventory/WMS | ec_warehouses, ec_stock_levels, ec_stock_movements |
| ERP — Purchasing | ec_suppliers, ec_purchase_orders, ec_goods_received, ec_supplier_prices |
| ERP — Accounting/GL | ec_accounts, ec_fiscal_years, ec_journal_entries, ec_journal_lines |
| ERP — CRM | ec_contacts, ec_leads, ec_activities |
| ERP — HR | ec_employees, ec_departments, ec_leave_requests, ec_time_entries, ec_ergani_submissions |
Always reference tables via $wpdb->prefix in code — never hardcode wp_.
Theme tables ({prefix}flavor_*) — 4 tables
| Table | Purpose |
|---|---|
flavor_options | Theme config store (per-key rows with groups/autoload) |
flavor_cache | Theme cache store (replaces transients) |
flavor_migrations | Executed theme migration tracking |
flavor_search_log | Search analytics (daily-cleanup cron, configurable retention) |
Flavor Core tables ({prefix}flavor_core_*) — 2 tables
Flavor Core (the license/update/debug product) owns its own data too:
| Table | Purpose |
|---|---|
flavor_core_data | Sensitive data (license cache, fingerprint token) — AES-256-GCM encrypted |
flavor_core_options | Non-sensitive settings (mode, channel, MCP toggle, migration markers) |
Entry Points
Plugin
// wp-ecommerce-core/wp-ec.php (plugin header + FLAVOR/WPEC constants; version at L6 + L27)
// → includes/Bootstrap.php (WPECommerce\Core\Bootstrap — Singleton, Bootstrap::instance())
// → Container registration (includes/Container.php)
// → Service providers loaded
// → REST routes registered (WPEC_REST_NAMESPACE = 'ec/v1', wp-ec.php:42)
Theme
// flavor-starter/functions.php
// → inc/core/Bootstrap.php (Flavor_Bootstrap::instance())
// → ModuleManager loads active modules (\Flavor\Modules\ModuleManager::getInstance())
// → Flavor Options + builder registered