Astra_Migrate_Header_Components

Class Astra_Migrate_Header_Components


Description


Source

File: inc/abilities/customizer/header/class-astra-migrate-header-components.php

class Astra_Migrate_Header_Components extends Astra_Abstract_Ability {
	/**
	 * Configure the ability.
	 *
	 * @return void
	 */
	public function configure() {
		$this->id          = 'astra/update-header-component';
		$this->category    = 'astra';
		$this->label       = __( 'Migrate Astra Header Component IDs', 'astra' );
		$this->description = __( 'Scans and fixes incorrect header builder component IDs. Automatically converts variations like menu_secondary to menu-2, social_1 to social-icons-1, etc. Use this when header components are not showing in customizer/frontend due to incorrect IDs.', 'astra' );

		$this->meta = array(
			'tool_type'   => 'write',
			'constraints' => array(
				'usage_hints' => array(
					'when_to_use'    => 'Use this when header components appear in database but not in customizer/frontend. Common issue: menu_secondary instead of menu-2.',
					'what_it_fixes'  => 'Normalizes all component IDs to Astra format: menu-1, menu-2, social-icons-1, button-1, html-1, widget-1, etc.',
					'automatic'      => 'Automatically scans both desktop and mobile layouts and fixes all incorrect IDs in one operation.',
					'safe_operation' => 'Only changes IDs that need normalization. Does not modify layout structure or remove components.',
					'cache_clear'    => 'After migration, customizer cache is automatically cleared to show changes immediately.',
				),
			),
		);
	}

	/**
	 * Get tool type.
	 *
	 * @return string
	 */
	public function get_tool_type() {
		return 'write';
	}

	/**
	 * Get input schema.
	 *
	 * @return array
	 */
	public function get_input_schema() {
		return array(
			'type'       => 'object',
			'properties' => array(
				'dry_run' => array(
					'type'        => 'boolean',
					'description' => 'If true, shows what would be changed without actually updating. Default: false',
					'default'     => false,
				),
			),
		);
	}

	/**
	 * Get examples.
	 *
	 * @return array
	 */
	public function get_examples() {
		return array(
			'fix header component IDs',
			'migrate header components',
			'normalize header widget IDs',
			'fix menu_secondary to menu-2',
			'repair header builder components',
			'convert header component IDs',
			'fix header components not showing',
			'migrate header builder IDs',
		);
	}

	/**
	 * Execute the ability.
	 *
	 * @param array $args Input arguments.
	 * @return array Result array.
	 */
	public function execute( $args ) {
		if ( ! defined( 'ASTRA_THEME_SETTINGS' ) ) {
			return Astra_Abilities_Response::error(
				__( 'Astra theme is not active.', 'astra' ),
				__( 'Please activate the Astra theme to use this feature.', 'astra' )
			);
		}

		$dry_run = isset( $args['dry_run'] ) ? (bool) $args['dry_run'] : false;

		$theme_options = get_option( ASTRA_THEME_SETTINGS, array() );
		if ( ! is_array( $theme_options ) ) {
			$theme_options = array();
		}

		$changes     = array();
		$total_fixes = 0;

		// Migrate desktop header items.
		if ( isset( $theme_options['header-desktop-items'] ) && is_array( $theme_options['header-desktop-items'] ) ) {
			$desktop_result = $this->migrate_layout( $theme_options['header-desktop-items'], 'desktop' );
			if ( ! empty( $desktop_result['changed'] ) ) {
				$changes['desktop'] = isset( $desktop_result['changes'] ) ? $desktop_result['changes'] : array();
				$total_fixes       += isset( $desktop_result['count'] ) ? (int) $desktop_result['count'] : 0;
				if ( ! $dry_run && isset( $desktop_result['layout'] ) ) {
					$theme_options['header-desktop-items'] = $desktop_result['layout'];
				}
			}
		}

		// Migrate mobile header items.
		if ( isset( $theme_options['header-mobile-items'] ) && is_array( $theme_options['header-mobile-items'] ) ) {
			$mobile_result = $this->migrate_layout( $theme_options['header-mobile-items'], 'mobile' );
			if ( ! empty( $mobile_result['changed'] ) ) {
				$changes['mobile'] = isset( $mobile_result['changes'] ) ? $mobile_result['changes'] : array();
				$total_fixes      += isset( $mobile_result['count'] ) ? (int) $mobile_result['count'] : 0;
				if ( ! $dry_run && isset( $mobile_result['layout'] ) ) {
					$theme_options['header-mobile-items'] = $mobile_result['layout'];
				}
			}
		}

		if ( 0 === $total_fixes ) {
			return Astra_Abilities_Response::success(
				__( 'No component IDs need migration. All component IDs are already correct.', 'astra' ),
				array(
					'fixes_needed' => 0,
					'dry_run'      => $dry_run,
				)
			);
		}

		if ( ! $dry_run ) {
			update_option( ASTRA_THEME_SETTINGS, $theme_options );

			// Clear customizer cache.
			if ( function_exists( 'wp_cache_flush' ) ) {
				wp_cache_flush();
			}

			$message = sprintf(
				/* translators: %d: number of fixes */
				_n(
					'Successfully migrated %d component ID. Changes are now visible in customizer and frontend.',
					'Successfully migrated %d component IDs. Changes are now visible in customizer and frontend.',
					$total_fixes,
					'astra'
				),
				$total_fixes
			);
		} else {
			$message = sprintf(
				/* translators: %d: number of fixes */
				_n(
					'Found %d component ID that needs migration. Run without dry_run to apply changes.',
					'Found %d component IDs that need migration. Run without dry_run to apply changes.',
					$total_fixes,
					'astra'
				),
				$total_fixes
			);
		}

		return Astra_Abilities_Response::success(
			$message,
			array(
				'fixes_applied' => ! $dry_run,
				'total_fixes'   => $total_fixes,
				'changes'       => $changes,
				'dry_run'       => $dry_run,
			)
		);
	}

