Skip to main content

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 is WPECommerce\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 groupExample tables
Infrastructureec_options, ec_cache, ec_migrations
Catalog — productsec_products, ec_product_variants, ec_brands
Catalog — taxonomyec_categories, ec_attributes, ec_attribute_terms
Customersec_customers, ec_addresses
Ordersec_orders, ec_order_items
Paymentsec_payments
Shippingec_shipments, ec_shipping_zones, ec_shipping_methods
Taxec_tax_classes, ec_tax_rates
Couponsec_coupons, ec_coupon_usage
Reviewsec_reviews, ec_review_images
ERP — Invoicing/myDATAec_invoice_series, ec_invoices, ec_invoice_lines, ec_mydata_log
ERP — Inventory/WMSec_warehouses, ec_stock_levels, ec_stock_movements
ERP — Purchasingec_suppliers, ec_purchase_orders, ec_goods_received, ec_supplier_prices
ERP — Accounting/GLec_accounts, ec_fiscal_years, ec_journal_entries, ec_journal_lines
ERP — CRMec_contacts, ec_leads, ec_activities
ERP — HRec_employees, ec_departments, ec_leave_requests, ec_time_entries, ec_ergani_submissions
note

Always reference tables via $wpdb->prefix in code — never hardcode wp_.

Theme tables ({prefix}flavor_*) — 4 tables

TablePurpose
flavor_optionsTheme config store (per-key rows with groups/autoload)
flavor_cacheTheme cache store (replaces transients)
flavor_migrationsExecuted theme migration tracking
flavor_search_logSearch 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:

TablePurpose
flavor_core_dataSensitive data (license cache, fingerprint token) — AES-256-GCM encrypted
flavor_core_optionsNon-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