Data Sovereignty Principle
Both the plugin and theme own all their data in custom database tables. This is a fundamental architectural decision.
Why Custom Tables?
- Performance — Optimized schema, proper indexes, no EAV overhead
- Independence — No dependency on WordPress options table
- Scalability — Can handle thousands of products/orders efficiently
- Clean separation — Plugin data and theme data don't interfere
Plugin Data Access
Configuration
// Store plugin settings
wpec_set_option('store_name', 'My Store', 'general');
wpec_get_option('store_name', 'Default Store');
// NEVER do this:
update_option('wpec_store_name', 'My Store'); // WRONG!
get_option('wpec_store_name'); // WRONG!
Cache
// Plugin cache (custom ec_cache table)
wpec_cache_set('product_count', 150, 3600); // TTL in seconds
$count = wpec_cache_get('product_count');
// NEVER do this:
set_transient('wpec_product_count', 150, 3600); // WRONG!
Theme Data Access
Configuration
// Store theme settings
flavor_set_option('header_sticky', 'true', 'header');
flavor_get_option('header_sticky', 'false');
// NEVER do this:
get_option('flavor_options'); // WRONG! The blob was deleted in v3.2.5
update_option('flavor_header_sticky', 'true'); // WRONG!
Cache
// Theme cache (custom flavor_cache table)
flavor_cache_set('menu_html', $html, 1800);
$html = flavor_cache_get('menu_html');
// IMPORTANT: flavor_cache_get() returns null (not false)
$val = flavor_cache_get('counter');
if ($val !== null) { /* exists */ }
// For integer casts with default:
$count = (int) flavor_cache_get('counter', 0);
// NEVER do this:
set_transient('flavor_menu_html', $html, 1800); // WRONG!
Module Settings
Module settings use dedicated option keys:
// Correct — dedicated key per module
flavor_set_option('wishlist_enabled', 'true', 'flavor_module_wishlist');
flavor_get_option('wishlist_enabled', 'false', 'flavor_module_wishlist');
// Wrong — shared options blob
flavor_set_option('wishlist_enabled', 'true'); // Don't pollute default group
WordPress Data (Read-Only)
For data that belongs to WordPress, use standard functions:
// These are fine — reading WordPress-owned data
get_option('admin_email');
get_option('date_format');
get_option('permalink_structure');
Type Safety
flavor_get_option() has built-in type safety:
// If caller passes array default but DB stores a scalar,
// it returns the default array (prevents crashes)
$colors = flavor_get_option('brand_colors', ['#000', '#fff']);
// If DB has scalar string → returns ['#000', '#fff']
// If DB has proper JSON array → returns parsed array