'migrate_to_v1', ]; /** * Migrate a page/template structure to current schema * * @param array $structure Page or template structure * @return array Migrated structure */ public static function migrate($structure) { $version = $structure['schemaVersion'] ?? 0; // Already at current version if ($version >= self::CURRENT_VERSION) { return $structure; } // Apply migrations in order for ($v = $version + 1; $v <= self::CURRENT_VERSION; $v++) { if (isset(self::$migrations[$v])) { $method = self::$migrations[$v]; $structure = self::$method($structure); } } // Set current version $structure['schemaVersion'] = self::CURRENT_VERSION; return $structure; } /** * Migrate to version 1 * - Normalize feature-grid items/features * - Normalize style keys * - Add missing defaults * * @param array $structure * @return array */ private static function migrate_to_v1($structure) { if (!isset($structure['sections']) || !is_array($structure['sections'])) { return $structure; } foreach ($structure['sections'] as &$section) { // Migrate section type if (!isset($section['type'])) { continue; } // Feature grid: normalize items/features if ($section['type'] === 'feature-grid') { $section = self::migrate_feature_grid($section); } // Normalize section styles $section = self::migrate_section_styles($section); // Normalize element styles $section = self::migrate_element_styles($section); } return $structure; } /** * Migrate feature-grid section * - Ensure items array exists * - Copy features to items if needed * * @param array $section * @return array */ private static function migrate_feature_grid($section) { $props = $section['props'] ?? []; // Handle items/features normalization if (!isset($props['items']) && isset($props['features'])) { // features exists but items doesn't - copy features to items $props['items'] = $props['features']; // If features was an empty string, convert to empty array if ($props['items'] === '') { $props['items'] = []; } // Keep features for backward compat but prefer items // Don't remove it yet - some old code may still reference it } // Ensure items is always an array if (!isset($props['items'])) { $props['items'] = []; } elseif (!is_array($props['items'])) { $props['items'] = []; } $section['props'] = $props; return $section; } /** * Migrate section styles * - Normalize key names * - Add missing defaults * * @param array $section * @return array */ private static function migrate_section_styles($section) { $styles = $section['styles'] ?? []; // Normalize contentWidth if missing if (!isset($styles['contentWidth']) && isset($styles['container_width'])) { // Old key name $styles['contentWidth'] = $styles['container_width']; unset($styles['container_width']); } // Normalize background type if (isset($styles['backgroundImage']) && !isset($styles['backgroundType'])) { // If there's a background image but no type, assume image type $styles['backgroundType'] = 'image'; } // Normalize height preset if (isset($styles['height']) && !isset($styles['heightPreset'])) { $height = $styles['height']; $map = [ 'small' => 'small', 'medium' => 'medium', 'large' => 'large', 'fullscreen' => 'fullscreen', 'screen' => 'fullscreen', // Old naming 'default' => 'default', ]; $styles['heightPreset'] = $map[$height] ?? 'default'; unset($styles['height']); } // Add default background settings if missing if (!isset($styles['backgroundType'])) { $styles['backgroundType'] = 'solid'; } $section['styles'] = $styles; return $section; } /** * Migrate element styles * - Normalize key names * - Add missing defaults * * @param array $section * @return array */ private static function migrate_element_styles($section) { $elementStyles = $section['elementStyles'] ?? []; // Normalize common element style keys $normalizations = [ 'cta' => 'cta_text', // Old key 'button' => 'cta_text', // Alias for button 'heading' => 'heading', // Standardize 'text' => 'text', // Standardize 'subtitle' => 'subtitle', // Standardize ]; $normalized = []; foreach ($elementStyles as $key => $style) { $normalized_key = $normalizations[$key] ?? $key; $normalized[$normalized_key] = $style; } // Add default styling keys if missing $defaults = [ 'title' => [], 'subtitle' => [], 'text' => [], 'cta_text' => [], 'feature_item' => [], ]; foreach ($defaults as $key => $default) { if (!isset($normalized[$key])) { $normalized[$key] = $default; } } $section['elementStyles'] = $normalized; return $section; } /** * Check if a structure needs migration * * @param array $structure * @return bool */ public static function needs_migration($structure) { return ($structure['schemaVersion'] ?? 0) < self::CURRENT_VERSION; } /** * Batch migrate multiple structures * * @param array $structures Array of structures * @return array Migrated structures */ public static function migrate_all($structures) { return array_map([self::class, 'migrate'], $structures); } /** * Get current schema version * * @return int */ public static function get_current_version() { return self::CURRENT_VERSION; } }