<?php
/**
 * Core plugin class.
 *
 * @link       https://www.cyberchimps.com
 * @since      1.0.0
 *
 * @package    Responsive_Block_Editor_Addons
 * @subpackage Responsive_Block_Editor_Addons/includes
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * The core plugin class Responsive_Block_Editor_Addons.
 *
 * @since      1.0.0
 * @package    Responsive_Block_Editor_Addons
 * @subpackage Responsive_Block_Editor_Addons/includes
 * @author     CyberChimps <support@cyberchimps.com>
 */
class Responsive_Block_Editor_Addons {

	/**
	 * Table of Contents Present on a Page.
	 *
	 * @var bool
	 */
	public static $table_of_contents_flag = false;

	/**
	 * The unique identifier of this plugin.
	 *
	 * @since    1.0.0
	 * @access   protected
	 * @var      string    $plugin_name    The string used to uniquely identify this plugin.
	 */
	protected $plugin_name;

	/**
	 * The current version of the plugin.
	 *
	 * @since    1.0.0
	 * @access   protected
	 * @var      string    $version    The current version of the plugin.
	 */
	protected $version;

	/**
	 * Verify whether any block is using animations extension .
	 *
	 * @since    2.1.2
	 * @access   protected
	 * @var      boolean    $is_animations_on    Whether animations extension is used by any block.
	 */
	protected static $is_animations_on = false;

	/**
	 * Responsive Block Editor Addons Blocks.
	 * 
	 * @since 2.0.7
	 * @access protected
	 * @var array $responsive_block_editor_addons_blocks
	 * @description This array contains the list of blocks that are registered by Responsive Block Editor Addons.
	 */
	protected $responsive_block_editor_addons_blocks = [
		'responsive-block-editor-addons/section',
		'responsive-block-editor-addons/advance-columns',
		'responsive-block-editor-addons/advance-columns/column',
		'responsive-block-editor-addons/advanced-heading',
		'responsive-block-editor-addons/advanced-text',
		'responsive-block-editor-addons/image',
		'responsive-block-editor-addons/buttons',
		'responsive-block-editor-addons/buttons/buttons-child',
		'responsive-block-editor-addons/responsive-block-editor-addons-cta',
		'responsive-block-editor-addons/blockquote',
		'responsive-block-editor-addons/divider',
		'responsive-block-editor-addons/info-block',
		'responsive-block-editor-addons/count-down',
		'responsive-block-editor-addons/spacer',
		'responsive-block-editor-addons/inline-notice',
		'responsive-block-editor-addons/progress-bar',
		'responsive-block-editor-addons/table-of-contents',
		'responsive-block-editor-addons/testimonial',
		'responsive-block-editor-addons/count-up',
		'responsive-block-editor-addons/flipbox',
		'responsive-block-editor-addons/icons-list',
		'responsive-block-editor-addons/icons-list/icons-list-child',
		'responsive-block-editor-addons/googlemap',
		'responsive-block-editor-addons/gallery-masonry',
		'responsive-block-editor-addons/post-grid',
		'responsive-block-editor-addons/post-carousel',
		'responsive-block-editor-addons/post-timeline',
		'responsive-block-editor-addons/image-boxes-block',
		'responsive-block-editor-addons/shape-divider',
		'responsive-block-editor-addons/accordion',
		'responsive-block-editor-addons/accordion/accordion-item',
		'responsive-block-editor-addons/content-timeline',
		'responsive-block-editor-addons/image-slider',
		'responsive-block-editor-addons/team',
		'responsive-block-editor-addons/expand',
		'responsive-block-editor-addons/card',
		'responsive-block-editor-addons/pricing-table',
		'responsive-block-editor-addons/pricing-list',
		'responsive-block-editor-addons/video-popup',
		'responsive-block-editor-addons/testimonial-slider',
		'responsive-block-editor-addons/feature-grid',
		'responsive-block-editor-addons/portfolio',
		'responsive-block-editor-addons/anchor',
		'responsive-block-editor-addons/call-mail-button',
		'responsive-block-editor-addons/social-icons',
		'responsive-block-editor-addons/tabs',
		'responsive-block-editor-addons/tabs/tabs-child',
		'responsive-block-editor-addons/taxonomy-list',
		'responsive-block-editor-addons/wp-search',
		'responsive-block-editor-addons/instagram',
		'responsive-block-editor-addons/image-hotspot',
		'responsive-block-editor-addons/contact-form-7-styler',
		'responsive-block-editor-addons/popup',
		'responsive-block-editor-addons/form',
		'responsive-block-editor-addons/form/input',
		'responsive-block-editor-addons/rbea-templates',
	];

	/**
	 * Define the core functionality of the plugin.
	 *
	 * Set the plugin name and the plugin version that can be used throughout the plugin.
	 * Load the dependencies, define the locale, and set the hooks for the admin area and
	 * the public-facing side of the site.
	 *
	 * @since    1.0.0
	 */
	public function __construct() {
		if ( defined( 'RESPONSIVE_BLOCK_EDITOR_ADDONS_VER' ) ) {
			$this->version = RESPONSIVE_BLOCK_EDITOR_ADDONS_VER;
		} else {
			$this->version = '1.4.0';
		}
		$this->plugin_name = 'responsive-block-editor-addons';

		add_action( 'plugins_loaded', array( $this, 'responsive_block_editor_addons_loader' ) );

		add_action( 'enqueue_block_assets', array( $this, 'responsive_block_editor_addons_block_assets' ) );

		add_filter( 'block_categories_all', array( $this, 'responsive_block_editor_addons_add_custom_block_category' ), 9999999, 2 );

		add_action( 'enqueue_block_editor_assets', array( $this, 'responsive_block_editor_addons_editor_assets' ) );

		add_action( 'admin_enqueue_scripts', array( &$this, 'responsive_block_editor_addons_admin_enqueue_styles' ) );

		add_action( 'admin_enqueue_scripts', array( $this, 'responsive_block_editor_addons_responsive_menu' ) );

		// Responsive Addons Menu.
		add_action( 'admin_menu', array( $this, 'responsive_block_editor_addons_admin_menu' ) );

		add_action( 'admin_menu', array( $this, 'responsive_block_editor_addons_remove_duplicate_submenu' ), 999 );

		// Remove all admin notices from specific pages.
		add_action( 'admin_init', array( $this, 'responsive_block_editor_addons_admin_init' ) );

		// Redirect to Getting Started Page on Plugin Activation.
		add_action( 'admin_init', array( $this, 'responsive_block_editor_addons_maybe_redirect_to_getting_started' ) );

		add_action( 'wp_ajax_responsive_block_editor_post_pagination', array( $this, 'post_pagination' ) );
		add_action( 'wp_enqueue_scripts', array( $this, 'load_dashicons_front_end' ) );
		add_action( 'wp_enqueue_scripts', array( $this, 'responsive_block_editor_addons_load_frontend_scripts' ) );

		// Display admin notice for RBEA review.
		add_action( 'admin_notices', array( $this, 'rbea_admin_review_notice' ) );
		add_action( 'admin_init', array( $this, 'rba_notice_dismissed' ) );
		add_action( 'admin_init', array( $this, 'rba_notice_change_timeout' ) );
		add_action( 'admin_init', array( $this, 'rba_notice_cross_dismiss' ) );

		add_action( 'wp_ajax_responsive_block_editor_cf7_shortcode', array( $this, 'cf7_shortcode' ) );
		add_action( 'wp_ajax_nopriv_responsive_block_editor_cf7_shortcode', array( $this, 'cf7_shortcode' ) );

		// Stores and Displays the blocks.
		add_action( 'init', array( $this, 'responsive_block_editor_addons_blocks_display' ) );

		// RBEA Getting Started Blocks Toggle.
		add_action( 'wp_ajax_rbea_blocks_toggle', array( $this, 'rbea_blocks_toggle' ) );

		// RBEA Auto Block Recovery Toggle.
		add_action( 'wp_ajax_rbea_toggle_auto_block_recovery', array( $this, 'rbea_toggle_auto_block_recovery' ) );

		// RBEA Global Inherit From Theme Toggle.
		add_action( 'wp_ajax_rbea_toggle_global_inherit_from_theme', array( $this, 'rbea_toggle_global_inherit_from_theme' ) );

		// RBEA Custom CSS Toggle.
		add_action( 'wp_ajax_rbea_toggle_custom_css', array( $this, 'rbea_toggle_custom_css' ) );

		// RBEA Template Library Button Toggle.
		add_action( 'wp_ajax_rbea_toggle_template_library_button', array( $this, 'rbea_toggle_template_library_button' ) );

		// RBEA Content Width Setting.
		add_action( 'wp_ajax_rbea_save_content_width', array( $this, 'rbea_save_content_width' ) );

		// RBEA Container Padding Setting.
		add_action( 'wp_ajax_rbea_save_container_padding', array( $this, 'rbea_save_container_padding' ) );

		// RBEA Container Gap Setting.
		add_action( 'wp_ajax_rbea_save_container_gap', array( $this, 'rbea_save_container_gap' ) );

		// RBEA Ai Suite — save all dashboard settings in one payload.
		add_action( 'wp_ajax_rbea_save_ai_suite_settings', array( $this, 'rbea_save_ai_suite_settings' ) );

		// RBEA Ai Suite — proxy generation request to the configured AI provider.
		add_action( 'wp_ajax_rbea_ai_generate', array( $this, 'rbea_ai_generate' ) );
		add_action( 'wp_ajax_rbea_ai_rewrite', array( $this, 'rbea_ai_rewrite' ) );

		add_action( 'rest_api_init', array( $this, 'register_custom_rest_endpoint' ) );
		add_action( 'wp_ajax_rbea_sync_library', array( $this, 'rbea_sync_library' ) );

		// RBA Form Block Processing.
		add_action( 'rest_api_init', array( $this, 'rba_form_block_processing' ) );

		add_action( 'responsive_register_admin_menu', array( $this, 'rba_register_admin_menu' ) );

		// Add media input script for media input
		add_action( 'admin_enqueue_scripts', array( $this, 'my_enqueue_media_scripts' ) );

		// Add rating links to plugin's description in plugins table
		add_filter('plugin_row_meta', array( $this, 'responsive_block_editor_addons_rate_plugin_link' ), 10, 2);

		// Add the post types to the block editor.
		add_filter( 'allowed_block_types_all', array( $this, 'responsive_block_editor_addons_allow_blocks_in_editor' ), 20, 2 );

		add_filter( 'plugin_action_links_responsive-block-editor-addons/responsive-block-editor-addons.php', array( $this, 'responsive_block_editor_addons_settings_link' ) );

		if ( ! is_admin() ) {
			add_action( 'render_block', array( $this, 'responsive_block_editor_addons_render_block' ), 5, 2 );
		}

		add_filter( 'content_save_pre', array( $this, 'responsive_block_editor_addons_fix_css_vars' ), 10 );

	}

	/**
	 * The name of the plugin used to uniquely identify it within the context of
	 * WordPress and to define internationalization functionality.
	 *
	 * @return string    The name of the plugin.
	 */
	public function get_plugin_name() {
		return $this->plugin_name;
	}

	/**
	 * Returns the version of plugin
	 *
	 * @return string    The version of the plugin.
	 */
	public function get_plugin_version() {
		return $this->version;
	}

	/**
	 * Sends the Post pagination markup to edit.js
	 *
	 * @since 1.0.3
	 */
	public function post_pagination() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( isset( $_POST['attributes'] ) ) {

			$query = $this->get_query( $_POST['attributes'], 'grid' ); //phpcs:ignore

			$pagination_markup = $this->render_pagination( $query, $_POST['attributes'] ); //phpcs:ignore

			wp_send_json_success( $pagination_markup );
		}

