Major improvements to WooNooW Page Editor system: Schema & Architecture: - Canonical section schema with unified sectionSchema.ts - Normalized feature-grid to use items (not features) - Standardized default values across all section types - Schema versioning with automatic migration on read Backend (PHP): - Enhanced PlaceholderRenderer with typed output contracts - Added fallback behavior for empty/invalid dynamic sources - Added caching support for post data resolution - New SchemaMigration class for backward compatibility - New Features class for feature flags - Enhanced PageSSR with full style support - Removed controller-level special-casing for related_posts Frontend (Admin SPA): - Updated CanvasRenderer with schema-aware transformation - Enhanced InspectorPanel with canonical schema metadata - Added new section renderers Frontend (Customer SPA): - New section components: BentoCategoryGrid, MarqueeBanner, ProductCarousel, ShoppableImage - Updated FeatureGridSection for items prop contract Testing: - Add PHP tests: SchemaMigrationTest, PlaceholderRendererTest, PageSSRTest - Add TypeScript tests: schema-integration, feature-grid-regression - Add parity tests for React vs SSR content matching - Add CI script: check-schema-drift.mjs - Add VERIFICATION_CHECKLIST.md Documentation: - RELEASE_NOTES-v1.0.md with full release notes - docs/PAGE_EDITOR_SECTION_SCHEMA_V1.md - docs/PAGE_EDITOR_SSR_COVERAGE_AUDIT.md
175 lines
4.2 KiB
PHP
175 lines
4.2 KiB
PHP
<?php
|
|
namespace WooNooW;
|
|
|
|
/**
|
|
* Feature Flags
|
|
* Manages feature toggles for staged rollout of new features
|
|
*/
|
|
class Features
|
|
{
|
|
/**
|
|
* Feature flag defaults
|
|
*/
|
|
private static $defaults = [
|
|
'dynamic_preview' => false, // Enable template preview with real data
|
|
'schema_v1' => true, // Use v1 schema with migrations
|
|
'enhanced_ssr' => true, // Enhanced SSR with full style support
|
|
'placeholder_cache' => true, // Cache resolved placeholders
|
|
];
|
|
|
|
/**
|
|
* Get a feature flag value
|
|
*
|
|
* @param string $feature Feature name
|
|
* @param bool $default Default value if not set
|
|
* @return bool
|
|
*/
|
|
public static function get($feature, $default = null)
|
|
{
|
|
$defaults = self::$defaults;
|
|
$default = $default ?? ($defaults[$feature] ?? false);
|
|
|
|
$settings = get_option('woonoow_feature_settings', []);
|
|
return isset($settings[$feature]) ? (bool) $settings[$feature] : $default;
|
|
}
|
|
|
|
/**
|
|
* Set a feature flag value
|
|
*
|
|
* @param string $feature Feature name
|
|
* @param bool $value Value to set
|
|
*/
|
|
public static function set($feature, $value)
|
|
{
|
|
$settings = get_option('woonoow_feature_settings', []);
|
|
$settings[$feature] = (bool) $value;
|
|
update_option('woonoow_feature_settings', $settings);
|
|
}
|
|
|
|
/**
|
|
* Check if dynamic preview is enabled
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function is_dynamic_preview_enabled()
|
|
{
|
|
return self::get('dynamic_preview');
|
|
}
|
|
|
|
/**
|
|
* Check if schema v1 migration is enabled
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function is_schema_v1_enabled()
|
|
{
|
|
return self::get('schema_v1');
|
|
}
|
|
|
|
/**
|
|
* Check if enhanced SSR is enabled
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function is_enhanced_ssr_enabled()
|
|
{
|
|
return self::get('enhanced_ssr');
|
|
}
|
|
|
|
/**
|
|
* Check if placeholder caching is enabled
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function is_placeholder_cache_enabled()
|
|
{
|
|
return self::get('placeholder_cache');
|
|
}
|
|
|
|
/**
|
|
* Get all feature flag values
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function get_all()
|
|
{
|
|
$settings = get_option('woonoow_feature_settings', []);
|
|
$result = [];
|
|
|
|
foreach (self::$defaults as $feature => $default) {
|
|
$result[$feature] = isset($settings[$feature])
|
|
? (bool) $settings[$feature]
|
|
: $default;
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Reset all feature flags to defaults
|
|
*/
|
|
public static function reset_all()
|
|
{
|
|
delete_option('woonoow_feature_settings');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hook helper to conditionally enable features based on user role
|
|
*/
|
|
class FeatureAccess
|
|
{
|
|
/**
|
|
* Check if current user can access a feature
|
|
*
|
|
* @param string $feature Feature name
|
|
* @return bool
|
|
*/
|
|
public static function can_access($feature)
|
|
{
|
|
// Check if feature is globally enabled
|
|
if (!Features::get($feature)) {
|
|
// Check for admin override
|
|
$override_key = "woonoow_{$feature}_override";
|
|
if (get_transient($override_key) === 'enabled') {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Enable a feature for a specific user
|
|
*
|
|
* @param string $feature Feature name
|
|
* @param int $user_id User ID
|
|
*/
|
|
public static function enable_for_user($feature, $user_id = null)
|
|
{
|
|
if (!$user_id) {
|
|
$user_id = get_current_user_id();
|
|
}
|
|
|
|
$transient_key = "woonoow_user_{$user_id}_{$feature}";
|
|
set_transient($transient_key, 'enabled', DAY_IN_SECONDS);
|
|
}
|
|
|
|
/**
|
|
* Disable a feature for a specific user
|
|
*
|
|
* @param string $feature Feature name
|
|
* @param int $user_id User ID
|
|
*/
|
|
public static function disable_for_user($feature, $user_id = null)
|
|
{
|
|
if (!$user_id) {
|
|
$user_id = get_current_user_id();
|
|
}
|
|
|
|
$transient_key = "woonoow_user_{$user_id}_{$feature}";
|
|
delete_transient($transient_key);
|
|
}
|
|
}
|