	/**
	 * Migrate a header layout by normalizing component IDs.
	 *
	 * @param array  $layout Layout array.
	 * @param string $type   Layout type (desktop or mobile).
	 * @return array Migration result with changed status, count, changes, and migrated layout.
	 */
	private function migrate_layout( $layout, $type ) {
		$sections = array( 'popup', 'above', 'primary', 'below' );
		$changes  = array();
		$count    = 0;
		$changed  = false;

		foreach ( $sections as $section ) {
			if ( ! isset( $layout[ $section ] ) || ! is_array( $layout[ $section ] ) ) {
				continue;
			}

			foreach ( $layout[ $section ] as $zone => $components ) {
				if ( ! is_array( $components ) ) {
					continue;
				}

				$normalized_components = array();
				foreach ( $components as $component_id ) {
					$normalized_id = $this->normalize_component_id( $component_id );

					if ( $normalized_id !== $component_id ) {
						$changes[] = array(
							'section' => $section,
							'zone'    => $zone,
							'old_id'  => $component_id,
							'new_id'  => $normalized_id,
						);
						++$count;
						$changed = true;
					}

					$normalized_components[] = $normalized_id;
				}

				$layout[ $section ][ $zone ] = $normalized_components;
			}
		}

		return array(
			'changed' => $changed,
			'count'   => $count,
			'changes' => $changes,
			'layout'  => $layout,
		);
	}

	/**
	 * Normalize component ID to match Astra's expected format.
	 *
	 * @param string $component_id Component ID to normalize.
	 * @return string Normalized component ID.
	 */
	private function normalize_component_id( $component_id ) {
		$component_id = sanitize_text_field( $component_id );

		$id_mapping = array(
			// Menu variations.
			'menu_primary'      => 'menu-1',
			'primary_menu'      => 'menu-1',
			'primary-menu'      => 'menu-1',
			'menu_1'            => 'menu-1',
			'menu_secondary'    => 'menu-2',
			'secondary_menu'    => 'menu-2',
			'secondary-menu'    => 'menu-2',
			'menu_2'            => 'menu-2',
			// Social icons variations.
			'social_icons_1'    => 'social-icons-1',
			'social_1'          => 'social-icons-1',
			'social-1'          => 'social-icons-1',
			'social_icons_2'    => 'social-icons-2',
			'social_2'          => 'social-icons-2',
			'social-2'          => 'social-icons-2',
			// Button variations.
			'button_1'          => 'button-1',
			'button_2'          => 'button-2',
			'button_3'          => 'button-3',
			// HTML variations.
			'html_1'            => 'html-1',
			'html_2'            => 'html-2',
			'html_3'            => 'html-3',
			// Widget variations.
			'widget_1'          => 'widget-1',
			'widget_2'          => 'widget-2',
			'widget_3'          => 'widget-3',
			// Mobile variations.
			'mobile_menu'       => 'mobile-menu',
			'mobile_trigger'    => 'mobile-trigger',
			// WooCommerce variations.
			'woo_cart'          => 'woo-cart',
			'woocommerce_cart'  => 'woo-cart',
			// EDD variations.
			'edd_cart'          => 'edd-cart',
			// Other variations.
			'language_switcher' => 'language-switcher',
		);

		if ( isset( $id_mapping[ $component_id ] ) ) {
			return $id_mapping[ $component_id ];
		}

		return $component_id;
	}
}


Methods


User Contributed Notes

You must log in before being able to contribute a note or feedback.