		wp_send_json_error( ' No attributes recieved' );
	}

	/**
	 * Renders the post post pagination on server.
	 *
	 * @param object $query WP_Query object.
	 * @param array  $attributes Array of block attributes.
	 * @since 1.0.3
	 */
	public function render_pagination( $query, $attributes ) {

		$permalink_structure = get_option( 'permalink_structure' );
		$base                = untrailingslashit( wp_specialchars_decode( get_pagenum_link() ) );
		$base                = $this->build_base_url( $permalink_structure, $base );
		$format              = $this->paged_format( $permalink_structure, $base );
		$paged               = $this->get_paged( $query );
		$page_limit          = min( $attributes['pageLimit'], $query->max_num_pages );
		$page_limit          = isset( $page_limit ) ? $page_limit : $attributes['postsToShow'];
		$attributes['postsToShow'];

		$links = paginate_links(
			array(
				'base'      => $base . '%_%',
				'format'    => $format,
				'current'   => ( ! $paged ) ? 1 : $paged,
				'total'     => $page_limit,
				'type'      => 'array',
				'mid_size'  => 4,
				'end_size'  => 4,
				'prev_text' => $attributes['previousButtonText'],
				'next_text' => $attributes['nextButtonText'],
			)
		);

		if ( isset( $links ) ) {
			return wp_kses_post( implode( PHP_EOL, $links ) );
		}

		return '';
	}

	/**
	 * Gives the paged Query var.
	 *
	 * @param Object $query Query.
	 * @return int $paged Paged Query var.
	 * @since 1.0.3
	 */
	public static function get_paged( $query ) {

		global $paged;

		// Check the 'paged' query var.
		$paged_qv = $query->get( 'paged' );

		if ( is_numeric( $paged_qv ) ) {
			return $paged_qv;
		}

		// Check the 'page' query var.
		$page_qv = $query->get( 'page' );

		if ( is_numeric( $page_qv ) ) {
			return $page_qv;
		}

		// Check the $paged global?
		if ( is_numeric( $paged ) ) {
			return $paged;
		}

		return 0;
	}


	/**
	 * Returns the Paged Format.
	 *
	 * @param string $permalink_structure Premalink Structure.
	 * @param string $base Base.
	 * @since 1.0.3
	 */
	public static function paged_format( $permalink_structure, $base ) {

		$page_prefix = empty( $permalink_structure ) ? 'paged' : 'page';

		if ( ! empty( $permalink_structure ) ) {
			$format  = substr( $base, -1 ) !== '/' ? '/' : '';
			$format .= $page_prefix . '/';
			$format .= '%#%';
			$format .= substr( $permalink_structure, -1 ) === '/' ? '/' : '';
		} elseif ( empty( $permalink_structure ) || is_search() ) {
			$parse_url = wp_parse_url( $base, PHP_URL_QUERY );
			$format    = empty( $parse_url ) ? '?' : '&';
			$format   .= $page_prefix . '=%#%';
		}

		return $format;
	}

	/**
	 * Builds the base url.
	 *
	 * @param string $permalink_structure Premalink Structure.
	 * @param string $base Base.
	 * @since 1.0.3
	 */
	public static function build_base_url( $permalink_structure, $base ) {
		// Check to see if we are using pretty permalinks.
		if ( ! empty( $permalink_structure ) ) {

			if ( strrpos( $base, 'paged-' ) ) {
				$base = substr_replace( $base, '', strrpos( $base, 'paged-' ), strlen( $base ) );
			}

			// Remove query string from base URL since paginate_links() adds it automatically.
			// This should also fix the WPML pagination issue that was added since 1.0.3.
			if ( count( $_GET ) > 0 ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
				$base = strtok( $base, '?' );
			}

			// Add trailing slash when necessary.
			if ( '/' === substr( $permalink_structure, -1 ) ) {
				$base = trailingslashit( $base );
			} else {
				$base = untrailingslashit( $base );
			}
		} else {
			$url_params = wp_parse_url( $base, PHP_URL_QUERY );

			if ( empty( $url_params ) ) {
				$base = trailingslashit( $base );
			}
		}

		return $base;
	}

	/**
	 * Returns Query.
	 *
	 * @param array  $attributes The block attributes.
	 * @param string $block_type The Block Type.
	 * @since 1.0.3
	 */
	public static function get_query( $attributes, $block_type ) {

		// Block type is grid/masonry/carousel/timeline.
		$query_args = array(
			'posts_per_page'      => ( isset( $attributes['postsToShow'] ) ) ? $attributes['postsToShow'] : 6,
			'post_status'         => 'publish',
			'post_type'           => ( isset( $attributes['postType'] ) ) ? $attributes['postType'] : 'post',
			'order'               => ( isset( $attributes['order'] ) ) ? $attributes['order'] : 'desc',
			'orderby'             => ( isset( $attributes['orderBy'] ) ) ? $attributes['orderBy'] : 'date',
			'ignore_sticky_posts' => 1,
			'paged'               => 1,
		);

		if ( $attributes['excludeCurrentPost'] ) {
			$query_args['post__not_in'] = array( get_the_ID() );
		}

		if ( isset( $attributes['categories'] ) && '' !== $attributes['categories'] ) {
			$query_args['tax_query'][] = array(
				'taxonomy' => ( isset( $attributes['taxonomyType'] ) ) ? $attributes['taxonomyType'] : 'category',
				'field'    => 'id',
				'terms'    => $attributes['categories'],
				'operator' => 'IN',
			);
		}

		if ( 'grid' === $block_type && isset( $attributes['postPagination'] ) && true === $attributes['postPagination'] ) {

			if ( get_query_var( 'paged' ) ) {

				$paged = get_query_var( 'paged' );

			} elseif ( get_query_var( 'page' ) ) {

				$paged = get_query_var( 'page' );

			} else {

				$paged = 1;

			}
			$query_args['posts_per_page'] = $attributes['postsToShow'];
			$query_args['paged']          = $paged;

		}

		if ( 'masonry' === $block_type && isset( $attributes['paginationType'] ) && 'none' !== $attributes['paginationType'] && isset( $attributes['paged'] ) ) {

			$query_args['paged'] = $attributes['paged'];

		}

		$query_args = apply_filters( "responsive_block_editor_post_query_args_{$block_type}", $query_args, $attributes );

		return new WP_Query( $query_args );
	}

	/**
	 * Remove the unnecessary duplicate submenu.
	 */
	public function responsive_block_editor_addons_remove_duplicate_submenu() {
		$theme = wp_get_theme();

		$rst_path = 'responsive-add-ons/responsive-add-ons.php';
		$rae_path = 'responsive-addons-for-elementor/responsive-addons-for-elementor.php';

		if ( ('Responsive' !== $theme->name && 'Responsive' !== $theme->parent_theme ) && ! is_plugin_active( $rst_path ) ) {
			// Remove the duplicate submenu under "Responsive"
			remove_submenu_page( 
				'responsive_block_editor_addons', // parent slug
				'responsive_block_editor_addons'  // same as parent slug (the auto-added submenu)
			);
		}

		if ( ('Responsive' !== $theme->name && 'Responsive' !== $theme->parent_theme ) && is_plugin_active( $rst_path ) && is_plugin_active( $rae_path ) ) {
			// Remove the duplicate submenu under "Responsive"
			remove_submenu_page( 
				'responsive_block_editor_addons', // parent slug
				'responsive_block_editor_addons'  // same as parent slug (the auto-added submenu)
			);
		}
	}

	/**
	 * Register the menu for the plugin.
	 *
	 * @return void [description]
	 */
	public function responsive_block_editor_addons_admin_menu() {

		$theme = wp_get_theme();

		if ( 'Responsive' !== $theme->name && 'Responsive' !== $theme->parent_theme ) {
			add_menu_page( __( 'Responsive', 'responsive-block-editor-addons' ), __( 'Responsive', 'responsive-block-editor-addons' ), 'manage_options', 'responsive_block_editor_addons', array( $this, 'responsive_block_editor_addons_getting_started' ), esc_url( RESPONSIVE_BLOCK_EDITOR_ADDONS_URL ) . 'admin/images/responsive-add-ons-menu-icon.png', 59 );
			$parent_slug = 'responsive_block_editor_addons';
			do_action( 'responsive_register_admin_menu', $parent_slug );
		}

		if ( ( 'Responsive' === $theme->name || 'Responsive' === $theme->parent_theme ) && version_compare( RESPONSIVE_THEME_VERSION, '4.9.7.1', '<=' ) ) {
			add_menu_page(
				__( 'Responsive Blocks', 'responsive-block-editor-addons' ),
				__( 'Resp Blocks', 'responsive-block-editor-addons' ),
				'manage_options',
				'responsive_block_editor_addons',
				array( $this, 'responsive_block_editor_addons_getting_started' ),
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'admin/images/responsive-block-editor-addons-menu-icon.svg',
				59
			);
		}
	}

	/**
	 * Display Getting Started Page.
	 *
	 * Output the content for the getting started page.
	 *
	 * @access public
	 */
	public function responsive_block_editor_addons_getting_started() {
		echo '<div id="rbea-getting-started-page-app"></div>';
	}

	/**
	 * Responsive_block_editor_addons_maybe_redirect_to_getting_started description
	 *
	 * @return [type] [description]
	 */
	public function responsive_block_editor_addons_maybe_redirect_to_getting_started() {
		if ( ! get_transient( 'responsive_block_editor_addons_activation_redirect' ) ) {
			return;
		}

		if ( wp_doing_ajax() ) {
			return;
		}

		delete_transient( 'responsive_block_editor_addons_activation_redirect' );

		if ( is_network_admin() || isset( $_GET['activate-multi'] ) ) { // phpcs:ignore
			return;
		}

		wp_safe_redirect( admin_url( 'admin.php?page=responsive_block_editor_addons' ) );

		exit;
	}


	/**
	 * Initialize the blocks
	 *
	 * @since    1.0.0
	 */
	public function responsive_block_editor_addons_loader() {
		/**
		* Load Post Grid PHP
		*/
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/post-grid/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/post-carousel/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/gallery-masonry/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/accordion/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/post-timeline/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/image-slider/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/testimonial-slider/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/utils/fonts.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'classes/class-responsive-block-editor-addons-frontend-styles-helper.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'classes/class-responsive-block-editor-addons-frontend-styles.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/inline-notice/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/taxonomy-list/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/table-of-contents/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/instagram/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/image-hotspot/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/portfolio/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/form/index.php';
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'src/blocks/content-timeline/index.php';

		/**
		 * REST API Endpoints for Layouts.
		 */
		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . '/includes/layout/layout-endpoints.php';
	}

	/** Adds the Responsive Blocks block category.
	 *
	 * @param array $categories Existing block categories.
	 *
	 * @return array Updated block categories.
	 */
	public function responsive_block_editor_addons_add_custom_block_category( $categories ) {
		$category = array(
			'slug'  => 'responsive_block_editor_addons',
			'title' => __( 'Responsive Gutenberg Blocks', 'responsive-block-editor-addons' ),
		);

		if ( is_array( $categories ) ) {
			$existing_slugs = array_column( $categories, 'slug' );

			if ( is_array( $existing_slugs ) ) {
				if ( in_array( $category['slug'], $existing_slugs ) ) {
					return $categories; // Bail early if category exists
				}
			}
		}

		array_unshift( $categories, $category ); // Add category on top of pile

		return $categories;
	}


	/**
	 * Get Post Types.
	 *
	 * @since 1.0.3
	 * @access public
	 */
	public static function get_post_types() {

		$post_types = get_post_types(
			array(
				'public'       => true,
				'show_in_rest' => true,
			),
			'objects'
		);

		$options = array();

		foreach ( $post_types as $post_type ) {
			if ( 'product' === $post_type->name ) {
				continue;
			}

			if ( 'attachment' === $post_type->name ) {
				continue;
			}

			if ( 'e-floating-buttons' === $post_type->name ) {
				continue;
			}

			if ( 'elementor_library' === $post_type->name ) {
				continue;
			}

			$options[] = array(
				'value' => $post_type->name,
				'label' => $post_type->label,
			);
		}

		return $options;
	}
	
	/**
	 * Enqueue assets for backend editor
	 *
	 * @since 1.0.0
	 */
	public function responsive_block_editor_addons_editor_assets() {
		$responsive_block_editor_ajax_nonce = wp_create_nonce( 'responsive_block_editor_ajax_nonce' );

		// Load the compiled blocks into the editor.
		wp_enqueue_script(
			'responsive_block_editor_addons-block-js',
			RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/responsive-block-editor-addons.js',
			array( 'lodash', 'react', 'react-dom', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-dom-ready', 'wp-edit-post', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keycodes', 'wp-plugins', 'wp-polyfill', 'wp-rich-text', 'wp-token-list', 'wp-url', 'jquery' ),
			filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/responsive-block-editor-addons.js' ),
			true
		);

		$user_data = wp_get_current_user();
		unset( $user_data->user_pass, $user_data->user_email );

		$blocks = get_option( 'rbea_blocks' );

		$is_taxonomy_list_on         = 1;
		$is_contact_7_form_styler_on = 1;
		$is_animation_toggled_on     = 1;
		$is_display_conditions_on    = 1;
		$is_responsive_conditions_on    = 1;

		$block_status_map = array_column( (array) $blocks, 'status', 'key' );

		if ( isset( $block_status_map['taxonomy-list'] ) ) {
			$is_taxonomy_list_on = $block_status_map['taxonomy-list'];
		}

		if ( isset( $block_status_map['contact-form-7-styler'] ) ) {
			$is_contact_7_form_styler_on = $block_status_map['contact-form-7-styler'];
		}

		if ( isset( $block_status_map['animations'] ) ) {
			$is_animation_toggled_on = $block_status_map['animations'];
		}

		if ( isset( $block_status_map['display-conditions'] ) ) {
			$is_display_conditions_on = $block_status_map['display-conditions'];
		}

		if ( isset( $block_status_map['responsive-conditions'] ) ) {
			$is_responsive_conditions_on = $block_status_map['responsive-conditions'];
		}

		$include_all_taxonomy = 0;

		$all_taxonomy_required_blocks = array(
			'portfolio',
			'responsive-block-editor-addons-post-grid',
			'post-timeline'
		);

		foreach ( $all_taxonomy_required_blocks as $block_key ) {
			if ( isset( $block_status_map[ $block_key ] ) && 1 === (int) $block_status_map[ $block_key ] ) {
				$include_all_taxonomy = 1;
				break;
			}
		}

		// Pass in REST URL.
		wp_localize_script(
			'responsive_block_editor_addons-block-js',
			'responsive_globals',
			array(
				'rest_url'                           => esc_url( rest_url() ),
				'ajax_url'                           => admin_url( 'admin-ajax.php' ),
				'user_data'                          => $user_data,
				'pro_activated'                      => false,
				'is_wpe'                             => function_exists( 'is_wpe' ),
				'post_types'                         => $is_taxonomy_list_on ? $this->get_post_types() : array(),
				'all_taxonomy'                       => $include_all_taxonomy ? $this->get_related_taxonomy() : array(),
				'responsive_block_editor_ajax_nonce' => $responsive_block_editor_ajax_nonce,
				'taxonomy_list'                      => $is_taxonomy_list_on ? $this->get_taxonomy_list() : array(),
				'home_url'                           => home_url(),
				'cf7_forms'                          => $is_contact_7_form_styler_on ? $this->get_cf7_forms() : array(),
				'plugin_url'                         => plugin_dir_url( __DIR__ ),
				'auto_block_recovery'                => get_option( 'rbea_auto_block_recovery', '1' ),
				'global_inherit_from_theme'          => get_option( 'rbea_global_inherit_from_theme', '0' ),
				'global_inherit_from_theme_last_changed' => get_option( 'rbea_global_inherit_from_theme_last_changed', '' ),
				'is_custom_css_on'                   => (int) get_option( 'rbea_custom_css_on', '1' ),
				'template_library_button_on'         => get_option( 'rbea_template_library_button_on', '1' ),
				'default_content_width'              => get_option( 'rbea_default_content_width', 1340 ),
				'default_container_padding'          => get_option( 'rbea_default_container_padding', 10 ),
				'default_container_gap'              => get_option( 'rbea_default_container_gap', 20 ),
				'blocks'                             => $blocks,
				'is_animation_on'                    => $is_animation_toggled_on,
				'is_display_conditions_on'           => $is_display_conditions_on,
				'is_responsive_conditions_on'           => $is_responsive_conditions_on,
				'user_roles'                         => $is_display_conditions_on ? $this->responsive_block_editor_addons_get_user_roles() : array(),
				'ai_suite'                           => $this->rbea_get_ai_suite_indicators(),
			)
		);

		// Load the compiled styles into the editor.
		wp_enqueue_style(
			'responsive_block_editor_addons-block-editor-css',
			RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/responsive-block-editor-addons-editor.css',
			array( 'wp-edit-blocks' ),
			filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/responsive-block-editor-addons-editor.css' )
		);

		wp_enqueue_script( 'responsive_block_editor_addons_deactivate_blocks', RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'admin/js/responsive-block-editor-addons-blocks-deactivate.js', array( 'wp-blocks' ), RESPONSIVE_BLOCK_EDITOR_ADDONS_VER, true );

		$deactivated_blocks = array();

		foreach ( $blocks as $block ) {
			if ( '' === $block['status'] ) {
				array_push( $deactivated_blocks, $block );
			}
		}

		wp_localize_script(
			'responsive_block_editor_addons_deactivate_blocks',
			'rbea_deactivate_blocks',
			array(
				'deactivated_blocks' => $deactivated_blocks,
			)
		);

		$block_status_map = array_column( (array) $blocks, 'status', 'key' );

		if ( isset( $block_status_map['animations'] ) ) {
			$is_animation_toggled_on = $block_status_map['animations'];
		}

		if ( $is_animation_toggled_on ) {
			wp_enqueue_style(
				'responsive-block-editor-addons-aos',
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/css/aos/aos.min.css',
				array(),
				filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/css/aos/aos.min.css' ),
			);
			wp_enqueue_script(
				'responsive-block-editor-addons-aos',
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/js/vendors/aos/aos.min.js',
				array(),
				filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/js/vendors/aos/aos.min.js' ),
				true
			);
		}
	}

	/**
	 * Get all taxonomies list.
	 *
	 * @since 1.0.0
	 * @access public
	 */
	public static function get_taxonomy_list() {
		$post_types   = self::get_post_types();
		$return_array = array();
		foreach ( $post_types as $key => $value ) {
			$post_type         = $value['value'];
			$taxonomies        = get_object_taxonomies( $post_type, 'objects' );
			$data              = array();
			$get_singular_name = get_post_type_object( $post_type );
			foreach ( $taxonomies as $tax_slug => $tax ) {
				if ( ! $tax->public || ! $tax->show_ui || ! $tax->show_in_rest ) {
					continue;
				}
				$data[ $tax_slug ] = $tax;
				$terms             = get_terms( $tax_slug );
				$related_tax_terms = array();
				if ( ! empty( $terms ) ) {
					foreach ( $terms as $t_index => $t_obj ) {
						$related_tax_terms[] = array(
							'id'            => $t_obj->term_id,
							'name'          => $t_obj->name,
							'count'         => $t_obj->count,
							'link'          => get_term_link( $t_obj->term_id ),
							'singular_name' => $get_singular_name->labels->singular_name,
						);
					}
					$return_array[ $post_type ]['terms'][ $tax_slug ] = $related_tax_terms;
				}
				$new_categories_list = get_terms(
					array(
						'taxonomy'   => $tax_slug,
						'hide_empty' => true,
						'parent'     => 0,
					)
				);
				$related_tax         = array();
				if ( ! empty( $new_categories_list ) ) {
					foreach ( $new_categories_list as $t_index => $t_obj ) {
						$child_arg     = array(
							'taxonomy'   => $tax_slug,
							'hide_empty' => true,
							'parent'     => $t_obj->term_id,
						);
						$child_cat     = get_terms( $child_arg );
						$child_cat_arr = $child_cat ? $child_cat : null;
						$related_tax[] = array(
							'id'            => $t_obj->term_id,
							'name'          => $t_obj->name,
							'count'         => $t_obj->count,
							'link'          => get_term_link( $t_obj->term_id ),
							'singular_name' => $get_singular_name->labels->singular_name,
							'children'      => $child_cat_arr,
						);
					}
					$return_array[ $post_type ]['without_empty_taxonomy'][ $tax_slug ] = $related_tax;
				}
				$new_categories_list_empty_tax = get_terms(
					array(
						'taxonomy'   => $tax_slug,
						'hide_empty' => false,
						'parent'     => 0,
					)
				);
				$related_tax_empty_tax         = array();
				if ( ! empty( $new_categories_list_empty_tax ) ) {
					foreach ( $new_categories_list_empty_tax as $t_index => $t_obj ) {
						$child_arg_empty_tax     = array(
							'taxonomy'   => $tax_slug,
							'hide_empty' => false,
							'parent'     => $t_obj->term_id,
						);
						$child_cat_empty_tax     = get_terms( $child_arg_empty_tax );
						$child_cat_empty_tax_arr = $child_cat_empty_tax ? $child_cat_empty_tax : null;
						$related_tax_empty_tax[] = array(
							'id'            => $t_obj->term_id,
							'name'          => $t_obj->name,
							'count'         => $t_obj->count,
							'link'          => get_term_link( $t_obj->term_id ),
							'singular_name' => $get_singular_name->labels->singular_name,
							'children'      => $child_cat_empty_tax_arr,
						);
					}
					$return_array[ $post_type ]['with_empty_taxonomy'][ $tax_slug ] = $related_tax_empty_tax;
				}
			}
			$return_array[ $post_type ]['taxonomy'] = $data;
		}
		return $return_array;
	}

	/**
	 * Get all taxonomies.
	 *
	 * @since 1.0.3
	 * @access public
	 */
	public static function get_related_taxonomy() {

		$post_types = self::get_post_types();

		$return_array = array();

		foreach ( $post_types as $key => $value ) {
			$post_type = $value['value'];

			$taxonomies = get_object_taxonomies( $post_type, 'objects' );
			$data       = array();

			foreach ( $taxonomies as $tax_slug => $tax ) {
				if ( ! $tax->public || ! $tax->show_ui || ! $tax->show_in_rest ) {
					continue;
				}

				$data[ $tax_slug ] = $tax;

				$terms = get_terms( $tax_slug );

				$related_tax = array();

				if ( ! empty( $terms ) ) {
					foreach ( $terms as $t_index => $t_obj ) {
						$related_tax[] = array(
							'id'   => $t_obj->term_id,
							'name' => $t_obj->name,
						);
					}

					$return_array[ $post_type ]['terms'][ $tax_slug ] = $related_tax;
				}
			}

			$return_array[ $post_type ]['taxonomy'] = $data;
		}

		return $return_array;
	}

	/**
	 * Enqueue assets for frontend and backend
	 *
	 * @since 1.0.0
	 */
	public function responsive_block_editor_addons_block_assets() {

		if ( ! is_admin() ) {

			$post          = get_post();
			$widget_blocks = get_option( 'widget_block' );

			$flag = false;

			if ( ( $post && ! empty( $post ) ) || ! empty( $widget_blocks ) ) {
				$blocks = array();

				/**
				* Handle potential 'post_content' null warning.
				* This warning typically occurs when users have added widget blocks from the Responsive theme
				* but there is no post content to render. This ensures compatibility by preventing
				* errors in scenarios where widget blocks exist without posts.
				*/
				if ( ! empty( $post ) ) {
					$blocks = parse_blocks( $post->post_content );
				}

				if ( ! self::$is_animations_on && ! empty( $blocks ) ) {
					self::$is_animations_on = $this->has_rbea_animation( $blocks );
				}

				foreach ( $widget_blocks as $widget ) {
					if ( ! empty( $widget['content'] ) ) {
						$flag = true;
						break;
					}
				}

				if ( ! empty( $blocks ) ) {
					foreach ( $blocks as $block ) {
						// Retrieve all block names for the current block and its inner blocks.
						$get_block_names = $this->rba_get_block_names( $block );

						// If true is returned, break out of the loop early.
						if ( true === $get_block_names ) {
							$flag = true;
							break;
						}
						// Check the block names if array is returned.
						if ( ! empty( $get_block_names ) ) {
							foreach ( $get_block_names as $block_name ) {
								if ( strpos( $block_name, 'responsive-block-editor-addons' ) !== false ) {
									$flag = true;
									break 2;  // Exit both loops when match is found.
								}
							}
						}
					}
				}
			}

			if ( $flag ) {

				// Load the compiled blocks into the editor.
				wp_enqueue_script(
					'responsive_blocks-frontend-js',
					RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/frontend_blocks.js',
					array( 'jquery' ),
					filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/frontend_blocks.js' ),
					true
				);

				// Load the compiled styles.
				wp_enqueue_style(
					'responsive_block_editor_addons-style-css',
					RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/responsive-block-editor-addons-style.css',
					array(),
					filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/responsive-block-editor-addons-style.css' )
				);
			} else {
				return;
			}
		}

		wp_register_script(
			'popper',
			RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/js/vendors/tippy.js/popper.min.js',
			array( 'jquery' ),
			RESPONSIVE_BLOCK_EDITOR_ADDONS_VER,
			true
		);

		wp_register_script(
			'tippy',
			RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/js/vendors/tippy.js/tippy-bundle.umd.min.js',
			array( 'jquery', 'popper' ),
			RESPONSIVE_BLOCK_EDITOR_ADDONS_VER,
			true
		);

		if ( is_admin() ) {
			if ( ! wp_script_is( 'popper', 'enqueued' ) ) {
				wp_enqueue_script( 'popper' );
			}
			if ( ! wp_script_is( 'tippy', 'enqueued' ) ) {
				wp_enqueue_script( 'tippy' );
			}
			wp_enqueue_script(//phpcs:ignore
				'responsive_block_editor_addons-image-hotspot-script-unescape',
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/js/vendors/lodash.unescape/unescape.min.js',
				array(),
				RESPONSIVE_BLOCK_EDITOR_ADDONS_VER,
				true
			);
			wp_enqueue_script(//phpcs:ignore
				'responsive_block_editor_addons-image-hotspot-script',
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/js/vendors/draggabilly.pkgd.min.js',
				array( 'jquery' ),
				RESPONSIVE_BLOCK_EDITOR_ADDONS_VER,
				true
			);
			wp_enqueue_script(//phpcs:ignore
				'responsive_block_editor_addons-image-hotspot-script-waypoints',
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/js/vendors/waypoints/lib/jquery.waypoints.min.js',
				array( 'jquery' ),
				RESPONSIVE_BLOCK_EDITOR_ADDONS_VER,
				true
			);
			wp_enqueue_style(
				'responsive_block_editor_addons-image-hotspot-tippy',
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/js/vendors/tippy.js/themes.css',
				array(),
				filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/js/vendors/tippy.js/themes.css' )
			);
			wp_enqueue_style(
				'responsive_block_editor_addons-style-css-tippy-animation',
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/js/vendors/tippy.js/animations.css',
				array(),
				filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/js/vendors/tippy.js/animations.css' )
			);
		}
		// Load the compiled styles.
		wp_enqueue_style(
			'responsive_block_editor_addons-style-css',
			RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/responsive-block-editor-addons-style.css',
			array(),
			filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/responsive-block-editor-addons-style.css' )
		);

		// Load the compiled blocks into the editor.
		wp_enqueue_script(
			'responsive_blocks-frontend-js',
			RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/frontend_blocks.js',
			array( 'jquery' ),
			filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/frontend_blocks.js' ),
			true
		);
		wp_enqueue_style(
			'animation.css',
			RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/css/animation.css',
			array(),
			filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/css/animation.css' )
		);
		wp_enqueue_style( 'dashicons' );

		$rbea_blocks = get_option( 'rbea_blocks' );

		$block_status_map = array_column( (array) $rbea_blocks, 'status', 'key' );

		if ( isset( $block_status_map['animations'] ) ) {
			$is_animations_toggled_on = $block_status_map['animations'];
		}

		if ( $is_animations_toggled_on && self::$is_animations_on ) {
			wp_enqueue_style(
				'responsive-block-editor-addons-aos',
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/css/aos/aos.min.css',
				array(),
				filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/css/aos/aos.min.css' ),
			);
			wp_enqueue_script(
				'responsive-block-editor-addons-aos',
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/js/vendors/aos/aos.min.js',
				array(),
				filemtime( RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'dist/js/vendors/aos/aos.min.js' ),
				true
			);
		}
	}

	/**
	 * Recursively checks if any block or its inner blocks
	 * contains the RBEA animation attribute.
	 *
	 * @param array $blocks Array of parsed Gutenberg blocks.
	 *
	 * @return bool True if at least one block has 'RBEAAnimationType' set, otherwise false.
	 */
	private function has_rbea_animation( $blocks ) {
		foreach ( $blocks as $block ) {
			if ( ! empty( $block['attrs']['RBEAAnimationType'] ) ) {
				return true;
			}
			if ( ! empty( $block['innerBlocks'] ) && $this->has_rbea_animation( $block['innerBlocks'] ) ) {
				return true;
			}
		}
		return false;
	}

	public function rba_get_block_names( $blocks, &$block_names = array() ) {

		// Check if the 'blockName' key exists and store its value
		if ( isset( $blocks['blockName'] ) ) {
			$block_names[] = $blocks['blockName'];

			// If the blockName contains 'responsive-block-editor-addons', return true immediately.
			if ( strpos( $blocks['blockName'], 'responsive-block-editor-addons' ) !== false ) {
				return true;
			}
		}

		// If 'innerBlocks' exists, iterate over each block and call the function recursively.
		if ( isset( $blocks['innerBlocks'] ) && is_array( $blocks['innerBlocks'] ) ) {
			foreach ( $blocks['innerBlocks'] as $inner_block ) {
				// If any recursive call returns true, exit early.
				if ( $this->rba_get_block_names( $inner_block, $block_names ) === true ) {
					return true;
				}
			}
		}

		return $block_names;
	}

	/**
	 * Check if RST plugin is installed or activated.
	 *
	 * @return string
	 */
	public function rst_status() {
		// Check if RST is activate.

		$rst_path = 'responsive-add-ons/responsive-add-ons.php';

		if ( is_plugin_active( $rst_path ) ) {
			return 'activated';
		}

		// Check if RST is installed.
		$installed_plugins = get_plugins();

		if ( isset( $installed_plugins[ $rst_path ] ) ) {
			return 'activate';
		} else {
			return 'install';
		}
	}

	/**
	 * Check if plugin is installed or activated.
	 *
	 * @return string
	 */
	public function rbea_plugin_status( $path ) {

		if ( is_plugin_active( $path ) ) {
			return 'activated';
		}

		// Check if RST is installed.
		$installed_plugins = get_plugins();

		if ( isset( $installed_plugins[ $path ] ) ) {
			return 'activate';
		} else {
			return 'install';
		}
	}

	/**
	 * Get responsive theme status.
	 * 
	 * @return string 'activated' if active, 'activate' if installed, 'install' if not found.
	 */
	function get_responsive_theme_status() {
		
		$theme_slug = 'responsive';
		$current_theme = wp_get_theme();
		
		// Check if responsive theme or its child theme is active.
		if ($current_theme->get_stylesheet() === $theme_slug || $current_theme->get('Template') === $theme_slug) {
			return 'activated';
		}
		
		// Check if responsive theme is installed
		$themes = wp_get_themes();
		if (isset($themes[$theme_slug])) {
			return 'activate';
		}
		
		// Check if any child theme of responsive is installed
		foreach ($themes as $theme) {
			if ($theme->get('Template') === $theme_slug) {
				return 'activate';
			}
		}
		
		return 'install';
	}

	/**
	 * Include Admin css
	 *
	 * @return void [description]
	 */
	public function my_enqueue_media_scripts() {
		wp_enqueue_media();
	}

	/**
	 * Include Admin css
	 *
	 * @return void [description]
	 */
	public function responsive_block_editor_addons_admin_enqueue_styles() {
		// Responsive Ready Sites admin styles.
		wp_register_style( 'responsive-block-editor-addons-admin', RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'admin/css/responsive-block-editor-addons-admin.css', false, RESPONSIVE_BLOCK_EDITOR_ADDONS_VER );

		wp_enqueue_style( 'responsive-block-editor-addons-admin' );

		if ( isset( $_GET['page'] ) && 'responsive_block_editor_addons' === $_GET['page'] ) {

			wp_register_style( 'responsive-block-editor-addons-getting-started', RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'admin/css/responsive-block-editor-addons-getting-started.css', false, RESPONSIVE_BLOCK_EDITOR_ADDONS_VER );

			wp_enqueue_style( 'responsive-block-editor-addons-getting-started' );

			wp_enqueue_script( 'rbea-toastify', 'https://cdn.jsdelivr.net/npm/toastify-js', array( 'jquery' ), RESPONSIVE_BLOCK_EDITOR_ADDONS_VER, true );

			wp_enqueue_script(
				'responsive-block-editor-addons-admin-jsfile',
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/responsive-block-editor-addons-getting-started.js',
				array( 'jquery', 'react', 'react-dom', 'wp-components' ),
				RESPONSIVE_BLOCK_EDITOR_ADDONS_VER,
				true
			);

			wp_enqueue_style( 'wp-components' );

			wp_enqueue_script( 'updates' );

			require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'includes/class-responsive-block-editor-addons-blocks-updater.php';

			$rbea_blocks = Responsive_Block_Editor_Addons_Blocks_Updater::get_instance();

			$blocks = $rbea_blocks->get_rbea_blocks();

			if ( $rbea_blocks->is_blocks_in_db() ) {
				$blocks = get_option( 'rbea_blocks' );
			}

			$rst_path = 'responsive-add-ons/responsive-add-ons.php';

			$rst_nonce = add_query_arg(
				array(
					'action'        => 'activate',
					'plugin'        => rawurlencode( $rst_path ),
					'plugin_status' => 'all',
					'paged'         => '1',
					'_wpnonce'      => wp_create_nonce( 'activate-plugin_' . $rst_path ),
				),
				network_admin_url( 'plugins.php' )
			);

			$rae_path = 'responsive-addons-for-elementor/responsive-addons-for-elementor.php';

			$rae_nonce = add_query_arg(
				array(
					'action'        => 'activate',
					'plugin'        => rawurlencode( $rae_path ),
					'plugin_status' => 'all',
					'paged'         => '1',
					'_wpnonce'      => wp_create_nonce( 'activate-plugin_' . $rae_path ),
				),
				network_admin_url( 'plugins.php' )
			);

			$theme_slug = 'responsive';

			$responsive_nonce = add_query_arg(
				array(
					'action'   => 'activate',
					'stylesheet' => rawurlencode( $theme_slug ),
					'_wpnonce' => wp_create_nonce( 'switch-theme_' . $theme_slug ),
				),
				admin_url( 'themes.php' )
			);

			wp_localize_script(
				'responsive-block-editor-addons-admin-jsfile',
				'rbealocalize',
				array(
					'pageurl'               => admin_url( 'post-new.php?post_type=page' ),
					'ajaxurl'               => admin_url( 'admin-ajax.php' ),
					'responsiveurl'         => RESPONSIVE_BLOCK_EDITOR_ADDONS_URL,
					'siteurl'               => site_url(),
					'installing'            => esc_html__( 'Installing ', 'responsive' ),
					'activating'            => esc_html__( 'Activating ', 'responsive' ),
					'verify_network'        => esc_html__( 'Not connect. Verify Network.', 'responsive' ),
					'page_not_found'        => esc_html__( 'Requested page not found. [404]', 'responsive' ),
					'internal_server_error' => esc_html__( 'Internal Server Error [500]', 'responsive' ),
					'json_parse_failed'     => esc_html__( 'Requested JSON parse failed', 'responsive' ),
					'timeout_error'         => esc_html__( 'Time out error', 'responsive' ),
					'ajax_req_aborted'      => esc_html__( 'Ajax request aborted', 'responsive' ),
					'uncaught_error'        => esc_html__( 'Uncaught Error', 'responsive' ),
					'rbea_version'          => RESPONSIVE_BLOCK_EDITOR_ADDONS_VER,
					'review_link'           => esc_url( 'https://wordpress.org/support/plugin/responsive-block-editor-addons/reviews/#new-post' ),
					'rst_url'               => esc_url( 'https://wordpress.org/plugins/responsive-add-ons/' ),
					'rbea_blocks'           => $blocks,
					'auto_block_recovery'   => get_option( 'rbea_auto_block_recovery', '1' ),
					'global_inherit_from_theme' => get_option( 'rbea_global_inherit_from_theme', '0' ),
					'custom_css_on'         => get_option( 'rbea_custom_css_on', '1' ),
					'template_library_button_on' => get_option( 'rbea_template_library_button_on', '1' ),
					'default_content_width'  => get_option( 'rbea_default_content_width', 1340 ),
					'default_container_padding' => get_option( 'rbea_default_container_padding', 10 ),
					'default_container_gap'  => get_option( 'rbea_default_container_gap', 20 ),
					'nonce'                 => wp_create_nonce( 'responsive_block_editor_ajax_nonce' ),
					'rst_status'            => $this->rbea_plugin_status( $rst_path ),
					'rae_status'            => $this->rbea_plugin_status( 'responsive-addons-for-elementor/responsive-addons-for-elementor.php' ),
					'responsive_status'     => $this->get_responsive_theme_status(),
					'rst_nonce'             => $rst_nonce,
					'rae_nonce'             => $rae_nonce,
					'responsive_nonce'      => $responsive_nonce,
					'rst_redirect'          => admin_url( 'admin.php?page=responsive_add_ons' ),
					'rae_redirect'          => admin_url( 'admin.php?page=rael_getting_started' ),
					'responsive_redirect'   => admin_url( 'admin.php?page=responsive' ),
					'ai_suite'              => $this->rbea_get_ai_suite_settings(),
				)
			);

			add_filter( 'admin_footer_text', '__return_false' );
			remove_filter( 'update_footer', 'core_update_footer' );
		}
	}

	/**
	 * Add Icon for Theme Builder under Elementor Addons Submenu.
	 *
	 * @return void [description]
	 */
	public function responsive_block_editor_addons_responsive_menu() {
		wp_enqueue_script( 'responsive_block_editor_addons_responsive_menu', RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'admin/js/responsive-menu.js', array( 'jquery' ), RESPONSIVE_BLOCK_EDITOR_ADDONS_VER, true );
	}

	/**
	 * On admin init.
	 *
	 * Preform actions on WordPress admin initialization.
	 *
	 * Fired by `admin_init` action.
	 *
	 * @access public
	 */
	public function responsive_block_editor_addons_admin_init() {

		// Update option autoload value.
		if ( get_option( 'total-responsive-sites-data' ) ) {

			global $wpdb;

			$option_name = 'total-responsive-sites-data';

			$autoload_value = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT autoload FROM {$wpdb->options} WHERE option_name = %s",
					$option_name
				)
			);

			if ( $autoload_value && 'no' !== $autoload_value ) {
				// Execute the SQL query
				$result = $wpdb->query(
					$wpdb->prepare(
						"UPDATE {$wpdb->options} SET autoload = %s WHERE option_name = %s",
						'no',
						$option_name
					)
				);
			}
		}

		$this->responsive_block_editor_addons_remove_all_admin_notices();
	}

	/**
	 * [responsive_block_editor_addons_remove_all_admin_notices description]
	 */
	private function responsive_block_editor_addons_remove_all_admin_notices() {
		$responsive_block_editor_addons_pages = array(
			'responsive_block_editor_addons',
			'responsive-block-editor-addons',
		);

		if ( empty( $_GET['page'] ) || ! in_array( $_GET['page'], $responsive_block_editor_addons_pages, true ) ) { //phpcs:ignore
			return;
		}

		remove_all_actions( 'admin_notices' );
	}

	/**
	 * Adding Dashicons in WordPress Front-end
	 */
	public function load_dashicons_front_end() {
		wp_enqueue_style( 'dashicons' );
	}

	/**
	 * Add Wrapper to all the Blocks for fetching the Table of Contents Headings.
	 *
	 * @param string $content Post Content.
	 *
	 * @since 1.22.1
	 */
	public function add_table_of_contents_wrapper( $content ) {

		if ( true === self::$table_of_contents_flag ) {
			return '<div class="responsive-block-editor-addons-toc__entry-content"></div>' . $content;
		}

		return $content;
	}

	/**
	 * Function to display RBEA review notice on admin page.
	 *
	 * @return void
	 */
	public function rbea_admin_review_notice() {

		// Don't show notice if it has been dismissed
		if ( get_option( 'responsive_block_editor_addons_review_notice_dismissed' ) ) {
			return;
		}

		// Initialize the review notice option if it doesn't exist
		if ( false === get_option( 'responsive_block_editor_addons_review_notice' ) ) {
			set_transient( 'responsive_block_editor_addons_intial_timeout', true, 7 * 24 * 60 * 60 );
			update_option( 'responsive_block_editor_addons_review_notice', true );
		}

		// Check if the "maybe later" transient is active (user clicked "maybe later")
		$maybe_later_active = (bool) get_transient( 'responsive_block_editor_addons_timeout' );
		
		// If "maybe later" is active, don't show notice regardless of other conditions
		if ( $maybe_later_active ) {
			return;
		}
		
		// Check if 7-day delay has passed (original 7-day timer)
		$seven_day_delay_passed = false === get_option( 'responsive_block_editor_addons_intial_timeout' ) ? false : true;
		
		// Check if user has at least 3 posts/pages with RBA blocks
		$posts_with_blocks = $this->count_posts_with_rba_blocks();
		$has_five_posts_with_blocks = $posts_with_blocks >= 3;
		
		// Check if user has used template library
		$template_library_used = (bool) get_option( 'responsive_block_editor_addons_template_library_used' );
		
		// Show notice if:
		// 1. 7-day delay has passed, OR
		// 2. User has 3+ posts/pages with RBA blocks, OR
		// 3. User has used template library
		if ( $seven_day_delay_passed || $has_five_posts_with_blocks || $template_library_used ) {
			$image_url = plugins_url( 'admin/images/rbea-logo.svg', __DIR__ );
			printf(
				'<div class="notice notice-info rbea-ask-for-review-notice">
					<div class="rbea-notice-content-wrapper">
						<div class="rbea-notice-image">
							<img src="%8$s" class="custom-logo" alt="Responsive Blocks" itemprop="logo">
						</div>
						<div class="rbea-notice-content">
							<div class="rbea-notice-heading">
								%2$s
							</div>
							<p class="rbea-review-request-text rbea-review-notice-text-container">%3$s</p>
							<div class="rbea-review-notice-container">
								<a href="%1$s" class="rbea-notice-close rbea-review-notice button-primary rbea-review-dismiss-btn" target="_blank">
									%4$s
								</a>
								<span class="dashicons dashicons-calendar"></span>
								<a href="%9$s" data-repeat-notice-after="60" class="rbea-notice-close rbea-review-notice">
									%5$s
								</a>
								<span class="dashicons dashicons-smiley"></span>
								<a href="%7$s" class="rbea-notice-close rbea-review-notice">
									%6$s
								</a>
							</div>
						</div>
					</div>
					<div>
						<a href="%10$s"><button type="button" class="rbea-ask-review-notice-dismiss"></button></a>
					</div>
				</div>',
				esc_url( 'https://wordpress.org/support/plugin/responsive-block-editor-addons/reviews/' ),
				esc_html__( 'Hello! Seems like you have used Responsive Blocks Plugin to build this website — Thanks a ton!', 'responsive-block-editor-addons' ),
				esc_html__( 'Could you please do us a BIG favor and give it a 5-star rating on WordPress? This would boost our motivation and help other users make a comfortable decision while choosing the Responsive Blocks.', 'responsive-block-editor-addons' ),
				esc_html__( 'Ok, you deserve it', 'responsive-block-editor-addons' ),
				esc_html__( 'Nope, maybe later', 'responsive-block-editor-addons' ),
				esc_html__( 'I already did', 'responsive-block-editor-addons' ),
				esc_url( '?responsive-block-editor-addons-notice-dismissed=true' ),
				esc_url( $image_url ),
				esc_url( '?responsive-block-editor-addons-review-notice-change-timeout=true' ),
				esc_url( '?responsive-block-editor-addons-cross-dismiss=true' )
			);
		}
	}

	/**
	 * Removed Ask For Review Admin Notice when dismissed.
	 */
	public function rba_notice_dismissed() {
		if ( isset( $_GET['responsive-block-editor-addons-notice-dismissed'] ) ) {
			update_option( 'responsive_block_editor_addons_review_notice_dismissed', true );
			wp_safe_redirect( remove_query_arg( array( 'responsive-block-editor-addons-notice-dismissed' ), wp_get_referer() ) );
		}
	}

	/**
	 * Removed Ask For Review Admin Notice when dismissed.
	 */
	public function rba_notice_change_timeout() {
		if ( isset( $_GET['responsive-block-editor-addons-review-notice-change-timeout'] ) ) {
			set_transient( 'responsive_block_editor_addons_timeout', true, DAY_IN_SECONDS );
			wp_safe_redirect( remove_query_arg( array( 'responsive-block-editor-addons-review-notice-change-timeout' ), wp_get_referer() ) );
		}
	}

	/**
	 * Handle cross button dismiss with 30-day timeout.
	 */
	public function rba_notice_cross_dismiss() {
		if ( isset( $_GET['responsive-block-editor-addons-cross-dismiss'] ) ) {
			set_transient( 'responsive_block_editor_addons_timeout', true, 30 * DAY_IN_SECONDS );
			wp_safe_redirect( remove_query_arg( array( 'responsive-block-editor-addons-cross-dismiss' ), wp_get_referer() ) );
		}
	}

	/**
	 * Count posts and pages that contain at least one RBA block.
	 *
	 * @return int Number of posts/pages with RBA blocks.
	 */
	public function count_posts_with_rba_blocks() {
		// Get all RBA block names
		$rba_blocks = array(
			'responsive-block-editor-addons/accordion',
			'responsive-block-editor-addons/advance-columns',
			'responsive-block-editor-addons/advanced-heading',
			'responsive-block-editor-addons/advanced-text',
			'responsive-block-editor-addons/anchor',
			'responsive-block-editor-addons/blockquote',
			'responsive-block-editor-addons/buttons',
			'responsive-block-editor-addons/call-mail-button',
			'responsive-block-editor-addons/call-to-action',
			'responsive-block-editor-addons/card',
			'responsive-block-editor-addons/container',
			'responsive-block-editor-addons/contact-form-7-styler',
			'responsive-block-editor-addons/content-timeline',
			'responsive-block-editor-addons/count-down',
			'responsive-block-editor-addons/count-up',
			'responsive-block-editor-addons/divider',
			'responsive-block-editor-addons/expand',
			'responsive-block-editor-addons/feature-grid',
			'responsive-block-editor-addons/flipbox',
			'responsive-block-editor-addons/form',
			'responsive-block-editor-addons/gallery-masonry',
			'responsive-block-editor-addons/googlemap',
			'responsive-block-editor-addons/how-to',
			'responsive-block-editor-addons/icons-list',
			'responsive-block-editor-addons/image',
			'responsive-block-editor-addons/image-boxes',
			'responsive-block-editor-addons/image-hotspot',
			'responsive-block-editor-addons/image-slider',
			'responsive-block-editor-addons/inline-notice',
			'responsive-block-editor-addons/instagram',
			'responsive-block-editor-addons/popup',
			'responsive-block-editor-addons/portfolio',
			'responsive-block-editor-addons/post-carousel',
			'responsive-block-editor-addons/post-grid',
			'responsive-block-editor-addons/post-timeline',
			'responsive-block-editor-addons/pricing-list',
			'responsive-block-editor-addons/pricing-table',
			'responsive-block-editor-addons/progress-bar',
			'responsive-block-editor-addons/section',
			'responsive-block-editor-addons/section-block',
			'responsive-block-editor-addons/shape-divider',
			'responsive-block-editor-addons/social-share',
			'responsive-block-editor-addons/spacer',
			'responsive-block-editor-addons/table-of-contents',
			'responsive-block-editor-addons/tabs',
			'responsive-block-editor-addons/taxonomy-list',
			'responsive-block-editor-addons/team',
			'responsive-block-editor-addons/testimonial',
			'responsive-block-editor-addons/testimonial-slider',
			'responsive-block-editor-addons/video-popup',
			'responsive-block-editor-addons/wp-search',
		);

		// Query for published posts and pages
		$args = array(
			'post_type'      => array( 'post', 'page' ),
			'post_status'    => 'publish',
			'posts_per_page' => -1,
			'fields'         => 'ids',
		);

		$posts = get_posts( $args );
		$count = 0;

		foreach ( $posts as $post_id ) {
			$content = get_post_field( 'post_content', $post_id );
			
			// Check if any RBA block exists in the content
			foreach ( $rba_blocks as $block_name ) {
				if ( strpos( $content, '<!-- wp:' . $block_name ) !== false ) {
					$count++;
					break; // Count this post only once, even if it has multiple RBA blocks
				}
			}
		}
		return $count;
	}

	/**
	 * Stores and Displays the Blocks.
	 *
	 * @since 1.7.0
	 */
	public function responsive_block_editor_addons_blocks_display() {

		require_once RESPONSIVE_BLOCK_EDITOR_ADDONS_DIR . 'includes/class-responsive-block-editor-addons-blocks-updater.php';

		$rbea_blocks = Responsive_Block_Editor_Addons_Blocks_Updater::get_instance();

		$rbea_path = 'responsive-block-editor-addons/responsive-block-editor-addons.php';

		// Get the current value of 'rbea_plugin_updated' option
		$exist_rbea_blocks_data_update = get_option( 'rbea_blocks_data_update', false );

		// If the option does not exist, add it with a value of false
		if ( ! $exist_rbea_blocks_data_update ) {
			$rbea_blocks->insert_blocks_data();
			update_option( 'rbea_blocks_data_update', true );
		}

		if ( ! function_exists( 'get_plugins' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}

		$installed_plugins = get_plugins();

		if ( isset( $installed_plugins[ $rbea_path ] ) ) {
			$installed_rbea_version = $installed_plugins[ $rbea_path ]['Version'];

			$blocks = get_option( 'rbea_blocks' );
			if ( ! $blocks ) {
				$rbea_blocks->insert_blocks_data();
			} else {
				$rbea_blocks->sync_blocks_data( $blocks );
			}
		}
	}

	/**
	 * Saves the block data in database when the block is toggled.
	 *
	 * @since 1.7.0
	 */
	public function rbea_blocks_toggle() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
			return;
		}

		if ( ! isset( $_POST['value'] ) ) {
			wp_send_json_error();
		}

		// Pre-sanitizing the response using a custom function to ensure all values are cleaned.
		// PHPCS incorrectly flags this as unsanitized, so the warning is suppressed.
		// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$data = $this->recursive_sanitize_text_field( json_decode( stripslashes( wp_unslash( $_POST['value'] ) ), true ) );
		// phpcs:enable

		update_option( 'rbea_blocks', $data );

		wp_send_json_success();
	}

	/**
	 * Saves the auto block recovery setting in database when the toggle is changed.
	 *
	 * @since 2.0.0
	 */
	public function rbea_toggle_auto_block_recovery() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
			return;
		}

		if ( ! isset( $_POST['value'] ) ) {
			wp_send_json_error();
		}

		// Sanitize the boolean value.
		$value = sanitize_text_field( wp_unslash( $_POST['value'] ) );
		$value = ( '1' === $value ) ? '1' : '0';

		update_option( 'rbea_auto_block_recovery', $value );

		wp_send_json_success();
	}

	/**
	 * Saves the global inherit from theme setting in database when the toggle is changed.
	 *
	 * @since 2.1.4
	 */
	public function rbea_toggle_global_inherit_from_theme() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
			return;
		}

		if ( ! isset( $_POST['value'] ) ) {
			wp_send_json_error();
		}

		// Sanitize the boolean value.
		$raw_value = sanitize_text_field( wp_unslash( $_POST['value'] ) );
		$value = ( '1' === $raw_value ) ? '1' : '0';

		update_option( 'rbea_global_inherit_from_theme', $value );

		// Record the time when the toggle was changed
		$timestamp = current_datetime()->format( 'c' );
		update_option( 'rbea_global_inherit_from_theme_last_changed', $timestamp, 'no' );

		wp_send_json_success();
	}

	/**
	 * Saves the custom CSS setting in database when the toggle is changed.
	 *
	 * @since 2.1.7
	 */
	public function rbea_toggle_custom_css() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
			return;
		}

		if ( ! isset( $_POST['value'] ) ) {
			wp_send_json_error();
		}

		// Sanitize the boolean value.
		$value = sanitize_text_field( wp_unslash( $_POST['value'] ) );
		$value = ( '1' === $value ) ? '1' : '0';

		update_option( 'rbea_custom_css_on', $value );

		wp_send_json_success();
	}

	/**
	 * Saves the template library button setting in database when the toggle is changed.
	 *
	 * @since 2.1.8
	 */
	public function rbea_toggle_template_library_button() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
			return;
		}

		if ( ! isset( $_POST['value'] ) ) {
			wp_send_json_error();
		}

		// Sanitize the boolean value.
		$value = sanitize_text_field( wp_unslash( $_POST['value'] ) );
		$value = ( '1' === $value ) ? '1' : '0';

		update_option( 'rbea_template_library_button_on', $value );

		wp_send_json_success();
	}

	/**
	 * Handles AJAX request to save the default content width setting.
	 *
	 * @since 2.1.5
	 * @return void
	 */
	public function rbea_save_content_width() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
			return;
		}

		if ( ! isset( $_POST['value'] ) ) {
			wp_send_json_error();
		}

		// Sanitize the numeric value.
		$value = intval( sanitize_text_field( wp_unslash( $_POST['value'] ) ) );
		
		// Ensure value is within reasonable bounds.
		$value = max( 100, min( 2000, $value ) );

		update_option( 'rbea_default_content_width', $value );

		wp_send_json_success();
	}

	/**
	 * Handles AJAX request to save the default container padding setting.
	 *
	 * @since 2.1.5
	 * @return void
	 */
	public function rbea_save_container_padding() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
			return;
		}

		if ( ! isset( $_POST['value'] ) ) {
			wp_send_json_error();
		}

		// Sanitize the numeric value.
		$value = intval( sanitize_text_field( wp_unslash( $_POST['value'] ) ) );
		
		// Ensure value is within reasonable bounds.
		$value = max( 0, min( 2000, $value ) );

		update_option( 'rbea_default_container_padding', $value );

		wp_send_json_success();
	}

	/**
	 * Handles AJAX request to save the default container gap setting.
	 *
	 * @since 2.1.5
	 * @return void
	 */
	public function rbea_save_container_gap() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
			return;
		}

		if ( ! isset( $_POST['value'] ) ) {
			wp_send_json_error();
		}

		// Sanitize the numeric value.
		$value = intval( sanitize_text_field( wp_unslash( $_POST['value'] ) ) );
		
		// Ensure value is within reasonable bounds.
		$value = max( 0, min( 2000, $value ) );

		update_option( 'rbea_default_container_gap', $value );

		wp_send_json_success();
	}

	/**
	 * Read the saved Ai Suite settings merged onto defaults.
	 *
	 * Used by the getting-started localize step (to hydrate the dashboard) and
	 * by the AJAX save handler (to compute the "current" baseline before merge).
	 *
	 * @return array
	 */
	public function rbea_get_ai_suite_settings() {
		$defaults = array(
			'enable_ai_writer' => true,
			'post_types'       => 'all',
			'user_role_access' => 'editor',
			'context'          => '',
			'default_tone'     => 'professional',
			'default_length'   => 'large',
			'default_language' => 'english',
			'max_tokens'       => 1500,
		);
		$saved = get_option( 'rbea_ai_suite_settings', array() );
		if ( ! is_array( $saved ) ) {
			$saved = array();
		}
		$merged = array_merge( $defaults, $saved );

		// Treat stored empty strings as "unset" so defaults apply after first install / partial saves.
		$fill_if_empty = array(
			'post_types',
			'user_role_access',
			'default_tone',
			'default_length',
			'default_language',
		);
		foreach ( $fill_if_empty as $key ) {
			if ( ! isset( $merged[ $key ] ) || '' === trim( (string) $merged[ $key ] ) ) {
				$merged[ $key ] = $defaults[ $key ];
			}
		}

		$mt = isset( $merged['max_tokens'] ) ? absint( $merged['max_tokens'] ) : 0;
		if ( $mt < 100 ) {
			$mt = 1500;
		}
		if ( $mt > 10000 ) {
			$mt = 10000;
		}
		$merged['max_tokens'] = $mt;

		return $merged;
	}

	/**
	 * Settings array for `update_option` (drops computed keys).
	 *
	 * @param array $settings Merged settings.
	 * @return array
	 */
	protected function rbea_ai_suite_settings_for_storage( array $settings ) {
		return $settings;
	}

	/**
	 * Language slug => English name for AI prompts (must match JS `src/utils/ai-suite-choices.js`).
	 *
	 * @return array<string, string>
	 */
	public function rbea_get_ai_suite_language_labels() {
		static $labels = null;
		if ( null !== $labels ) {
			return $labels;
		}

		$labels = array(
			'afrikaans'         => 'Afrikaans',
			'amharic'           => 'Amharic',
			'arabic'            => 'Arabic',
			'azerbaijani'       => 'Azerbaijani',
			'belarusian'        => 'Belarusian',
			'bulgarian'         => 'Bulgarian',
			'bengali'           => 'Bengali',
			'bosnian'           => 'Bosnian',
			'catalan'           => 'Catalan',
			'cebuano'           => 'Cebuano',
			'czech'             => 'Czech',
			'welsh'             => 'Welsh',
			'danish'            => 'Danish',
			'german'            => 'German',
			'greek'             => 'Greek',
			'english'           => 'English',
			'esperanto'        => 'Esperanto',
			'spanish'           => 'Spanish',
			'estonian'          => 'Estonian',
			'basque'            => 'Basque',
			'persian'           => 'Persian',
			'finnish'           => 'Finnish',
			'french'            => 'French',
			'galician'          => 'Galician',
			'gujarati'          => 'Gujarati',
			'hebrew'            => 'Hebrew',
			'hindi'             => 'Hindi',
			'croatian'          => 'Croatian',
			'hungarian'         => 'Hungarian',
			'armenian'          => 'Armenian',
			'indonesian'        => 'Indonesian',
			'icelandic'         => 'Icelandic',
			'italian'           => 'Italian',
			'japanese'          => 'Japanese',
			'javanese'          => 'Javanese',
			'georgian'          => 'Georgian',
			'kazakh'            => 'Kazakh',
			'khmer'             => 'Khmer',
			'kannada'           => 'Kannada',
			'korean'            => 'Korean',
			'kurdish'           => 'Kurdish',
			'kyrgyz'            => 'Kyrgyz',
			'lao'               => 'Lao',
			'lithuanian'        => 'Lithuanian',
			'latvian'           => 'Latvian',
			'macedonian'        => 'Macedonian',
			'malayalam'         => 'Malayalam',
			'mongolian'         => 'Mongolian',
			'marathi'           => 'Marathi',
			'malay'             => 'Malay',
			'burmese'           => 'Burmese',
			'norwegian_bokmal'  => 'Norwegian Bokmål',
			'nepali'            => 'Nepali',
			'dutch'             => 'Dutch',
			'norwegian_nynorsk' => 'Norwegian Nynorsk',
			'occitan'           => 'Occitan',
			'punjabi'           => 'Punjabi',
			'polish'            => 'Polish',
			'portuguese'        => 'Portuguese',
			'romanian'          => 'Romanian',
			'russian'           => 'Russian',
			'sakha_yakut'       => 'Sakha (Yakut)',
			'sindhi'            => 'Sindhi',
			'sinhala'           => 'Sinhala',
			'slovak'            => 'Slovak',
			'slovenian'         => 'Slovenian',
			'albanian'          => 'Albanian',
			'serbian'           => 'Serbian',
			'swedish'           => 'Swedish',
			'swahili'           => 'Swahili',
			'tamil'             => 'Tamil',
			'telugu'            => 'Telugu',
			'thai'              => 'Thai',
			'tagalog'           => 'Tagalog',
			'turkish'           => 'Turkish',
			'tatar'             => 'Tatar',
			'uyghur'            => 'Uyghur',
			'ukrainian'         => 'Ukrainian',
			'urdu'              => 'Urdu',
			'uzbek'             => 'Uzbek',
			'vietnamese'        => 'Vietnamese',
			'yoruba'            => 'Yoruba',
			'chinese'           => 'Chinese',
		);

		return $labels;
	}

	/**
	 * Handles AJAX request to save the Ai Suite dashboard settings.
	 *
	 * Accepts each field as an individual `$_POST` key, sanitizes, merges with
	 * the existing values, and persists into the `rbea_ai_suite_settings` option.
	 */
	public function rbea_save_ai_suite_settings() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Forbidden' ), 403 );
			return;
		}

		$current = $this->rbea_get_ai_suite_settings();
		$post    = wp_unslash( $_POST );

		$text_fields = array(
			'post_types',
			'user_role_access',
			'default_tone',
			'default_length',
			'default_language',
		);

		$clean = $current;

		if ( array_key_exists( 'enable_ai_writer', $post ) ) {
			$value                     = (string) $post['enable_ai_writer'];
			$clean['enable_ai_writer'] = ( '1' === $value || 'true' === $value );
		}

		foreach ( $text_fields as $field ) {
			if ( array_key_exists( $field, $post ) ) {
				$clean[ $field ] = sanitize_text_field( (string) $post[ $field ] );
			}
		}

		if ( array_key_exists( 'context', $post ) ) {
			$clean['context'] = sanitize_textarea_field( (string) $post['context'] );
		}

		if ( array_key_exists( 'max_tokens', $post ) ) {
			$clean['max_tokens'] = absint( $post['max_tokens'] );
		}

		$allowed_post_types = array( 'all', 'post', 'page' );
		if ( ! in_array( (string) $clean['post_types'], $allowed_post_types, true ) ) {
			$clean['post_types'] = 'all';
		}

		$allowed_roles = array( 'administrator', 'editor' );
		if ( ! in_array( (string) $clean['user_role_access'], $allowed_roles, true ) ) {
			$clean['user_role_access'] = 'editor';
		}

		$allowed_tones = array( 'informative', 'casual', 'friendly', 'professional', 'inspirational' );
		if ( ! in_array( (string) $clean['default_tone'], $allowed_tones, true ) ) {
			$clean['default_tone'] = 'professional';
		}

		$allowed_lengths = array( 'short', 'medium', 'large', 'big' );
		if ( ! in_array( (string) $clean['default_length'], $allowed_lengths, true ) ) {
			$clean['default_length'] = 'large';
		}

		$lang_labels = $this->rbea_get_ai_suite_language_labels();
		if ( ! isset( $lang_labels[ (string) $clean['default_language'] ] ) ) {
			$clean['default_language'] = 'english';
		}

		$max_tokens = absint( $clean['max_tokens'] );
		if ( $max_tokens < 100 ) {
			$max_tokens = 1500;
		}
		if ( $max_tokens > 10000 ) {
			$max_tokens = 10000;
		}
		$clean['max_tokens'] = $max_tokens;

		update_option( 'rbea_ai_suite_settings', $this->rbea_ai_suite_settings_for_storage( $clean ) );

		wp_send_json_success( $clean );
	}

	/**
	 * Whether the logged-in user satisfies Ai Suite "User Role Access" for the AI Write toolbar.
	 *
	 * @param string $user_role_access Saved setting: `administrator` or `editor`.
	 * @return bool
	 */
	protected function rbea_ai_write_current_user_passes_role_gate( $user_role_access ) {
		$user = wp_get_current_user();
		if ( ! $user || ! $user->ID ) {
			return false;
		}
		$uid = (int) $user->ID;
		if ( function_exists( 'is_multisite' ) && is_multisite() && function_exists( 'is_super_admin' ) && is_super_admin( $uid ) ) {
			return true;
		}
		$access = (string) $user_role_access;
		if ( 'administrator' === $access ) {
			return user_can( $user, 'manage_options' );
		}
		if ( 'editor' === $access ) {
			return user_can( $user, 'edit_others_posts' ) || user_can( $user, 'manage_options' );
		}
		return false;
	}

	/**
	 * Editor-safe Ai Suite indicators for `responsive_globals`.
	 *
	 * Mirrors the dashboard `ai_suite` shape but never sends the raw API key
	 * to the editor — only `has_api_key` so the UI can show / hide the
	 * "Connect your API key" notice. Includes `post_types` and `ai_write_role_allowed`
	 * for AI Write toolbar gating (no API key).
	 *
	 * @return array
	 */
	public function rbea_get_ai_suite_indicators() {
		$settings = $this->rbea_get_ai_suite_settings();
		$wp_ai_supported = function_exists( 'wp_ai_client_prompt' ) && function_exists( 'wp_supports_ai' );
		$has_ai          = false;
		if ( $wp_ai_supported && wp_supports_ai() ) {
			$has_ai = wp_ai_client_prompt( 'test' )->is_supported_for_text_generation();
		}
		$connectors_url = ( function_exists( 'is_multisite' ) && is_multisite() )
			? network_admin_url( 'options-connectors.php' )
			: admin_url( 'options-connectors.php' );
		return array(
			'enable_ai_writer'        => (bool) $settings['enable_ai_writer'],
			// Back-compat shape for the editor UI: this now means "AI is available via WP Connectors".
			'has_api_key'             => (bool) $has_ai,
			'wp_ai_supported'         => (bool) $wp_ai_supported,
			'default_tone'            => $settings['default_tone'],
			'default_length'          => $settings['default_length'],
			'default_language'        => $settings['default_language'],
			'post_types'              => $settings['post_types'],
			'ai_write_role_allowed'   => $this->rbea_ai_write_current_user_passes_role_gate( $settings['user_role_access'] ),
			'settings_url'            => $connectors_url,
		);
	}

	/**
	 * AJAX handler — proxy a generation request to the configured AI provider.
	 *
	 * Accepts `prompt`, `length`, `tone`, and optional `language` from $_POST
	 * (language falls back to saved Ai Suite default when omitted). Reads API
	 * key, provider, model, and `max_tokens` from `rbea_ai_suite_settings`.
	 * `maxOutputTokens` uses saved `max_tokens` (default 1500, clamped 100–10000).
	 */
	public function rbea_ai_generate() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( ! current_user_can( 'edit_posts' ) ) {
			wp_send_json_error( array( 'message' => __( 'Forbidden', 'responsive-block-editor-addons' ) ), 403 );
			return;
		}

		if ( ! function_exists( 'wp_ai_client_prompt' ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'AI features require WordPress 7.0 or newer.', 'responsive-block-editor-addons' ),
				),
				501
			);
			return;
		}

		$post   = wp_unslash( $_POST );
		$prompt = isset( $post['prompt'] ) ? sanitize_textarea_field( (string) $post['prompt'] ) : '';
		$length   = isset( $post['length'] ) ? sanitize_text_field( (string) $post['length'] ) : '';
		$tone     = isset( $post['tone'] ) ? sanitize_text_field( (string) $post['tone'] ) : '';
		$language = isset( $post['language'] ) ? sanitize_text_field( (string) $post['language'] ) : '';

		$allowed_lengths_ajax = array( 'short', 'medium', 'large', 'big' );
		$allowed_tones_ajax   = array( 'informative', 'casual', 'friendly', 'professional', 'inspirational' );

		if ( '' === $prompt ) {
			wp_send_json_error(
				array( 'message' => __( 'Please enter a prompt before generating.', 'responsive-block-editor-addons' ) ),
				400
			);
			return;
		}

		$settings = $this->rbea_get_ai_suite_settings();

		if ( ! in_array( $length, $allowed_lengths_ajax, true ) ) {
			$length = (string) $settings['default_length'];
		}
		if ( ! in_array( $length, $allowed_lengths_ajax, true ) ) {
			$length = 'large';
		}

		if ( ! in_array( $tone, $allowed_tones_ajax, true ) ) {
			$tone = (string) $settings['default_tone'];
		}
		if ( ! in_array( $tone, $allowed_tones_ajax, true ) ) {
			$tone = 'professional';
		}

		$lang_labels = $this->rbea_get_ai_suite_language_labels();
		if ( '' === $language ) {
			$language = (string) $settings['default_language'];
		}
		if ( ! isset( $lang_labels[ $language ] ) ) {
			$language = 'english';
		}
		$language_name = (string) $lang_labels[ $language ];

		$max_output_tokens = absint( $settings['max_tokens'] );
		if ( $max_output_tokens < 100 ) {
			$max_output_tokens = 1500;
		}
		if ( $max_output_tokens > 10000 ) {
			$max_output_tokens = 10000;
		}

		// Length → approximate word target (aligned with Ai Suite / AI Write UI).
		$length_map  = array(
			'short'  => __( 'Keep it very brief — about 5 to 15 words.', 'responsive-block-editor-addons' ),
			'medium' => __( 'Aim for about 20 to 30 words.', 'responsive-block-editor-addons' ),
			'large'  => __( 'Aim for about 40 to 60 words.', 'responsive-block-editor-addons' ),
			'big'    => __( 'Aim for at least 80 words.', 'responsive-block-editor-addons' ),
		);
		$length_hint = isset( $length_map[ $length ] ) ? $length_map[ $length ] : '';

		$tone_map  = array(
			'informative'   => __( 'Use a clear, informative tone.', 'responsive-block-editor-addons' ),
			'casual'        => __( 'Use a casual, conversational tone.', 'responsive-block-editor-addons' ),
			'friendly'      => __( 'Use a warm, friendly tone.', 'responsive-block-editor-addons' ),
			'professional'  => __( 'Use a professional, business-appropriate tone.', 'responsive-block-editor-addons' ),
			'inspirational' => __( 'Use an inspirational, motivating tone.', 'responsive-block-editor-addons' ),
		);
		$tone_hint = isset( $tone_map[ $tone ] ) ? $tone_map[ $tone ] : '';

		$language_hint = sprintf(
			/* translators: %s: language name, e.g. "Spanish". */
			__( 'Write entirely in %s.', 'responsive-block-editor-addons' ),
			$language_name
		);
		$context = trim( (string) ( $settings['context'] ?? '' ) );

		$instructions  = "Write content for the topic below. Return plain text only — no HTML, no Markdown, no surrounding quotes, no commentary.";
		$instructions .= "\n" . $language_hint;
		$instructions .= $tone_hint ? "\n" . $tone_hint : '';
		$instructions .= $length_hint ? "\n" . $length_hint : '';
		if ( '' !== $context ) {
			$instructions .= "\n\n" . __(
				'Use the site context below to align the response with the website purpose, target audience, and brand guidelines when relevant.',
				'responsive-block-editor-addons'
			);
			$instructions .= "\n" . __( 'Site context:', 'responsive-block-editor-addons' ) . "\n" . $context;
		}

		$builder = wp_ai_client_prompt( 'Topic: ' . $prompt )
			->using_system_instruction( $instructions )
			->using_max_tokens( $max_output_tokens )
			->using_temperature( 0.7 )
			->using_model_preference( 'gemini-2.5-flash-lite' );

		if ( ! $builder->is_supported_for_text_generation() ) {
			wp_send_json_error(
				array(
					'message' => __( 'No AI provider is configured. Install an AI provider plugin and add a key under Settings → Connectors.', 'responsive-block-editor-addons' ),
				),
				400
			);
			return;
		}

		$text = $builder->generate_text();
		if ( is_wp_error( $text ) ) {
			$error_data = $text->get_error_data();
			$status     = is_array( $error_data ) && isset( $error_data['status'] ) ? (int) $error_data['status'] : 500;
			wp_send_json_error(
				array(
					'message' => $this->rbea_ai_humanize_wp_ai_error( $text ),
				),
				$status
			);
			return;
		}

		wp_send_json_success( array( 'text' => $text ) );
	}

	/**
	 * AJAX handler — rewrite existing text directly from the rewrite-mode popup.
	 *
	 * Accepts `text`, a `rewrite_action`, and optional `tone` / `language`.
	 * Uses the saved Ai Suite provider/model/API key and returns rewritten plain text.
	 */
	public function rbea_ai_rewrite() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		if ( ! current_user_can( 'edit_posts' ) ) {
			wp_send_json_error( array( 'message' => __( 'Forbidden', 'responsive-block-editor-addons' ) ), 403 );
			return;
		}

		if ( ! function_exists( 'wp_ai_client_prompt' ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'AI features require WordPress 7.0 or newer.', 'responsive-block-editor-addons' ),
				),
				501
			);
			return;
		}

		$post           = wp_unslash( $_POST );
		$text           = isset( $post['text'] ) ? sanitize_textarea_field( (string) $post['text'] ) : '';
		$rewrite_action = isset( $post['rewrite_action'] ) ? sanitize_text_field( (string) $post['rewrite_action'] ) : '';
		$tone           = isset( $post['tone'] ) ? sanitize_text_field( (string) $post['tone'] ) : '';
		$language       = isset( $post['language'] ) ? sanitize_text_field( (string) $post['language'] ) : '';

		if ( '' === $text ) {
			wp_send_json_error(
				array(
					'message' => __( 'Enter or keep some text in the textarea before rewriting.', 'responsive-block-editor-addons' ),
				),
				400
			);
			return;
		}

		$allowed_rewrite_actions = array(
			'simplify_language',
			'make_longer',
			'make_shorter',
			'fix_spelling_grammar',
			'change_tone',
			'translate_to',
		);
		if ( ! in_array( $rewrite_action, $allowed_rewrite_actions, true ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Choose a valid rewrite action.', 'responsive-block-editor-addons' ),
				),
				400
			);
			return;
		}

		$settings = $this->rbea_get_ai_suite_settings();
		$context  = trim( (string) ( $settings['context'] ?? '' ) );

		$allowed_tones_ajax = array( 'informative', 'casual', 'friendly', 'professional', 'inspirational' );
		$tone_map  = array(
			'informative'   => __( 'Use a clear, informative tone.', 'responsive-block-editor-addons' ),
			'casual'        => __( 'Use a casual, conversational tone.', 'responsive-block-editor-addons' ),
			'friendly'      => __( 'Use a warm, friendly tone.', 'responsive-block-editor-addons' ),
			'professional'  => __( 'Use a professional, business-appropriate tone.', 'responsive-block-editor-addons' ),
			'inspirational' => __( 'Use an inspirational, motivating tone.', 'responsive-block-editor-addons' ),
		);
		$lang_labels = $this->rbea_get_ai_suite_language_labels();

		$action_instruction = '';
		switch ( $rewrite_action ) {
			case 'simplify_language':
				$action_instruction = __( 'Simplify the following text without changing its language. Preserve the original meaning and tone while making it easier to read and understand.', 'responsive-block-editor-addons' );
				break;
			case 'make_longer':
				$action_instruction = __( 'Expand the text with a bit more detail while preserving the original meaning.', 'responsive-block-editor-addons' );
				break;
			case 'make_shorter':
				$action_instruction = __( 'Shorten the text while preserving the key meaning and clarity.', 'responsive-block-editor-addons' );
				break;
			case 'fix_spelling_grammar':
				$action_instruction = __( 'Fix spelling, grammar, punctuation, and awkward phrasing while preserving the meaning.', 'responsive-block-editor-addons' );
				break;
			case 'change_tone':
				if ( ! in_array( $tone, $allowed_tones_ajax, true ) ) {
					wp_send_json_error(
						array(
							'message' => __( 'Choose a tone before rewriting.', 'responsive-block-editor-addons' ),
						),
						400
					);
					return;
				}
				$action_instruction = isset( $tone_map[ $tone ] ) ? $tone_map[ $tone ] : '';
				break;
			case 'translate_to':
				if ( ! isset( $lang_labels[ $language ] ) ) {
					wp_send_json_error(
						array(
							'message' => __( 'Choose a language before rewriting.', 'responsive-block-editor-addons' ),
						),
						400
					);
					return;
				}
				$action_instruction = sprintf(
					/* translators: %s: language name, e.g. "Spanish". */
					__( 'Translate the text entirely into %s while preserving the meaning.', 'responsive-block-editor-addons' ),
					(string) $lang_labels[ $language ]
				);
				break;
		}

		$max_output_tokens = absint( $settings['max_tokens'] );
		if ( $max_output_tokens < 100 ) {
			$max_output_tokens = 1500;
		}
		if ( $max_output_tokens > 10000 ) {
			$max_output_tokens = 10000;
		}

		$instructions  = 'Rewrite the text below. Return plain text only — no HTML, no Markdown, no surrounding quotes, no commentary.';
		if ( '' !== $context ) {
			$instructions .= "\n\n" . __(
				'Use the site context below to align the response with the website purpose, target audience, and brand guidelines when relevant.',
				'responsive-block-editor-addons'
			);
			$instructions .= "\n" . __( 'Site context:', 'responsive-block-editor-addons' ) . "\n" . $context;
		}
		$instructions .= "\n" . $action_instruction;

		$builder = wp_ai_client_prompt( "Text:\n" . $text )
			->using_system_instruction( $instructions )
			->using_max_tokens( $max_output_tokens )
			->using_temperature( 0.5 )
			->using_model_preference ( 'gemini-2.5-flash-lite' );

		if ( ! $builder->is_supported_for_text_generation() ) {
			wp_send_json_error(
				array(
					'message' => __( 'No AI provider is configured. Install an AI provider plugin and add a key under Settings → Connectors.', 'responsive-block-editor-addons' ),
				),
				400
			);
			return;
		}

		$rewritten_text = $builder->generate_text();
		if ( is_wp_error( $rewritten_text ) ) {
			$error_data = $rewritten_text->get_error_data();
			$status     = is_array( $error_data ) && isset( $error_data['status'] ) ? (int) $error_data['status'] : 500;
			wp_send_json_error(
				array(
					'message' => $this->rbea_ai_humanize_wp_ai_error( $rewritten_text ),
				),
				$status
			);
			return;
		}

		wp_send_json_success( array( 'text' => $rewritten_text ) );
	}

	/**
	 * Human-friendly error messages for WP AI Client failures.
	 *
	 * Since providers are configured in WordPress (Connectors), avoid provider-specific wording
	 * and keep messages actionable without referencing models/billing.
	 *
	 * @param WP_Error $error Error returned by wp_ai_client_prompt()->generate_text().
	 * @return string
	 */
	protected function rbea_ai_humanize_wp_ai_error( WP_Error $error ) {
		$data   = $error->get_error_data();
		$status = is_array( $data ) && isset( $data['status'] ) ? (int) $data['status'] : 0;

		if ( 429 === $status ) {
			return __( 'AI is temporarily unavailable due to usage limits. Please try again later.', 'responsive-block-editor-addons' );
		}

		if ( 401 === $status || 403 === $status ) {
			return __( 'AI isn’t available due to a permissions issue. Please check the site’s AI provider configuration.', 'responsive-block-editor-addons' );
		}

		if ( $status >= 500 || 0 === $status ) {
			return __( 'The AI provider is temporarily unavailable. Please try again in a moment.', 'responsive-block-editor-addons' );
		}

		return __( 'Couldn’t generate content right now. Please try again.', 'responsive-block-editor-addons' );
	}

	/**
	 * Recursively sanitize the response fields from $_POST.
	 *
	 * @return mixed
	 */
	public function recursive_sanitize_text_field($array) {
		foreach ( $array as $key => &$value ) {
			if ( is_array( $value ) ) {
				$value = $this->recursive_sanitize_text_field($value);
			}
			else {
				$value = sanitize_text_field( wp_unslash( $value ) );
			}
		}
		return $array;
	}



	/**
	 * Function to integrate CF7 Forms.
	 *
	 * @since 1.10.0
	 */
	public function get_cf7_forms() {
		$field_options = array();

		if ( class_exists( 'WPCF7_ContactForm' ) ) {
			$args             = array(
				'post_type'      => 'wpcf7_contact_form',
				'posts_per_page' => -1,
			);
			$forms            = get_posts( $args );
			$field_options[0] = array(
				'value' => -1,
				'label' => __( 'Select Form', 'responsive-block-editor-addons' ),
			);
			if ( $forms ) {
				foreach ( $forms as $form ) {
					$field_options[] = array(
						'value' => $form->ID,
						'label' => $form->post_title,
					);
				}
			}
		}

		if ( empty( $field_options ) ) {
			$field_options = array(
				'-1' => __( 'You have not added any Contact Form 7 yet.', 'responsive-block-editor-addons' ),
			);
		}
		return $field_options;
	}


	/**
	 * Renders the Contact Form 7 shortcode.
	 *
	 * @since 1.10.0
	 */
	public function cf7_shortcode() {
		check_ajax_referer( 'responsive_block_editor_ajax_nonce', 'nonce' );

		$id = isset($_POST['formId']) ? intval($_POST['formId']) : 0;

		if ( $id && 0 !== $id && -1 !== $id ) {
			$data['html'] = do_shortcode( '[contact-form-7 id="' . $id . '" ajax="true"]' );
		} else {
			$data['html'] = '<p>' . __( 'Please select a valid Contact Form 7.', 'responsive-block-editor-addons' ) . '</p>';
		}
		wp_send_json_success( $data );
	}

	public function custom_rest_endpoint_callback( $data ) {

		$params = $data->get_params();

		if ( ! isset( $params['sync'] ) ) {
			return new WP_REST_Response( array( 'error' => 'Insufficient params' ), 500 );
		}

		// Check if the option exists and its value is "Activated".
		$is_pro_active = get_option( 'wc_am_client_responsive_addons_pro_activated' );

		if ( 'false' === $params['sync'] ) {
			$response_data = array(
				'pro_active' => 'Activated' === $is_pro_active,
			);
		}

		if ( 'true' === $params['sync'] ) {
			$is_xml_updated = get_option( 'last_xml_export_checksums' );
			$data           = get_option( 'total-responsive-sites-data' );
			// Fetch data from the external endpoint.
			$external_data = wp_remote_get(
				'https://ccreadysites.cyberchimps.com/wp-json/wp/v2/get-last-xml-export-checksum2',
				array(
					'timeout' => 20,
				)
			);

			if ( is_wp_error( $external_data ) ) {
				// Handle error from the external endpoint, if any.
				return new WP_REST_Response( array( 'error' => $external_data->get_error_message() ), 500 );
			}

			$external_data_body    = wp_remote_retrieve_body( $external_data );
			$external_data_decoded = json_decode( $external_data_body, true );
			$response_data         = array(
				'pro_active' => 'Activated' === $is_pro_active,
				'xml_update' => $external_data_decoded['last_xml_export_checksums'] !== $is_xml_updated,
				'data'       => $data,
			);
		}

		return new WP_REST_Response( $response_data, 200 );
	}

	/**
	 * Check if the user has capabilities to import Pro templates.
	 *
	 * @return WP_REST_Response
	 */
	public function check_user_capabilities_for_pro_templates() {
		$product_details = get_option( 'reads_app_settings' );

		if ( ! isset( $product_details ) || ! is_array( $product_details ) || empty( $product_details['account'] ) ) {
			return new WP_REST_Response(
				array( 'is_capable' => false ),
				403
			);
		}

		// Get the product ID from the product details.
		$product_id = $product_details['account']['product_id'] ?? null;

		
		if ( is_null( $product_id ) ) {
			return new WP_REST_Response(
				array(
					'is_capable' => false
				),
				403
			);
		}
		
		$product_id = (int) $product_id;
		
		$allowed_ids = array( 560, 561, 562 );
	
		$is_capable = in_array( $product_id, $allowed_ids, true );
	
		$status_code = $is_capable ? 200 : 403;
	
		return new WP_REST_Response(
			array(
				'is_capable' => $is_capable,
			),
			$status_code
		);
	}

	public function register_custom_rest_endpoint() {
		register_rest_route(
			'custom/v1', // Namespace
			'/responsive-pro-activation-status/', // Route
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'custom_rest_endpoint_callback' ),
				'permission_callback' => '__return_true', // No specific permissions for simplicity
			)
		);

		register_rest_route(
			'custom/v1', // Namespace
			'/pro-template-capability/', // Route
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'check_user_capabilities_for_pro_templates' ),
				'permission_callback' => '__return_true', // No specific permissions for simplicity
			)
		);
	}

	public function rbea_sync_library() {
		// Step 1: Get the count from the API hit
		$count_api_url  = 'https://ccreadysites.cyberchimps.com/wp-json/wp/v2/get-ready-sites-requests-count';
		$count_response = wp_remote_get(
			$count_api_url,
			array(
				'timeout' => 20,
			)
		);

		if ( is_wp_error( $count_response ) ) {
			wp_send_json_error();
		}

		$total_count = intval( wp_remote_retrieve_body( $count_response ) );

		if ( $total_count <= 0 ) {
			wp_send_json_error();
		}

		// Step 2: Calculate total pages
		$per_page    = 15;
		$total_pages = ceil( ( $total_count * $per_page ) / 100 );

		// Step 3: Store total pages in wp_options table
		update_option( 'total-responsive-site-pages', $total_pages );
		$all_filtered_data = array();

		// Step 4 and 5: Loop through pages and filter the response
		for ( $page = 1; $page <= $total_pages; $page++ ) {

			$api_url  = "https://ccreadysites.cyberchimps.com/wp-json/wp/v2/cyberchimps-sites/?per_page=100&page={$page}";
			$response = wp_remote_get(
				$api_url,
				array(
					'timeout' => 20,
				)
			);

			if ( ! is_wp_error( $response ) ) {
				$data = json_decode( wp_remote_retrieve_body( $response ), true );

				// Step 6: Filter the response by page_builder = gutenberg
				$filtered_data     = array_filter(
					$data,
					function ( $site ) {
						return isset( $site['page_builder'] ) && 'gutenberg' === $site['page_builder'];
					}
				);
				$all_filtered_data = array_merge( $all_filtered_data, $filtered_data );

			}
		}
		$filtered_json_all = wp_json_encode( $all_filtered_data, JSON_PRETTY_PRINT );
		update_option( 'total-responsive-sites-data', $filtered_json_all );

		$plugin_dir_path = plugin_dir_path( __FILE__ );
		$relative_path   = 'data/';
		$full_path       = $plugin_dir_path . $relative_path;
		$file_path_all   = $full_path . 'responsive-sites-gutenberg-all.json';

		$bytes_written = file_put_contents( $file_path_all, $filtered_json_all ); //phpcs:ignore

		// Check if the data was successfully written to the file
		if ( false !== $bytes_written ) {
			// Store latest checksum after successful sync so future sync clicks can skip work.
			$checksum_response = wp_remote_get(
				'https://ccreadysites.cyberchimps.com/wp-json/wp/v2/get-last-xml-export-checksum2',
				array(
					'timeout' => 20,
				)
			);
			if ( ! is_wp_error( $checksum_response ) ) {
				$checksum_body = wp_remote_retrieve_body( $checksum_response );
				$checksum_json = json_decode( $checksum_body, true );
				if ( is_array( $checksum_json ) && isset( $checksum_json['last_xml_export_checksums'] ) ) {
					update_option( 'last_xml_export_checksums', sanitize_text_field( $checksum_json['last_xml_export_checksums'] ) );
				}
			}

			wp_send_json_success( array( 'filtered_data' => $filtered_json_all ) );
		} else {
			wp_send_json_error( array( 'message' => 'Error writing filtered data to the file.' ) );
		}
		wp_send_json_success();
	}

	/**
	 * Process the form of Form Block.
	 *
	 * @since 1.7.9
	 */
	public function rba_form_block_processing() {
		register_rest_route(
			'wp/v2',
			'/rba_process_form',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'rba_form_processing' ),
				'permission_callback' => '__return_true',
			)
		);
	}

	/**
	 * Find form block by block_id in post content.
	 * Recursively searches through blocks and inner blocks.
	 *
	 * @param array  $blocks  Array of blocks to search.
	 * @param string $block_id The block_id to find.
	 * @return array|null Block attributes if found, null otherwise.
	 * @since 2.2.1
	 */
	private function find_form_block_by_id( $blocks, $block_id ) {
		if ( ! is_array( $blocks ) || empty( $blocks ) ) {
			return null;
		}

		foreach ( $blocks as $block ) {
			// Only search in our form blocks.
			if ( isset( $block['blockName'] ) && 'responsive-block-editor-addons/form' === $block['blockName'] ) {
				// Check if this is the block we're looking for.
				if ( isset( $block['attrs']['block_id'] ) && $block['attrs']['block_id'] === $block_id ) {
					return $block['attrs'];
				}
			}

			// Recursively search inner blocks.
			if ( ! empty( $block['innerBlocks'] ) ) {
				$result = $this->find_form_block_by_id( $block['innerBlocks'], $block_id );
				if ( null !== $result ) {
					return $result;
				}
			}
		}

		return null;
	}

	/**
	 * Get form block attributes by searching post, site builder, and widgets.
	 *
	 * @param string $block_id    The block_id to find.
	 * @param int    $post_id     The post ID to search first (0 if not available).
	 * @param bool   $block_found Reference parameter to indicate if block was found.
	 * @return array|null Block attributes if found, null otherwise.
	 * @since 2.2.1
	 */
	private function get_form_block_attributes( $block_id, $post_id, &$block_found = false ) {
		$block_found = false;

		// Search in the specific post first.
		if ( $post_id > 0 ) {
			$post_content = get_post_field( 'post_content', $post_id );
			if ( $post_content ) {
				$blocks = parse_blocks( $post_content );
				$block_attrs = $this->find_form_block_by_id( $blocks, $block_id );
				if ( null !== $block_attrs ) {
					$block_found = true;
					return $block_attrs;
				}
			}
		}

		// Search in Responsive Add-ons Site Builder posts.
		$site_builder_args = array(
			'post_type'      => 'resp-site-builder',
			'post_status'    => array( 'publish' ),
			'posts_per_page' => -1,
		);
		$site_builder_query = new WP_Query( $site_builder_args );

		if ( ! empty( $site_builder_query->posts ) ) {
			foreach ( $site_builder_query->posts as $sb_post ) {
				if ( is_object( $sb_post ) && ! empty( $sb_post->post_content ) ) {
					$blocks = parse_blocks( $sb_post->post_content );
					$block_attrs = $this->find_form_block_by_id( $blocks, $block_id );
					if ( null !== $block_attrs ) {
						$block_found = true;
						return $block_attrs;
					}
				}
			}
		}

		// Final fallback: Search in widget areas.
		$widget_blocks = get_option( 'widget_block' );
		if ( ! empty( $widget_blocks ) && is_array( $widget_blocks ) ) {
			foreach ( $widget_blocks as $widget ) {
				if ( ! empty( $widget['content'] ) ) {
					$blocks = parse_blocks( $widget['content'] );
					$block_attrs = $this->find_form_block_by_id( $blocks, $block_id );
					if ( null !== $block_attrs ) {
						$block_found = true;
						return $block_attrs;
					}
				}
			}
		}

		// Block not found.
		return null;
	}

	/**
	 * RBA Form Block Processing.
	 *
	 * @param WP_REST_Request $request WP_Query object.
	 * @since 1.7.9
	 */
	public function rba_form_processing( WP_REST_Request $request ) {
		$params    = $request->get_params();
		$form_data = $params['form_data'];
		$page_url  = $params['page_url'];
		$block_id  = isset( $params['block_id'] ) ? sanitize_text_field( $params['block_id'] ) : '';
		$post_id   = isset( $params['post_id'] ) ? absint( $params['post_id'] ) : 0;
		$site_name = isset( $params['site_name'] ) ? $params['site_name'] : '';
		$site_url  = isset( $params['site_url'] ) ? $params['site_url'] : '';

		// Require block_id and post_id - reject if block_id is missing.
		if ( empty( $block_id ) ) {
			return rest_ensure_response(
				array(
					'success' => false,
					'message' => 'Block ID and Post ID are required.',
				)
			);
		}

		// Security fix: Get block attributes from server-side, never trust client input.
		$block_found = false;
		$block_attrs = $this->get_form_block_attributes( $block_id, $post_id, $block_found );

		// If block not found, reject the request.
		if ( ! $block_found || null === $block_attrs ) {
			return rest_ensure_response(
				array(
					'success' => false,
					'message' => 'Form block not found. Invalid submission.',
				)
			);
		}

		// Extract email_to from block attributes.
		$email_to = isset( $block_attrs['formEmailTo'] ) && ! empty( $block_attrs['formEmailTo'] ) 
			? $block_attrs['formEmailTo'] 
			: get_bloginfo( 'admin_email' );
		$email_to = sanitize_email( $email_to );

		// Extract subject from block attributes.
		$subject = isset( $block_attrs['formEmailSubject'] ) && ! empty( $block_attrs['formEmailSubject'] )
			? $block_attrs['formEmailSubject']
			: '';
		$subject = sanitize_text_field( $subject );

		$table_content = '';

		foreach ( $form_data as $data ) {
			$labels         = sanitize_text_field( explode( ':', $data, 2 )[0] );
			$info           = sanitize_text_field( explode( ':', $data, 2 )[1] );
			$table_content .= '<tr><td><strong>' . $labels . ':</strong> ' . $info . '</td></tr>';
		}

		$email_content = '<div>
		<h3>Form submission from ' . $site_name . '
		</h3>
		<hr>
		<table>
		  <tbody>
			<tr>
			  <td>
				<strong>Form submission from:</strong>
				<a href="' . $page_url . '" target="_blank" >' . $page_url . '</a>
			  </td>
			</tr>' . $table_content . '
			</tbody>
			<tfoot>
				<tr>
				<td>
					<hr>You received this email because your email address is set in the content form settings on <a href="' . $site_url . '" target="_blank" >' . $site_name . '</a>
				</td>
				</tr>
			</tfoot>
			</table>
		</div>';

		$headers = array(
			'Content-Type: text/html; charset=UTF-8',
		);

		$sent = wp_mail( $email_to, $subject, $email_content, $headers );

		if ( $sent ) {
			$response = rest_ensure_response(
				array(
					'success' => true,
					'message' => 'Email sent successfully!',
				)
			);
		} else {
			$response = rest_ensure_response(
				array(
					'success' => false,
					'message' => 'Error sending email.',
				)
			);
		}

		return $response;
	}

	/**
	 * RBA Register Admin Menu.
	 *
	 * @param string $slug parent slug of submenu.
	 * @since 1.8.0
	 */
	public function rba_register_admin_menu( $slug ) {
		add_submenu_page(
			$slug,
			'Responsive Blocks',
			'Blocks',
			'manage_options',
			'responsive_block_editor_addons',
			array( $this, 'responsive_block_editor_addons_getting_started' ),
		);
	}

	/**
     * Add links to plugin's description in plugins table
     *
     * @param array  $links  Initial list of links.
     * @param string $file   Basename of current plugin.
     *
     * @return array
     */
    public function responsive_block_editor_addons_rate_plugin_link( $links, $file ) {
		if ( $file !== plugin_basename( RESPONSIVE_BLOCK_EDITOR_ADDONS_BASENAME ) ) {
			return $links;
		}
		
		$rate_url = 'https://wordpress.org/support/plugin/responsive-block-editor-addons/reviews/';
		$rate_link = '<a target="_blank" href="' . esc_url( $rate_url ) . '" title="' . esc_attr__( 'Rate the plugin', 'responsive-block-editor-addons' ) . '">' . esc_html__( 'Rate the plugin ★★★★★', 'responsive-block-editor-addons' ) . '</a>';
		$links[] = $rate_link;

		$docs_url  = esc_url( 'https://cyberchimps.com/docs/responsive-blocks/' );
		$docs_link = '<a target="_blank" href="' . esc_url( $docs_url ) . '" title="' . esc_attr__( 'Support', 'responsive-block-editor-addons' ) . '">' . esc_html__( 'Support', 'responsive-block-editor-addons' ) . '</a>';
		$links[] = $docs_link;

		return $links;
	}


	/**	 
	 * Function to ensure that the blocks from Responsive Blocks plugin are available in the block editor.
	 * 
	 * @param array $allowed_block_types The allowed block types.
	 * @param WP_Block_Editor_Context $editor_context The editor context.
	 * @return array The modified list of allowed block types.
	 * @since 2.0.7
	 */
	public function responsive_block_editor_addons_allow_blocks_in_editor( $allowed_block_types, $editor_context ) {
		if(is_plugin_active("ionos-essentials/ionos-essentials.php")){
			if ( ! $editor_context->post ) {
				return $allowed_block_types;
			}
		
			// If $allowed_block_types is false or not an array, reinitialize it.
			if ( ! is_array( $allowed_block_types ) ) {
				$allowed_block_types = array_keys( WP_Block_Type_Registry::get_instance()->get_all_registered() );
			}
		
			// Merge your blocks into the allowed list if not present
			foreach ( $this->responsive_block_editor_addons_blocks as $block ) {
				if ( ! in_array( $block, $allowed_block_types, true ) ) {
					$allowed_block_types[] = $block;
				}
			}
		
			return $allowed_block_types;
		}
		return $allowed_block_types;
		
	}

	/**
	 * Adds a "Settings" link to the plugin actions row on the Plugins page.
	 *
	 * This link redirects the user to the plugin's settings page in the WordPress admin.
	 *
	 * @param array $links Existing plugin action links.
	 * @return array Modified plugin action links with the "Settings" link prepended.
	 */
	public function responsive_block_editor_addons_settings_link( $links ) {
		$settings_link = '<a href="' . admin_url( 'admin.php?page=responsive_block_editor_addons' ) . '">' . __( 'Settings', 'responsive-block-editor-addons' ) . '</a>';
		array_unshift( $links, $settings_link );
		return $links;
	}

	/**
	 * Load Frontend Scripts.
	 */
	public function responsive_block_editor_addons_load_frontend_scripts() {

		$blocks = get_option( 'rbea_blocks' );

		$block_status_map = array_column( (array) $blocks, 'status', 'key' );

		if ( isset( $block_status_map['animations'] ) ) {
			$is_animations_toggled_on = $block_status_map['animations'];
		}

		if ( $is_animations_toggled_on && self::$is_animations_on ) {
			wp_enqueue_script(
				'responsive-block-editor-addons-frontend-scripts',
				RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/responsive-block-editor-addons-aos-initialized.js',
				array(),
				RESPONSIVE_BLOCK_EDITOR_ADDONS_VER,
				true
			);
		}

		// Enqueue inherit from theme frontend script
		wp_enqueue_script(
			'responsive-block-editor-addons-inherit-theme',
			RESPONSIVE_BLOCK_EDITOR_ADDONS_URL . 'dist/responsive-block-editor-addons-inherit-theme.js',
			array(),
			RESPONSIVE_BLOCK_EDITOR_ADDONS_VER,
			true
		);

		// Localize script with global inherit from theme settings
		$global_inherit_value = get_option( 'rbea_global_inherit_from_theme', '0' );
		$global_inherit_value = ( '1' === (string) $global_inherit_value || 1 === $global_inherit_value ) ? '1' : '0';
		wp_localize_script(
			'responsive-block-editor-addons-inherit-theme',
			'rbea_globals',
			array(
				'global_inherit_from_theme' => $global_inherit_value,
				'global_inherit_from_theme_last_changed' => get_option( 'rbea_global_inherit_from_theme_last_changed', '' ),
			)
		);

	}

	/**
	 * Manipulate the markup of block on frontend.
	 */
	public function responsive_block_editor_addons_render_block( $block_content, $block ) {

		$blocks = get_option( 'rbea_blocks' );

		$block_status_map = array_column( (array) $blocks, 'status', 'key' );

		if ( isset( $block_status_map['display-conditions'] ) ) {
			$is_display_conditions_toggled_on = $block_status_map['display-conditions'];
		}

		if ( $is_display_conditions_toggled_on && ! empty( $block['attrs']['RBEADisplayConditions'] ) ) {
			switch ( $block['attrs']['RBEADisplayConditions'] ) {
				case 'userstate':
					$block_content = $this->responsive_block_editor_addons_user_state_visibility( $block['attrs'], $block_content );
					break;

				case 'userrole':
					$block_content = $this->responsive_block_editor_addons_user_role_visibility( $block['attrs'], $block_content );
					break;

				case 'browser':
					$block_content = $this->responsive_block_editor_addons_browser_visibility( $block['attrs'], $block_content );
					break;

				case 'os':
					$block_content = $this->responsive_block_editor_addons_os_visibility( $block['attrs'], $block_content );
					break;

				case 'day':
					$block_content = $this->responsive_block_editor_addons_day_visibility( $block['attrs'], $block_content );
					break;

				default:
					// nothing for now.
					break;
			}
		}

		if ( isset( $block_status_map['animations'] ) ) {
			$is_animations_toggled_on = $block_status_map['animations'];
		}

		if ( $is_animations_toggled_on && ! empty( $block['attrs']['RBEAAnimationType'] ) ) {
			$attrs = $block['attrs'];
			$attrs['RBEAAnimationTime']   = isset( $attrs['RBEAAnimationTime'] ) ? $attrs['RBEAAnimationTime'] : 400;
			$attrs['RBEAAnimationDelay']  = isset( $attrs['RBEAAnimationDelay'] ) ? $attrs['RBEAAnimationDelay'] : 0;
			$attrs['RBEAAnimationEasing'] = isset( $attrs['RBEAAnimationEasing'] ) ? $attrs['RBEAAnimationEasing'] : 'ease';
			$attrs['RBEAAnimationRepeat'] = isset( $attrs['RBEAAnimationRepeat'] ) ? 'false' : 'true';
			
			$aos_attributes = '<div data-aos= "' . esc_attr( $attrs['RBEAAnimationType'] ) . '" data-aos-duration="' . esc_attr( $attrs['RBEAAnimationTime'] ) . '" data-aos-delay="' . esc_attr( $attrs['RBEAAnimationDelay'] ) . '" data-aos-easing="' . esc_attr( $attrs['RBEAAnimationEasing'] ) . '" data-aos-once="' . esc_attr( $attrs['RBEAAnimationRepeat'] ) . '" ';
			$block_content  = preg_replace( '/<div /', $aos_attributes, $block_content, 1 );
		}

		// Inject inherit from theme data attributes for old blocks that don't have them
		$block_content = $this->inject_inherit_from_theme_attributes( $block_content, $block );

		// Replace SVG placeholders with actual SVG markup
		$block_content = $this->render_svg_icons_dynamically( $block_content );

		return $block_content;
	}

	/**
	 * Inject inherit from theme data attributes for old blocks.
	 * 
	 * This ensures that blocks saved before the inherit-from-theme feature was added
	 * will still work correctly when the global inherit setting is enabled.
	 *
	 */
	public function inject_inherit_from_theme_attributes( $block_content, $block ) {
		// Skip if block content is empty or block doesn't already have data-rbea-inherit-wrapper
		if ( empty( $block_content ) || strpos( $block_content, 'data-rbea-inherit-wrapper' ) !== false ) {
			return $block_content;
		}

		// Define block-specific selectors for inject inherit from theme data attributes
		$inherit_blocks_config = array(
			'responsive-block-editor-addons/buttons-child' => array(
				'wrapper_class' => 'responsive-block-editor-addons-button__wrapper',
				'parent' => 'self',
				'child' => '.responsive-block-editor-addons-buttons-repeater',
			),
			'responsive-block-editor-addons/card' => array(
				'wrapper_class' => 'wp-block-responsive-block-editor-addons-card-item__button-wrapper',
				'parent' => 'self',
				'child' => '.responsive-block-editor-addons-card-button-inner a',
			),
			'responsive-block-editor-addons/call-mail-button' => array(
				'wrapper_class' => 'responsive-block-editor-addons-block-call-mail-button',
				'parent' => 'self',
				'child' => '.responsive-block-editor-addons-call-mail-button-button-container',
			),
			'responsive-block-editor-addons/popup' => array(
				'wrapper_class' => 'responsive-block-editor-addons-popup-trigger-wrap',
				'parent' => 'self',
				'child' => '.responsive-block-editor-addons-popup-button-trigger',
				'child_extra' => 'wp-block-button',
			),
			'responsive-block-editor-addons/responsive-block-editor-addons-cta' => array(
				'wrapper_class' => 'responsive-block-editor-addons-cta-button-wrapper',
				'parent' => 'self',
				'child' => 'a',
			),
			'responsive-block-editor-addons/pricing-table' => array(
				'wrapper_class' => 'wp-block-responsive-block-editor-addons-pricing-table-item__button-wrapper',
				'button_class' => 'wp-block-responsive-block-editor-addons-pricing-table-item__button',
				'parent' => 'self',
				'child' => 'a',
		),
		);

		// Check if this block supports inherit from theme
		if ( ! isset( $inherit_blocks_config[ $block['blockName'] ] ) ) {
			return $block_content;
		}

		$config = $inherit_blocks_config[ $block['blockName'] ];
		$attrs = $block['attrs'];

		// Get attribute values (with defaults for old blocks)
		$inherit_from_theme_saved = isset( $attrs['inheritFromThemesaved'] ) ? $attrs['inheritFromThemesaved'] : false;
		$local_timestamp = isset( $attrs['inheritFromThemeLocalTimestamp'] ) ? $attrs['inheritFromThemeLocalTimestamp'] : '';

		// Build data attributes string
		$data_attrs = sprintf(
			' data-rbea-inherit-wrapper="true" data-inherit-from-theme="%s" data-local-timestamp="%s" data-rbea-inherit-parent="%s" data-rbea-inherit-child="%s"',
			$inherit_from_theme_saved ? '1' : '0',
			esc_attr( $local_timestamp ),
			esc_attr( $config['parent'] ),
			esc_attr( $config['child'] )
		);

	// Add extra child class if defined (for popup block)
	if ( isset( $config['child_extra'] ) ) {
		$data_attrs .= sprintf( ' data-rbea-inherit-child-extra="%s"', esc_attr( $config['child_extra'] ) );
	}

	// Special handling for pricing table block
	// Old pricing table blocks don't have the button wrapper div, so we need to create it
	if ( $block['blockName'] === 'responsive-block-editor-addons/pricing-table' && 
	     strpos( $block_content, $config['wrapper_class'] ) === false ) {
		// Find all pricing table item buttons and wrap them
		$button_class = $config['button_class'];
		$wrapper_class = $config['wrapper_class'];
		
		// Pattern to match: <a class="...wp-block-responsive-block-editor-addons-pricing-table-item__button..." ...>...</a>
		$button_pattern = '/(<a\s+[^>]*class="[^"]*' . preg_quote( $button_class, '/' ) . '[^"]*"[^>]*>.*?<\/a>)/s';
		
		$block_content = preg_replace_callback( $button_pattern, function( $matches ) use ( $wrapper_class, $data_attrs ) {
			$button_html = $matches[1];
			// Wrap the button with the new wrapper div
			return sprintf( '<div class="%s"%s>%s</div>', $wrapper_class, $data_attrs, $button_html );
		}, $block_content );
		
		return $block_content;
	}

	// Inject attributes into the wrapper element
	// Look for the wrapper class and add attributes to that element
	$pattern = '/(<[^>]*class="[^"]*' . preg_quote( $config['wrapper_class'], '/' ) . '[^"]*"[^>]*)(>)/';
	$replacement = '$1' . $data_attrs . '$2';
	$block_content = preg_replace( $pattern, $replacement, $block_content, 1 );

	return $block_content;
}

	/**
	 *  Get the User Roles
	 *
	 *  @since 2.1.3
	 */
	public function responsive_block_editor_addons_get_user_roles() {

		global $wp_roles;

		$field_options = array();

		$role_lists = $wp_roles->get_names();

		$field_options[0] = array(
			'value' => '',
			'label' => __( 'None', 'responsive-block-editor-addons' ),
		);

		foreach ( $role_lists as $key => $role_list ) {
			$field_options[] = array(
				'value' => $key,
				'label' => $role_list,
			);
		}

		return $field_options;
	}

	/**
	 * User State Visibility.
	 *
	 * @param array $block_attributes The block data.
	 * @param mixed $block_content The block content.
	 *
	 * @since 2.1.3
	 * @return mixed Returns the new block content.
	 */
	public function responsive_block_editor_addons_user_state_visibility( $block_attributes, $block_content ) {
		if ( ! empty( $block_attributes['RBEALoggedIn'] ) && is_user_logged_in() ) {
			return '';
		}

		if ( ! empty( $block_attributes['RBEALoggedOut'] ) && ! is_user_logged_in() ) {
			return '';
		}

		return $block_content;
	}

	/**
	 * User Role Visibility.
	 *
	 * @param array $block_attributes The block data.
	 * @param mixed $block_content The block content.
	 *
	 * @since 2.1.3
	 * @return mixed Returns the new block content.
	 */
	public function responsive_block_editor_addons_user_role_visibility( $block_attributes, $block_content ) {
		if ( empty( $block_attributes['RBEARole'] ) ) {
			return $block_content;
		}

		$user = wp_get_current_user();
		return is_user_logged_in() && ! empty( $user->roles ) && in_array( $block_attributes['RBEARole'], $user->roles, true ) ? '' : $block_content;
	}

	/**
	 * Browser Visibility.
	 *
	 * @param array $block_attributes The block data.
	 * @param mixed $block_content The block content.
	 *
	 * @since 2.1.3
	 * @return mixed Returns the new block content.
	 */
	public function responsive_block_editor_addons_browser_visibility( $block_attributes, $block_content ) {

		if ( empty( $block_attributes['RBEABrowser'] ) ) {
			return $block_content;
		}
		$user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? Responsive_Block_Editor_Addons_Helper::get_instance()->rbea_get_browser_name( sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ) ) : '';

		return $block_attributes['RBEABrowser'] === $user_agent ? '' : $block_content;
	}

	/**
	 * Operating System Visibility.
	 *
	 * @param array $block_attributes The block data.
	 * @param mixed $block_content The block content.
	 * @since 2.1.3
	 * @return mixed Returns the new block content.
	 */
	public function responsive_block_editor_addons_os_visibility( $block_attributes, $block_content ) {

		if ( empty( $block_attributes['RBEASystem'] ) ) {
			return $block_content;
		}

		$os = array(
			'iphone'   => '(iPhone)',
			'android'  => '(Android)',
			'windows'  => 'Win16|(Windows 95)|(Win95)|(Windows_95)|(Windows 98)|(Win98)|(Windows NT 5.0)|(Windows 2000)|(Windows NT 5.1)|(Windows XP)|(Windows NT 5.2)|(Windows NT 6.0)|(Windows Vista)|(Windows NT 6.1)|(Windows 7)|(Windows NT 4.0)|(WinNT4.0)|(WinNT)|(Windows NT)|Windows ME',
			'open_bsd' => 'OpenBSD',
			'sun_os'   => 'SunOS',
			'linux'    => '\bLinux\b(?!.*\bAndroid\b)', // Linux but NOT Android.
			'mac_os'   => '(Mac_PowerPC|Macintosh|Mac OS|MacOS)',
		);

		$user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ) : '';

		return isset( $os[ $block_attributes['RBEASystem'] ] ) && preg_match( '@' . $os[ $block_attributes['RBEASystem'] ] . '@', $user_agent ) ? '' : $block_content;
	}

	/**
	 * Day Visibility.
	 *
	 * @param array $block_attributes The block data.
	 * @param mixed $block_content The block content.
	 *
	 * @since 2.1.3
	 * @return mixed Returns the new block content.
	 */
	public function responsive_block_editor_addons_day_visibility( $block_attributes, $block_content ) {

		// If not set restriction.
		if ( empty( $block_attributes['RBEADay'] ) ) {
			return $block_content;
		}

		$current_day = strtolower( current_datetime()->format( 'l' ) );
		// Check in restricted day.
		return ! in_array( $current_day, $block_attributes['RBEADay'] ) ? $block_content : '';

	}

	/**
	 * Render SVG icons dynamically from placeholders.
	 *
	 * Replaces placeholder spans with actual SVG markup on the frontend.
	 *
	 * @param string $block_content The block content.
	 * @return string Modified block content with SVGs rendered.
	 */
	public function render_svg_icons_dynamically( $block_content ) {
		if ( empty( $block_content ) ) {
			return $block_content;
		}

		// Pattern to match placeholder spans with rbea-dynamic-icon class (including closing tag)
		$pattern = '/<span\s+([^>]*\s+)?class=["\']([^"\']*\s+)?rbea-dynamic-icon([^"\']*)?["\']([^>]*)?>\s*<\/span>/i';

		$replaced_content = preg_replace_callback(
			$pattern,
			function( $matches ) {
				// Extract the full span tag (opening tag only for attribute extraction)
				$full_match = $matches[0];
				$opening_tag = $matches[0];
				if ( preg_match( '/<span[^>]*>/', $full_match, $tag_match ) ) {
					$opening_tag = $tag_match[0];
				}

				// Extract data-icon attribute
				if ( preg_match( '/data-icon=["\']([^"\']+)["\']/', $opening_tag, $icon_matches ) ) {
					$icon_name = $icon_matches[1];

					// Render SVG using the renderer class
					$svg = Responsive_Block_Editor_Addons_SVG_Renderer::render( $icon_name );

					if ( ! empty( $svg ) ) {
						// Wrap SVG in span with original classes preserved
						$wrapper_classes = 'rbea-svg-icon-wrap';
						if ( preg_match( '/class=["\']([^"\']+)["\']/', $opening_tag, $class_matches ) ) {
							$original_classes = $class_matches[1];
							$wrapper_classes = $original_classes . ' rbea-svg-icon-wrap';
						}

						return '<span class="' . esc_attr( $wrapper_classes ) . '">' . $svg . '</span>';
					}
				}

				// Return original if no icon found
				return $full_match;
			},
			$block_content
		);

		return is_null( $replaced_content ) ? $block_content : $replaced_content;
	}

	/**
	 * Fix malformed CSS variables caused by Unicode dash encoding during block serialization.
	 */
	public function responsive_block_editor_addons_fix_css_vars( $content ) {

		// Fix broken unicode dash in CSS vars.
		$content = preg_replace(
			'/var\(\\\\?u002d\\\\?u002dresponsive/',
			'var(--responsive',
			$content
		);

		return $content;

	}
}
