Files
WooNooW/includes/Features.php
Dwindi Ramadhana 396ca25be4 feat: Page Editor v1.0 - canonical schema, SSR parity, and migration
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
2026-05-30 13:02:08 +07:00

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);
}
}