<?php

use PublishPress\Blocks\Utilities;

defined('ABSPATH') || die;

require_once plugin_dir_path(dirname(__FILE__)) . 'incl/rest-api/presets.php';
require_once plugin_dir_path(dirname(__FILE__)) . 'incl/block-styles/block-styles.php';
require_once plugin_dir_path(dirname(__FILE__)) . 'incl/auto-insert-blocks/class-auto-insert-blocks.php';
require_once plugin_dir_path(dirname(__FILE__)) . 'incl/auto-insert-blocks/class-auto-insert-metaboxes.php';

/**
 * Main class of Gutenberg Advanced
 */
if (! class_exists('AdvancedGutenbergMain')) {
    class AdvancedGutenbergMain
    {
        /**
         * Default role access
         *
         * @var array   Array of default role access
         */
        public static $default_roles_access = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' );

        /**
         * Default active all blocks
         *
         * @var string  All blocks
         */
        public static $default_active_blocks = 'all';
        /**
         * Store original editor settings value, before we modify it to allow/hide blocks based on user roles
         *
         * @var string Original settings
         */
        protected static $original_block_editor_settings;

        /**
         * AdvancedGutenbergMain constructor.
         */
        public function __construct()
        {
            global $wp_version;

            add_action('init', array( $this, 'registerPostMeta' ));
            add_action('admin_init', array($this, 'addCustomStylesToReusableBlocks'));
            add_action('admin_init', array( $this, 'registerStylesScripts' ));
            add_action('wp_loaded', [ 'PublishPress\Blocks\Controls', 'addAttributes' ], 999);
            add_filter('rest_pre_dispatch', [ 'PublishPress\Blocks\Controls', 'removeAttributes' ], 10, 3);
            add_action('wp_enqueue_scripts', array( $this, 'registerStylesScriptsFrontend' ));
            add_action('enqueue_block_assets', array( $this, 'addEditorAndFrontendStyles' ), 9999);
            add_action('plugins_loaded', array( $this, 'advgbBlockLoader' ), 10);
            add_action('rest_api_init', array( $this, 'registerRestAPI' ));
            add_action(
                'admin_print_scripts',
                array( $this, 'disableAllAdminNotices' )
            ); // Disable all admin notice for page belong to plugin
            add_action('wp_login_failed', array( $this, 'handleLoginFailed' ));
            add_filter('safe_style_css', array( $this, 'addAllowedInlineStyles' ), 10, 1);
            add_filter('wp_kses_allowed_html', array( $this, 'addAllowedTags' ), 1);
            add_filter('all_plugins', array( $this, 'addFreeLabel' ));

            // Front-end ajax
            add_action('wp_ajax_advgb_contact_form_save', array( $this, 'saveContactFormData' ));
            add_action('wp_ajax_nopriv_advgb_contact_form_save', array( $this, 'saveContactFormData' ));
            add_action('wp_ajax_advgb_newsletter_save', array( $this, 'saveNewsletterData' ));
            add_action('wp_ajax_nopriv_advgb_newsletter_save', array( $this, 'saveNewsletterData' ));
            add_action('wp_ajax_advgb_lores_validate', array( $this, 'validateLoresForm' ));
            add_action('wp_ajax_nopriv_advgb_lores_validate', array( $this, 'validateLoresForm' ));

            if (is_admin()) {

                add_action('admin_footer', array( $this, 'initBlocksList' ));
                add_action('admin_menu', array( $this, 'registerMainMenu' ));
                add_action('admin_menu', array( $this, 'registerBlockConfigPage' ));
                add_action('plugins_loaded', [ $this, 'upgradeProNotices' ], 10);
                add_action('enqueue_block_editor_assets', array( $this, 'addEditorAssets' ), 9999);
                add_filter('mce_external_plugins', array( $this, 'addTinyMceExternal' ));
                add_filter('mce_buttons_2', array( $this, 'addTinyMceButtons' ));
                add_filter('admin_body_class', array( $this, 'setAdvgEditorBodyClassses' ));
                add_filter('admin_footer_text', [ $this, 'adminFooter' ]);
                add_action('admin_enqueue_scripts', [ $this, 'adminMenuStyles' ]);
                add_action('activated_plugin', [ $this, 'maybeNewBlocks' ], 9999, 2);
                add_filter('plugin_row_meta', [$this, 'addPluginActionLinks'], 10, 2);

                if ($wp_version >= 5.8) {
                    add_action('admin_enqueue_scripts', array( $this, 'addEditorAssetsWidgets' ), 9999);
                    add_filter('block_editor_settings_all', array( $this, 'replaceEditorSettings' ), 9999);

                    if (Utilities::settingIsEnabled('enable_advgb_blocks')) {
                        add_filter('block_categories_all', array( $this, 'addAdvBlocksCategory' ));
                    }
                } else {
                    add_filter('block_editor_settings', array( $this, 'replaceEditorSettings' ), 9999);

                    if (Utilities::settingIsEnabled('enable_advgb_blocks')) {
                        add_filter('block_categories', array( $this, 'addAdvBlocksCategory' ));
                    }
                }

                if ($wp_version >= 5.9) {
                    add_action('admin_init', array( $this, 'addEditorAssetsSiteEditor' ));
                }

                // Ajax
                add_action('wp_ajax_advgb_update_blocks_list', array( $this, 'updateBlocksList' ));
                add_action('wp_ajax_advgb_block_config_save', array( $this, 'saveBlockConfig' ));
                add_action('wp_ajax_advgb_feature_save', [ $this, 'saveFeature' ]);
                add_action('wp_ajax_pp_blocks-usage_scan_batch', [ $this, 'scan_block_usage' ]);
            } else {
                // Front-end
                add_filter('render_block_data', array( $this, 'contentPreRender' ));
                add_filter('render_block', array( $this, 'addNonceToFormBlocks' ));
                add_filter('render_block', [ 'PublishPress\Blocks\Controls', 'checkBlockControls' ], 10, 2);
                add_filter('widget_display_callback', [ 'PublishPress\Blocks\Controls', 'checkBlockControlsWidget' ]);
                add_filter('the_content', array( $this, 'addFrontendContentAssets' ), 9);

                if ($wp_version >= 5.8) {
                    add_filter('widget_block_content', array( $this, 'addFrontendWidgetAssets' ), 9);
                }
            }

            add_filter('register_post_type_args', [$this, 'filterWpBlockPostTypeArgs'], 10, 2);
            add_filter('register_taxonomy_args', [$this, 'filterWpBlockCategoryArgs'], 10, 3);

            if ( Utilities::settingIsEnabled( 'enable_custom_styles' ) ) {
                new AdvancedGutenbergBlockStyles();
            }

            if ( Utilities::settingIsEnabled( 'auto_insert_blocks' ) ) {
                new AdvancedGutenbergAutoInsertBlocks();
                new AdvancedGutenbergAutoInsertMetaboxes();
            }
        }

        /**
         * Disable all admin notices in our page
         *
         * @return void
         */
        public function disableAllAdminNotices()
        {
            global $wp_filter;
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- No action, nonce is not required
            if (( ! empty($_GET['page']) && in_array($_GET['page'], array( 'advgb_main' )) )) {
                if (is_user_admin()) {
                    if (isset($wp_filter['user_admin_notices'])) {
                        unset($wp_filter['user_admin_notices']);
                    }
                } elseif (isset($wp_filter['admin_notices'])) {
                    unset($wp_filter['admin_notices']);
                }
                if (isset($wp_filter['all_admin_notices'])) {
                    unset($wp_filter['all_admin_notices']);
                }
            }
        }

        /**
         * Add blocks category
         *
         * @param array $categories List of current blocks categories
         *
         * @return array New array include our category
         */
        public function addAdvBlocksCategory($categories)
        {
            return in_array(
                'advgb-category',
                wp_list_pluck($categories, 'slug'),
                true
            ) ? $categories : array_merge(
                array(
                    array(
                        'slug'  => 'advgb-category',
                        'title' => __('PublishPress Blocks', 'advanced-gutenberg'),
                    ),
                ),
                $categories
            );
        }

        /**
         * Add inline styles allowed for user without unfiltered_html capability
         *
         * @param array $styles List of current allowed styles
         *
         * @return array New list of allowed styles
         */
        public function addAllowedInlineStyles($styles)
        {
            return array_merge(
                $styles,
                array( 'justify-content', 'align-items', 'border-radius' )
            );
        }

        /**
         * Add allowed tags for user without unfiltered_html capability
         *
         * @param array $tags List of current allowed tags
         *
         * @return array New list of allowed tags
         */
        public function addAllowedTags($tags)
        {
            $tags['svg']  = array(
                'width'               => true,
                'height'              => true,
                'viewbox'             => true,
                'xmlns'               => true,
                'fill'                => true,
                'styles'              => true,
                'preserveAspectRatio' => true,
            );
            $tags['g']    = array(
                'fill'         => true,
                'fill-rule'    => true,
                'fill-opacity' => true,
                'stroke'       => true,
                'stroke-width' => true,
            );
            $tags['path'] = array(
                'd'            => true,
                'fill'         => true,
                'fill-opacity' => true,
            );

            return $tags;
        }

        /**
         * Add "Free" label to plugin name in the Plugins list page only
         *
         * @param array $plugins List of plugins
         *
         * @return array
         */
        public function addFreeLabel($plugins)
        {
            global $pagenow;

            if (!is_admin() || 'plugins.php' !== $pagenow) {
                return $plugins;
            }

            $plugin_file = plugin_basename(ADVANCED_GUTENBERG_PLUGIN);

            if (isset($plugins[$plugin_file]['Name'])) {
                $plugins[$plugin_file]['Name'] = 'PublishPress Blocks Free';
            }

            return $plugins;
        }

        /**
         * Replaces if needed editor settings to allow/hide blocks
         *
         * @param array $settings Editor settings
         *
         * @return array
         */
        public function replaceEditorSettings($settings)
        {
            self::$original_block_editor_settings = $settings;

            $advgb_blocks_vars = array();

            if (Utilities::settingIsEnabled('enable_block_access')) {
                $getUserRoleBlocksData = $this->getUserRoleBlocksData();

                $advgb_blocks_vars['blocks'] = $getUserRoleBlocksData['blocks'];
            }

            // No Block Access defined for this role, so we define empty arrays
            if (! isset($advgb_blocks_vars['blocks']['active_blocks']) && empty($advgb_blocks_vars['blocks']['active_blocks'])) {
                $advgb_blocks_vars['blocks']['active_blocks']   = array();
                $advgb_blocks_vars['blocks']['inactive_blocks'] = array();
            }

            if (is_array($settings['allowedBlockTypes'])) {
                // Remove blocks from the list that are not allowed
                // Note that we do not add missing blocks, because another plugin may have used the hook to remove some of them
                foreach ($settings['allowedBlockTypes'] as $key => $type) {
                    if (in_array($type, $advgb_blocks_vars['blocks']['inactive_blocks'])) {
                        unset($settings['allowedBlockTypes'][ $key ]);
                    }
                }
            } elseif ($settings['allowedBlockTypes'] === true) {
                // All was allowed, only return what the block access by user role allows

                if (count($advgb_blocks_vars['blocks']['active_blocks']) || count($advgb_blocks_vars['blocks']['inactive_blocks'])) {
                    $settings['allowedBlockTypes'] = $advgb_blocks_vars['blocks']['active_blocks'];
                }
            }

            $current_screen = get_current_screen();
            if (
                method_exists($current_screen, 'is_block_editor') && $current_screen->is_block_editor()
                 && ( ! defined('GUTENBERG_VERSION') || ( defined('GUTENBERG_VERSION') && version_compare(
                     GUTENBERG_VERSION,
                     '5.3.0',
                     '>='
                 ) ) )
            ) {
                // WP 5 and Gutenberg 5.3.0 fires enqueue_block_editor_assets before block_editor_settings, Gutenberg plugin do the contrary
                // Gutenberg WP5 core feature is used and we are in the block editor page, we must enqueue our assets after retrieving editor settings
                $this->addEditorAssets(true);
            }

            return $settings;
        }

        /**
         * Enqueue styles and scripts for gutenberg
         *
         * @param boolean $force_loading Should force loading assets
         *
         * @return void
         */
        public function addEditorAssets($force_loading = false)
        {
            $current_screen = get_current_screen();
            if (
                ! $force_loading && method_exists(
                    $current_screen,
                    'is_block_editor'
                ) && $current_screen->is_block_editor()
                 && ( ! defined('GUTENBERG_VERSION') || ( defined('GUTENBERG_VERSION') && version_compare(
                     GUTENBERG_VERSION,
                     '5.3.0',
                     '>='
                 ) ) )
            ) {
                // This function will be called manually in the block_editor_settings filter
                // WP 5 and Gutenberg 5.3.0 fires enqueue_block_editor_assets before block_editor_settings, Gutenberg plugin do the contrary
                return;
            }

            $this->enqueueEditorAssets();
            $this->advgbBlocksVariables();
        }

        /**
         * Add styles for Site Editor
         * Note: these assets loads inline inside the Site Editor iframe
         *
         * @return void
         */
        public function addEditorAssetsSiteEditor()
        {
            global $pagenow;

            if (Utilities::settingIsEnabled('enable_advgb_blocks') && $pagenow === 'site-editor.php') {
                add_editor_style(site_url('/wp-includes/css/dashicons.css')); // 'dashicons'
                add_editor_style(ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/blocks.css');
                add_editor_style(ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/columns-editor.css');
                add_editor_style(ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/recent-posts.css');
                add_editor_style(ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/editor.css');
                add_editor_style(ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/site-editor.css');
                add_editor_style(ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/fonts/material-icons.min.css');
                add_editor_style(ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/fonts/material-icons-custom.min.css');
                add_editor_style(ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/slick.css');
                add_editor_style(ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/slick-theme.css');

                // Pro
                if (defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                    if (
                        method_exists(
                            'PPB_AdvancedGutenbergPro\Utils\Definitions',
                            'advgb_pro_enqueue_main_styles_inline'
                        )
                    ) {
                        PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_enqueue_main_styles_inline();
                    }
                }

                $this->advgbDisableBlocks();
            }
        }

        /**
         * Enqueue styles and scripts for gutenberg in widgets.php
         *
         * @param int $hook Hook suffix for the current admin page
         *
         * @return void
         */
        public function addEditorAssetsWidgets($hook)
        {
            if ('widgets.php' != $hook) {
                return;
            }

            $this->enqueueEditorAssets();
            $this->advgbBlocksVariables(false);
            $this->advgbDisableBlocks();
        }

        /**
         * Enqueue styles and scripts for gutenberg
         *
         * @return void
         */
        public function enqueueEditorAssets()
        {
            $currentScreen = get_current_screen();

            if (
                Utilities::settingIsEnabled('enable_advgb_blocks')
                 || Utilities::settingIsEnabled('enable_block_access')
                 || Utilities::settingIsEnabled('block_controls')
            ) {
                // Define the dependency for the editor based on current screen
                if ($currentScreen->id === 'customize') {
                    // Customizer > Widgets
                    $wp_editor_dep = 'wp-customize-widgets';
                } elseif ($currentScreen->id === 'widgets') {
                    // Appearance > Widgets
                    $wp_editor_dep = 'wp-edit-widgets';
                } else {
                    // Post edit and Site Editor
                    $wp_editor_dep = 'wp-editor';
                }

                PublishPress\Blocks\Controls::editorAssets($wp_editor_dep);

                if (Utilities::settingIsEnabled('enable_advgb_blocks')) {
                    wp_enqueue_script(
                        'advgb_blocks',
                        ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/blocks.js',
                        array(
                            'lodash',
                            'wp-blocks',
                            'wp-i18n',
                            'wp-element',
                            'wp-data',
                            $wp_editor_dep,
                            'wp-plugins',
                            'wp-compose'
                        ),
                        ADVANCED_GUTENBERG_VERSION,
                        true
                    );

                    wp_set_script_translations(
                        'advgb_blocks',
                        'advanced-gutenberg',
                        plugin_dir_path(ADVANCED_GUTENBERG_PLUGIN) . 'languages'
                    );

                    // Pro Ads in some blocks for free version
                    if (! defined('ADVANCED_GUTENBERG_PRO_LOADED')) {

                        Utilities::enqueueToolTipsAssets();

                        wp_enqueue_script(
                            'advgb_pro_ad_js',
                            ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/pro-ad.js',
                            [ 'advgb_blocks' ],
                            ADVANCED_GUTENBERG_VERSION,
                            true
                        );
                        wp_enqueue_style(
                            'advgb_pro_ad_css',
                            ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/pro-ad.css',
                            [],
                            ADVANCED_GUTENBERG_VERSION
                        );
                        wp_localize_script(
                            'advgb_pro_ad_js',
                            'advgbProAdI18n',
                            [
                                'promoLink' => ADVANCED_GUTENBERG_UPGRADE_LINK,
                                'upgradeText'   => __( 'Upgrade to Pro', 'advanced-gutenberg' ),
                                'proText'   => __( 'Pro', 'advanced-gutenberg' )
                            ]
                        );

                        wp_set_script_translations(
                            'advgb_pro_ad_js',
                            'advanced-gutenberg',
                            plugin_dir_path(ADVANCED_GUTENBERG_PLUGIN) . 'languages'
                        );
                    }
                }

                if (Utilities::settingIsEnabled('enable_block_access')) {
                    wp_enqueue_script(
                        'advgb_blocks_editor',
                        ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/editor.js',
                        array(
                            'wp-blocks',
                            'wp-i18n',
                            'wp-element',
                            'wp-data',
                            $wp_editor_dep,
                            'wp-plugins',
                            'wp-compose'
                        ),
                        ADVANCED_GUTENBERG_VERSION,
                        true
                    );
                }
            }

            // Don't load custom-styles.js in widgets.php, Theme Customizer > Widgets and Site Editor
            if (
                Utilities::settingIsEnabled('enable_custom_styles')
                && $currentScreen->id !== 'widgets'
                && is_customize_preview() === false
                && $currentScreen->id !== 'site-editor'
            ) {
                wp_enqueue_script(
                    'advgb_custom_styles_script',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/custom-styles.js',
                    array( 'wp-blocks' ),
                    ADVANCED_GUTENBERG_VERSION,
                    true
                );
                $custom_styles_data   = get_option('advgb_custom_styles', AdvancedGutenbergBlockStyles::$default_custom_styles);
                wp_localize_script('advgb_custom_styles_script', 'advgbBlocksCustomStyles', array(
                    'customStyles' => ! $custom_styles_data ? array() : $custom_styles_data,
                ));
            }

            // Only load post-sidebar.js in post type 'post' and 'page'
            if (
                $currentScreen->base === 'post'
                 && ( $currentScreen->id == 'post' || $currentScreen->id == 'page' )
            ) {
                // Get global settings
                $saved_settings = get_option('advgb_settings');

                // Get post settings
                $editorWidthGlobal  = isset($saved_settings['editor_width'])
                    && ! empty($saved_settings['editor_width'])
                    ? $this->getAdvgbEditorWidth($saved_settings['editor_width'])
                    : 'default';
                $editorColsVGGlobal = $this->colsVisualGuideGlobal();

                // Settings as javascript variables
                wp_localize_script(
                    'wp-blocks',
                    'advg_settings',
                    [
                        'editor_width_global'                => $editorWidthGlobal,
                        'enable_columns_visual_guide_global' => $editorColsVGGlobal,
                    ]
                );

                wp_enqueue_script(
                    'advgb_post_sidebar',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/post-sidebar.js',
                    array( 'wp-blocks' ),
                    ADVANCED_GUTENBERG_VERSION,
                    true
                );
            }

            // Pro
            if (defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                if (
                    method_exists(
                        'PPB_AdvancedGutenbergPro\Utils\Definitions',
                        'advgb_pro_enqueue_scripts_editor'
                    )
                ) {
                    PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_enqueue_scripts_editor();
                }

                if (
                    method_exists(
                        'PPB_AdvancedGutenbergPro\Utils\Definitions',
                        'advgb_pro_enqueue_scripts_editor_conditional'
                    )
                ) {
                    PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_enqueue_scripts_editor_conditional();
                }
            }

            // Include needed JS libraries
            wp_enqueue_script('jquery-ui-tabs');
            wp_enqueue_script('jquery-ui-sortable');
            wp_enqueue_script('slick_js');
            wp_enqueue_script('advgb_masonry_js');

            // Include needed CSS styles
            wp_enqueue_style('material_icon_font');
            wp_enqueue_style('material_icon_font_custom');
            wp_enqueue_style('slick_style');
            wp_enqueue_style('slick_theme_style');
        }

        /**
         * Output blocks data and settings as javascript objects (advgb_blocks_var, advgbBlocks and advgbDefaultConfig)
         *
         * @param boolean $post When the blocks load in post edit screen
         *
         * @return void
         */
        public function advgbBlocksVariables($post = true)
        {
            $advgb_blocks_vars = array();

            $getUserRoleBlocksData = $this->getUserRoleBlocksData();

            $advgb_blocks_vars['user_block_features'] = $getUserRoleBlocksData['user_block_features'];

            if (Utilities::settingIsEnabled('enable_block_access')) {
                $advgb_blocks_vars['blocks'] = $getUserRoleBlocksData['blocks'];
            }

            // No Block Access defined for this role, so we define empty arrays
            if (! isset($advgb_blocks_vars['blocks']['active_blocks']) && empty($advgb_blocks_vars['blocks']['active_blocks'])) {
                $advgb_blocks_vars['blocks']['active_blocks']   = array();
                $advgb_blocks_vars['blocks']['inactive_blocks'] = array();
            }

            global $post;
            if ($post) {
                $advgb_blocks_vars['post_id']   = $post->ID;
                $advgb_blocks_vars['post_type'] = $post->post_type;
            }

            $advgb_blocks_vars['original_settings'] = self::$original_block_editor_settings;
            $advgb_blocks_vars['ajaxurl']           = admin_url('admin-ajax.php');
            $advgb_blocks_vars['nonce']             = wp_create_nonce('advgb_update_blocks_list');
            wp_localize_script('wp-blocks', 'advgb_blocks_vars', $advgb_blocks_vars);

            // Set variable needed by blocks editor
            $avatarHolder         = ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/testimonial/avatar-placeholder.png';
            $default_thumb        = ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/recent-posts/recent-post-default.png';
            $image_holder         = ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/advimage/imageholder.svg';
            $login_logo           = ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/login-form/login.svg';
            $reg_logo             = ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/login-form/reg.svg';
            $saved_settings       = get_option('advgb_settings');
            $custom_styles_data   = Utilities::settingIsEnabled('enable_custom_styles') ? get_option('advgb_custom_styles', AdvancedGutenbergBlockStyles::$default_custom_styles) : [];
            $recaptcha_config     = get_option('advgb_recaptcha_config');
            $recaptcha_config     = $recaptcha_config !== false ? $recaptcha_config : array( 'recaptcha_enable' => 0 );
            $blocks_icon_color    = isset($saved_settings['blocks_icon_color']) ? $saved_settings['blocks_icon_color'] : '#655997';
            $rp_default_thumb     = isset($saved_settings['rp_default_thumb']) ? $saved_settings['rp_default_thumb'] : array(
                'url' => $default_thumb,
                'id'  => 0
            );
            $icons                = array();
            $icons['material']    = file_get_contents(plugin_dir_path(__DIR__) . 'assets/css/fonts/codepoints.json');
            $icons['material']    = json_decode($icons['material'], true);
            $enable_advgb_blocks  = ! isset($saved_settings['enable_advgb_blocks']) || $saved_settings['enable_advgb_blocks'] ? 1 : 0;
            $pp_series_active     = is_plugin_active('organize-series/orgSeries.php') || is_plugin_active('publishpress-series-pro/publishpress-series-pro.php') ? 1 : 0;
            $pp_series_options    = get_option('org_series_options');
            $pp_series_slug       = isset($pp_series_options['series_taxonomy_slug']) && ! empty($pp_series_options['series_taxonomy_slug']) ? $pp_series_options['series_taxonomy_slug'] : 'series';
            $pp_series_post_types = isset($pp_series_options['post_types_for_series']) && ! empty($pp_series_options['post_types_for_series']) ? $pp_series_options['post_types_for_series'] : [ 'post' ];
            $block_controls       = Utilities::settingIsEnabled('block_controls') ? 1 : 0;
            $block_extend         = 1;
            $timezone             = function_exists('wp_timezone_string') ? wp_timezone_string() : 'UTC';
            $timezones            = [];
            $reusable_blocks      = Utilities::settingIsEnabled('reusable_blocks') ? 1 : 0;
            global $wp_version;
            $blocks_widget_support = ( $wp_version >= 5.8 ) ? 1 : 0;

            // Pro
            if (defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                if (method_exists('PPB_AdvancedGutenbergPro\Utils\Definitions', 'advgb_pro_timezones_list')) {
                    $timezones = PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_timezones_list();
                }
            }

            wp_localize_script('wp-blocks', 'advgbBlocks', array(
                'color'                 => $blocks_icon_color,
                'post_thumb'            => $rp_default_thumb['url'],
                'default_thumb'         => $default_thumb,
                'image_holder'          => $image_holder,
                'avatarHolder'          => $avatarHolder,
                'login_logo'            => $login_logo,
                'reg_logo'              => $reg_logo,
                'home_url'              => home_url(),
                'config_url'            => admin_url('admin.php?page=advgb_settings'),
                'customStyles'          => ! $custom_styles_data ? array() : $custom_styles_data,
                'captchaEnabled'        => $recaptcha_config['recaptcha_enable'],
                'pluginUrl'             => ADVANCED_GUTENBERG_PLUGIN_DIR_URL,
                'iconList'              => $icons,
                'registerEnabled'       => get_option('users_can_register'),
                'blocks_widget_support' => $blocks_widget_support,
                'enable_advgb_blocks'   => $enable_advgb_blocks,
                'advgb_pro'             => defined('ADVANCED_GUTENBERG_PRO_LOADED') ? 1 : 0,
                'pp_series_active'      => $pp_series_active,
                'pp_series_slug'        => $pp_series_slug,
                'pp_series_post_types'  => $pp_series_post_types,
                'block_controls'        => $block_controls,
                'reusable_blocks'       => $reusable_blocks,
                'block_extend'          => $block_extend,
                'timezone'              => $timezone,
                'timezones'             => $timezones
            ));

            // Setup default config data for blocks
            $blocks_config_saved = get_option('advgb_blocks_default_config');
            $blocks_config_saved = $blocks_config_saved !== false ? $blocks_config_saved : array();
            wp_localize_script('wp-blocks', 'advgbDefaultConfig', $blocks_config_saved);

            // Block controls
            if (Utilities::settingIsEnabled('block_controls')) {
                PublishPress\Blocks\Controls::editorData();
            }

            // Pro
            if (defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                if (method_exists('PPB_AdvancedGutenbergPro\Utils\Definitions', 'advgb_pro_fonts_list')) {
                    PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_fonts_list();
                }
            }
        }

        /**
         * Enqueue styles for gutenberg editor and front-end
         *
         * @return mixed
         */
        public function addEditorAndFrontendStyles()
        {
            // Load custom styles in the <head>
            if (Utilities::settingIsEnabled('enable_custom_styles')) {
                add_action('wp_head', array( $this, 'loadCustomStylesFrontend' ));
                add_action('admin_head', array( $this, 'loadCustomStylesAdmin' ));
            }

            add_action('admin_head', array( $this, 'setBlocksSpacingAdmin' ));

            global $pagenow;

            if (
                is_admin()
                 && Utilities::settingIsEnabled('enable_advgb_blocks')
                 && $pagenow !== 'site-editor.php'
            ) {
                wp_enqueue_style('dashicons');
                wp_enqueue_style(
                    'advgb_recent_posts_styles',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/recent-posts.css',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
            }

            if (is_admin() && Utilities::settingIsEnabled('enable_advgb_blocks')) {
                wp_enqueue_style(
                    'advgb_blocks_styles',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/blocks.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );

                wp_enqueue_style(
                    'advgb_columns_editor_styles',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/columns-editor.css',
                    [ 'advgb_blocks_styles' ],
                    ADVANCED_GUTENBERG_VERSION
                );

                // Pro
                if (defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                    if (
                        method_exists(
                            'PPB_AdvancedGutenbergPro\Utils\Definitions',
                            'advgb_pro_enqueue_main_styles'
                        )
                    ) {
                        PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_enqueue_main_styles();
                    }
                }
            }

            if (is_admin()) {
                wp_enqueue_style(
                    'advgb_editor_styles',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/editor.css',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
            }

            if (! function_exists('advgbAddScriptAttributes')) {
                /**
                 * Add attributes to script tag
                 *
                 * @param string $tag Script tag
                 * @param string $handle Handle name
                 *
                 * @return mixed
                 */
                function advgbAddScriptAttributes($tag, $handle)
                {
                    if ('advgb_map_api' === $handle) {
                        return str_replace(' src', ' defer src', $tag);
                    } elseif ('advgb_recaptcha_js' === $handle) {
                        return str_replace(' src', ' async defer src', $tag);
                    }

                    return $tag;
                }
            }
            add_filter('script_loader_tag', 'advgbAddScriptAttributes', 10, 2);

            if (is_admin()) {
                $this->loadGoogleMapApi();
                $this->loadRecaptchaApi();
            }
        }

        /**
         * Update the blocks list for first time install or when a new block is installed
         *
         * @TODO - Blocks with block.json metadata are not detected in this trigger
         * https://github.com/publishpress/PublishPress-Blocks/issues/1266
         *
         * @return void
         */
        public function initBlocksList()
        {
            if (
                get_option('advgb_blocks_list') === false
                 || (bool) get_option('advgb_maybe_new_blocks')
                 || ( defined('GUTENBERG_VERSION') && version_compare(
                     get_option('advgb_gutenberg_version'),
                     GUTENBERG_VERSION,
                     '<'
                 ) )
            ) {
                $advgb_nonce = wp_create_nonce('advgb_update_blocks_list');
                wp_enqueue_script('wp-blocks');
                wp_enqueue_script('wp-element');
                wp_enqueue_script('wp-data');
                wp_enqueue_script('wp-components');
                wp_enqueue_script('wp-block-library');
                wp_enqueue_script('wp-editor');
                do_action('enqueue_block_editor_assets');
                wp_enqueue_script(
                    'advgb_update_list',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/update-block-list.js',
                    array( 'jquery' ),
                    ADVANCED_GUTENBERG_VERSION
                );

                $blockCategories = array();
                if (function_exists('gutenberg_get_block_categories')) {
                    $blockCategories = gutenberg_get_block_categories(get_post());
                } elseif (function_exists('get_block_categories')) {
                    $blockCategories = get_block_categories(get_post());
                }

                wp_add_inline_script(
                    'wp-blocks',
                    sprintf('wp.blocks.setCategories( %s );', wp_json_encode($blockCategories)),
                    'after'
                );

                // Block types scripts
                $block_type_registry = \WP_Block_Type_Registry::get_instance();
                foreach ($block_type_registry->get_all_registered() as $block_name => $block_type) {
                    if (! empty($block_type->editor_script)) {
                        wp_enqueue_script($block_type->editor_script);
                    }
                }

                wp_localize_script('advgb_update_list', 'updateListNonce', array( 'nonce' => $advgb_nonce ));

                // Disable trigger
                update_option('advgb_maybe_new_blocks', intval(false), false);
            }
        }

        /**
         * Unregister Table of Contents block in Widgets and Site Editor
         *
         * @return void
         */
        public function advgbDisableBlocks()
        {
            if (Utilities::settingIsEnabled('enable_advgb_blocks')) {
                wp_enqueue_script(
                    'advgb_disable_blocks_js',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/disable-blocks.js',
                    array( 'advgb_blocks' ),
                    ADVANCED_GUTENBERG_VERSION
                );
            }
        }

        /**
         * Load block that required server side render
         *
         * @return void
         */
        public function advgbBlockLoader()
        {
            // Block Content Display
            require_once(plugin_dir_path(dirname(__FILE__)) . 'assets/blocks/recent-posts/block.php');
            // Load all block registrations
            require_once(plugin_dir_path(dirname(__FILE__)) . 'assets/blocks/register-blocks.php');

        }

        /**
         * Add "Upgrade to Pro" notices
         *
         * @return void
         */
        public function upgradeProNotices()
        {
            if (
                current_user_can('install_plugins')
                && ! defined('ADVANCED_GUTENBERG_PRO_LOADED')
                && class_exists('PPVersionNotices\Module\TopNotice\Module')
                && class_exists('PPVersionNotices\Module\MenuLink\Module')
            ) {
                // Top notice
                add_filter(
                    \PPVersionNotices\Module\TopNotice\Module::SETTINGS_FILTER,
                    function ($settings) {
                        $settings['advanced-gutenberg'] = [
                            'message' => __(
                                'You\'re using PublishPress Blocks Free. The Pro version has more features and support. %sUpgrade to Pro%s',
                                'advanced-gutenberg'
                            ),
                            'link'    => 'https://publishpress.com/links/blocks-banner',
                            'screens' => [
                                [ 'base' => 'toplevel_page_advgb_main' ],
                                [ 'base' => 'blocks_page_advgb_block_access' ],
                                [ 'base' => 'blocks_page_advgb_block_usage' ],
                                [ 'base' => 'blocks_page_advgb_block_settings' ],
                                [ 'base' => 'blocks_page_advgb_custom_styles' ],
                                [ 'base' => 'blocks_page_advgb_settings' ],
                                [ 'base' => 'blocks_page_advgb_block_controls' ],
                            ]
                        ];

                        return $settings;
                    }
                );

                // Menu link
                add_filter(
                    \PPVersionNotices\Module\MenuLink\Module::SETTINGS_FILTER,
                    function ($settings) {
                        $settings['advanced-gutenberg'] = [
                            'parent' => 'advgb_main',
                            'label'  => __('Upgrade to Pro', 'advanced-gutenberg'),
                            'link'   => ADVANCED_GUTENBERG_UPGRADE_LINK,
                        ];

                        return $settings;
                    }
                );
            }
        }

        /**
         * Register REST API
         *
         * @return void
         */
        public function registerRestAPI()
        {
            // Add author info
            register_rest_field(
                'post',
                'author_meta',
                array(
                    'get_callback'    => array( $this, 'getAuthorInfo' ),
                    'update_callback' => null,
                    'schema'          => null,
                )
            );

            // Add post featured img
            register_rest_field(
                'post',
                'featured_img',
                array(
                    'get_callback'    => array( $this, 'getFeaturedImg' ),
                    'update_callback' => null,
                    'schema'          => null,
                )
            );

            // Register router to get data for Woo Products block
            if (class_exists('WC_REST_Products_Controller')) {
                include_once(plugin_dir_path(dirname(__FILE__)) . 'assets/blocks/woo-products/controller.php');
                $controller = new AdvgbProductsController();
                $controller->register_routes();
            }

            // Register custom routes for Block controls
            if (
                Utilities::settingIsEnabled('block_controls')
                 && method_exists('PublishPress\Blocks\Controls', 'registerCustomRoutes')
            ) {
                PublishPress\Blocks\Controls::registerCustomRoutes();
            }
        }

        /**
         * Get post author info for REST API
         *
         * @param array $object API Object
         *
         * @return mixed
         */
        public function getAuthorInfo($object)
        {
            // Get the author name
            $author['display_name'] = get_the_author_meta('display_name', $object['author']);

            // Get the author link
            $author['author_link'] = get_author_posts_url($object['author']);

            // Return the author data
            return $author;
        }

        /**
         * Get featured image link for REST API
         *
         * @param array $object API Object
         *
         * @return mixed
         */
        public function getFeaturedImg($object)
        {
            $featured_img = wp_get_attachment_image_src(
                $object['featured_media'],
                'medium',
                false
            );

            if ($featured_img) {
                return $featured_img[0];
            }
        }

        /**
         * Ajax to update blocks list
         *
         * @return mixed
         */
        public function updateBlocksList()
        {
            if (! current_user_can('activate_plugins')) {
                wp_send_json('', 400);
            }

            if (empty($_POST['nonce'])) {
                wp_send_json('', 400);
            }

            if (
                ! wp_verify_nonce(sanitize_text_field($_POST['nonce']), 'advgb_update_blocks_list')
                 && ! wp_verify_nonce(sanitize_text_field($_POST['nonce']), 'advgb_nonce')
            ) {
                wp_send_json('', 400);
            }

            /**
             * Cleanup block list
             *
             * @param array $block Block
             *
             * @return mixed
             */
            function cleanupBlockList(array $block)
            {
                $block['icon']     = isset($block['icon']) ? htmlentities(stripslashes($block['icon']), ENT_QUOTES) : '';
                $block['name']     = isset($block['name']) ? sanitize_text_field($block['name']) : '';
                $block['title']    = isset($block['title']) ? sanitize_text_field($block['title']) : '';
                $block['category'] = isset($block['category']) ? sanitize_text_field($block['category']) : '';

                return $block;
            }

            if (is_array($_POST['blocksList'])) {
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
                $blocksList = array_map('cleanupBlockList', $_POST['blocksList']);
            } else {
				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
                $blocksList = json_decode(stripslashes($_POST['blocksList']));
            }

            $savedBlocksList = get_option('advgb_blocks_list');
            if (! is_array($savedBlocksList)) {
                $savedBlocksList = array();
            }

            $blocksListName      = array();
            $savedBlocksListName = array();

            // Blocks coming from Block Access admin screen form
            foreach ($blocksList as &$block) {
                // Convert object to array
                $block            = (array) $block;
                $blocksListName[] = $block['name'];
            }

            // Blocks saved in advgb_blocks_list option
            foreach ($savedBlocksList as $block) {
                // Convert object to array
                $block                 = (array) $block;
                $savedBlocksListName[] = $block['name'];
            }

            // Check if we have new blocks installed
            $newBlocks = array_diff($blocksListName, $savedBlocksListName);
            if (count($newBlocks)) {
                update_option('advgb_blocks_list', $blocksList, false);
            }

            // Check that advgb_blocks_user_roles is up to date - The result of this check is not saved
            $advgb_blocks_user_roles         = get_option('advgb_blocks_user_roles');
            $advgb_blocks_user_roles_updated = array();

            if ($advgb_blocks_user_roles) {
                foreach ($advgb_blocks_user_roles as $role => $blocks) {
                    if (is_array($blocks) && is_array($blocks['active_blocks']) && is_array($blocks['inactive_blocks'])) {
                        $allAccessBlocks = array_merge($blocks['active_blocks'], $blocks['inactive_blocks']);

                        $newAllowedBlocks = array_diff($blocksListName, $allAccessBlocks);
                        $newAllowedBlocks = array_unique($newAllowedBlocks);

                        if ($newAllowedBlocks) {
                            $advgb_blocks_user_roles_updated[ $role ]['active_blocks']   = array_merge(
                                $blocks['active_blocks'],
                                $newAllowedBlocks
                            );
                            $advgb_blocks_user_roles_updated[ $role ]['inactive_blocks'] = $blocks['inactive_blocks'];
                        }
                    }
                }
            }

            if (
                ( defined('GUTENBERG_VERSION')
                   && version_compare(get_option('advgb_gutenberg_version'), GUTENBERG_VERSION, '<') )
            ) {
                update_option('advgb_gutenberg_version', GUTENBERG_VERSION);
            }

            wp_send_json([
                'blocks_list' => $blocksList
            ], 200);
        }

        public function scan_block_usage()
        {
            check_ajax_referer('block_usage_nonce', 'nonce');

            if (! current_user_can('administrator')) {
                wp_send_json(__('No permission!', 'advanced-gutenberg'), 403);
                return false;
            }

            $offset = (int) ($_POST['offset'] ?? 0);
            $batch_size = 30;
            $current_time = current_time('mysql');

            $post_types = [];
            if (isset($_POST['post_types'])) {
                if (is_array($_POST['post_types'])) {
                    $post_types = map_deep($_POST['post_types'], 'sanitize_text_field');
                } else {
                    $post_types = array_filter(
                        explode(',', sanitize_text_field($_POST['post_types'])),
                        function ($type) {
                            return !empty(trim($type));
                        }
                    );
                }
            }

            if (empty($post_types)) {
                $post_types = array_keys(get_post_types(['show_in_rest' => true]));
            }

            $query = new WP_Query([
                'post_type' => $post_types,
                'posts_per_page' => $batch_size,
                'offset' => $offset,
                'post_status' => 'any',
                'orderby' => 'ID',
                'order' => 'ASC'
            ]);

            $usage = [];
            $posts = [];
            $processed = 0;

            foreach ($query->posts as $post) {
                $post_id = $post->ID;
                // Skip if no content
                if (empty($post->post_content)) {
                    continue;
                }
                $blocks = parse_blocks($post->post_content);

                // skip if block is empty
                if (empty($blocks)) {
                    continue;
                }

                $can_edit = current_user_can('edit_post', $post_id);

                $post_data = [
                    'post_id' => $post_id,
                    'post_title' => $post->post_title ?: "Post ID: $post_id",
                    'edit_link' => $can_edit ? get_edit_post_link($post_id, '') : '',
                    'view_link' => get_permalink($post_id),
                    'post_type' => $post->post_type,
                    'extra' => [],
                    'blocks' => []
                ];

                $block_counts = [];

                foreach ($blocks as $b) {
                    if (empty($b['blockName'])) {
                        continue;
                    }
                    $name = $b['blockName'];

                    // Store complete block data
                    $post_data['blocks'][] = [
                        'name' => $name,
                        'clientId' => $b['clientId'] ?? '',
                        'innerBlocks' => array_map(function ($inner) {
                            return [
                                'name' => $inner['blockName'] ?? '',
                                'clientId' => $inner['clientId'] ?? '',
                                'innerBlocks' => $inner['innerBlocks'] ?? []
                            ];
                        }, $b['innerBlocks'] ?? [])
                    ];

                    // Count blocks
                    $block_counts[$name] = ($block_counts[$name] ?? 0) + 1;
                }

                $posts[] = $post_data;

                foreach ($block_counts as $name => $count) {
                    if (!isset($usage[$name])) {
                        $usage[$name] = [
                            'posts' => [],
                            'total' => 0
                        ];
                    }

                    $usage[$name]['posts'][$post_id] = [
                        'count' => $count,
                        'scanned' => $current_time
                    ];
                    $usage[$name]['total'] += $count;
                }

                $processed++;
            }

            wp_send_json_success([
                'usage' => $usage,
                'posts' => $posts,
                'lastScanDate' => $current_time,
                'processed' => $processed,
                'total' => $query->found_posts,
            ]);
        }

        /**
         * Ajax for saving a feature from main page
         *
         * @return boolean,void     Return false if failure, echo json on success
         */
        public function saveFeature()
        {
            if (! current_user_can('activate_plugins')) {
                wp_send_json(__('No permission!', 'advanced-gutenberg'), 403);

                return false;
            }

            if (
                ! wp_verify_nonce(
                    sanitize_key($_POST['nonce']),
                    'advgb_main_features_nonce'
                )
            ) {
                wp_send_json(__('Invalid nonce token!', 'advanced-gutenberg'), 400);
            }

            if (empty($_POST['feature']) || ! $_POST['feature']) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
                wp_send_json(__('Error: wrong data', 'advanced-gutenberg'), 400);

                return false;
            }

            $feature      = sanitize_text_field($_POST['feature']);
            $all_features = [
                'block_controls',
                'enable_block_access',
                'enable_block_usage',
                'enable_custom_styles',
                'enable_advgb_blocks',
                'reusable_blocks',
                'auto_insert_blocks'
            ];

            // Pro features
            if (defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                array_push(
                    $all_features,
                    'enable_core_blocks_features'
                );
            }

            if (in_array($feature, $all_features)) {
                $advgb_settings             = get_option('advgb_settings');
                $advgb_settings[ $feature ] = (bool) $_POST['new_state'] ? 1 : 0;

                update_option('advgb_settings', $advgb_settings);
                wp_send_json(true, 200);
            } else {
                wp_send_json(__('Error: can\'t edit this feature', 'advanced-gutenberg'), 400);

                return false;
            }
        }

        /**
         * Ajax for saving block default config
         *
         * @return boolean,void     Return false if failure, echo json on success
         */
        public function saveBlockConfig()
        {
            // Check users permissions
            if (! current_user_can('activate_plugins')) {
                wp_send_json(__('No permission!', 'advanced-gutenberg'), 403);

                return false;
            }

            if (
                ! isset($_POST['nonce'])
                || is_array($_POST['nonce'])
                || ! wp_verify_nonce(
                    sanitize_text_field(wp_unslash($_POST['nonce'])),
                    'advgb_block_config_nonce'
                )
            ) {
                wp_send_json(__('Invalid nonce token!', 'advanced-gutenberg'), 400);
            }

            $blocks_config_saved = get_option('advgb_blocks_default_config');
            if (! is_array($blocks_config_saved)) {
                $blocks_config_saved = array();
            }

            $blockType            = isset($_POST['blockType']) && ! is_array($_POST['blockType'])
                ? sanitize_text_field(wp_unslash($_POST['blockType']))
                : '';
            $blocks_settings_list = PublishPress\Blocks\Configuration::defaultConfig();

            if (! isset($blocks_settings_list[ $blockType ])) {
                wp_send_json(__('Error: wrong block type', 'advanced-gutenberg'), 400);

                return false;
            }

            $raw_settings = isset($_POST['settings']) && is_array($_POST['settings'])
                ? wp_unslash($_POST['settings'])
                : array();

            if (! isset($raw_settings[ $blockType ]) || ! is_array($raw_settings[ $blockType ])) {
                wp_send_json(__('Error: wrong data', 'advanced-gutenberg'), 400);

                return false;
            }

            $allowed_setting_names = $this->getBlockConfigSettingNames($blocks_settings_list[ $blockType ]);
            $settings              = array(
                $blockType => array(),
            );

            foreach ($raw_settings[ $blockType ] as $key => $option) {
                $setting_key = (string) $key;
                if (
                    ! isset($allowed_setting_names[ $setting_key ])
                    || is_array($option)
                    || is_object($option)
                ) {
                    continue;
                }

                $option = sanitize_text_field((string) $option);
                if (is_numeric($option)) {
                    if ($setting_key !== 'lat' && $setting_key !== 'lng') {
                        $option = floatval($option);
                    }
                }

                $settings[ $blockType ][ $setting_key ] = $option;
            }

            // Modify settings for social links blocks config
            if ($blockType === 'advgb-social-links') {
                $items                           = array();
                $settings[ $blockType ]['items'] = array();

                foreach ($settings[ $blockType ] as $k => $option) {
                    if (strpos($k, '.') !== false) {
                        $item                          = explode('.', $k, 2);
                        $items[ $item[0] ][ $item[1] ] = $option;
                    }
                }

                foreach ($items as $item) {
                    array_push($settings[ $blockType ]['items'], $item);
                }
            }

            $blocks_config_saved[ $blockType ] = $settings[ $blockType ];

            update_option('advgb_blocks_default_config', $blocks_config_saved, false);
            wp_send_json(true, 200);
        }

        /**
         * Get allowed default config setting names for a block.
         *
         * @param array $block_settings Block settings definition.
         *
         * @return array
         */
        private function getBlockConfigSettingNames(array $block_settings)
        {
            $setting_names = array();

            foreach ($block_settings as $category) {
                if (empty($category['settings']) || ! is_array($category['settings'])) {
                    continue;
                }

                foreach ($category['settings'] as $setting) {
                    if (empty($setting['name']) || ! is_string($setting['name'])) {
                        continue;
                    }

                    $setting_names[ $setting['name'] ] = true;
                }
            }

            return $setting_names;
        }

        /**
         * Ajax for saving contact form data
         *
         * @return boolean,void     Return false if failure, echo json on success
         */
        public function saveContactFormData()
        {
            // Don't save if Settings > PublishPress Blocks are disabled
            if (! Utilities::settingIsEnabled('enable_advgb_blocks')) {
                return false;
            }

            if (! wp_verify_nonce(sanitize_text_field($_POST['nonce']), 'advgb_blockform_nonce_field')) {
                wp_send_json(__('Invalid nonce token!', 'advanced-gutenberg'), 400);
            }

			// phpcs:disable -- WordPress.Security.NonceVerification.Recommended - frontend form, no nonce
			if ( ! isset( $_POST['action'] ) ) {
				wp_send_json( __( 'Bad Request!', 'advanced-gutenberg' ), 400 );

				return false;
			}

			$this->rateLimitFormSubmission( 'contact_form' );

			if ( isset( $_POST['captcha'] ) ) {
				$recaptcha_config = get_option( 'advgb_recaptcha_config' );
				if ( ! isset( $recaptcha_config['recaptcha_secret_key'] ) || ! isset( $recaptcha_config['recaptcha_site_key'] ) ) {
					wp_send_json( __( 'Server error. Try again later!', 'advanced-gutenberg' ), 500 );
				}

				$captcha    = $_POST['captcha'];
				$secret_key = $recaptcha_config['recaptcha_secret_key'];
				$verify     = wp_remote_get( "https://www.google.com/recaptcha/api/siteverify?secret={$secret_key}&response={$captcha}" );

				if ( ! is_array( $verify ) || ! isset( $verify['body'] ) ) {
					wp_send_json( __( 'Cannot validate captcha', 'advanced-gutenberg' ), 400 );
				}

				$verified = json_decode( $verify['body'] );
				if ( ! $verified->success ) {
					wp_send_json( __( 'Captcha validation error', 'advanced-gutenberg' ), 400 );
				}
			}

			$contacts_saved = get_option( 'advgb_contacts_saved' );
			if ( ! is_array( $contacts_saved ) ) {
				$contacts_saved = array();
			}

			$contact_data = array(
				'date'  => $this->sanitizeFormPostField( 'submit_date', 'text', 100, 'contact_form' ),
				'name'  => $this->sanitizeFormPostField( 'contact_name', 'text', 200, 'contact_form' ),
				'email' => $this->sanitizeFormPostField( 'contact_email', 'email', 254, 'contact_form' ),
				'msg'   => $this->sanitizeFormPostField( 'contact_msg', 'textarea', 5000, 'contact_form' ),
			);

			array_push( $contacts_saved, $contact_data );
			$contacts_saved = $this->limitSavedFormEntries( $contacts_saved, 'advgb_contacts_saved' );

			$saved = update_option( 'advgb_contacts_saved', $contacts_saved, false );
			if ( $saved ) {
				$saved_settings = get_option( 'advgb_email_sender' );
				$website_title  = get_option( 'blogname' );
				$admin_email    = get_option( 'admin_email' );
				$sender_name    = isset( $saved_settings['contact_form_sender_name'] ) && $saved_settings['contact_form_sender_name'] ? $saved_settings['contact_form_sender_name'] : $website_title;
				$sender_email   = isset( $saved_settings['contact_form_sender_email'] ) && $saved_settings['contact_form_sender_email'] ? $saved_settings['contact_form_sender_email'] : $admin_email;
				$email_title    = isset( $saved_settings['contact_form_email_title'] ) && $saved_settings['contact_form_email_title'] ? $saved_settings['contact_form_email_title'] : __( 'Website Contact',
					'advanced-gutenberg' );
				$email_receiver = isset( $saved_settings['contact_form_email_receiver'] ) && $saved_settings['contact_form_email_receiver'] ? $saved_settings['contact_form_email_receiver'] : $admin_email;
				$email_header[] = 'Content-Type: text/html; charset=UTF-8';
				$email_header[] = 'From: ' . $sender_name . ' <' . $sender_email . '>';
				$msg            = '<html><body>';
				$msg            .= '<h2>' . __( 'You have received a contact from your website.',
						'advanced-gutenberg' ) . '</h2>';
				$msg            .= '<ul>';
				$msg            .= '<li><strong>' . __( 'Name',
						'advanced-gutenberg' ) . ': </strong>' . $contact_data['name'] . '</li>';
				$msg            .= '<li><strong>' . __( 'Email',
						'advanced-gutenberg' ) . ': </strong>' . $contact_data['email'] . '</li>';
				$msg            .= '<li><strong>' . __( 'Date',
						'advanced-gutenberg' ) . ': </strong>' . $contact_data['date'] . '</li>';
				$msg            .= '<li><strong>' . __( 'Message',
						'advanced-gutenberg' ) . ': </strong>' . $contact_data['msg'] . '</li>';
				$msg            .= '</ul>';
				$msg            .= '</body></html>';

				wp_mail( $email_receiver, $email_title, $msg, $email_header );
				wp_send_json( $contact_data, 200 );
			} else {
				wp_send_json( __( 'Error while sending the form. Please try again.', 'advanced-gutenberg' ), 500 );
			}
			// phpcs:enable
        }

        /**
         * Ajax for saving newsletter form data
         *
         * @return boolean,void     Return false if failure, echo json on success
         */
        public function saveNewsletterData()
        {
            // Don't save if Settings > PublishPress Blocks are disabled
            if (! Utilities::settingIsEnabled('enable_advgb_blocks')) {
                return false;
            }

            if (! wp_verify_nonce(sanitize_text_field($_POST['nonce']), 'advgb_blockform_nonce_field')) {
                wp_send_json(__('Invalid nonce token!', 'advanced-gutenberg'), 400);
            }

			// phpcs:disable -- WordPress.Security.NonceVerification.Recommended - frontend form, no nonce
			if ( ! isset( $_POST['action'] ) ) {
				wp_send_json( __( 'Bad Request!', 'advanced-gutenberg' ), 400 );

				return false;
			}

			$this->rateLimitFormSubmission( 'newsletter' );

			if ( isset( $_POST['captcha'] ) ) {
				$recaptcha_config = get_option( 'advgb_recaptcha_config' );
				if ( ! isset( $recaptcha_config['recaptcha_secret_key'] ) || ! isset( $recaptcha_config['recaptcha_site_key'] ) ) {
					wp_send_json( __( 'Server error. Try again later!', 'advanced-gutenberg' ), 500 );
				}

				$captcha    = $_POST['captcha'];
				$secret_key = $recaptcha_config['recaptcha_secret_key'];
				$verify     = wp_remote_get( "https://www.google.com/recaptcha/api/siteverify?secret={$secret_key}&response={$captcha}" );

				if ( ! is_array( $verify ) || ! isset( $verify['body'] ) ) {
					wp_send_json( __( 'Cannot validate captcha', 'advanced-gutenberg' ), 400 );
				}

				$verified = json_decode( $verify['body'] );
				if ( ! $verified->success ) {
					wp_send_json( __( 'Captcha validation error', 'advanced-gutenberg' ), 400 );
				}
			}

			$newsletter_saved = get_option( 'advgb_newsletter_saved' );
			if ( ! is_array( $newsletter_saved ) ) {
				$newsletter_saved = array();
			}

			$newsletter_data = array(
				'date'  => $this->sanitizeFormPostField( 'submit_date', 'text', 100, 'newsletter' ),
				'fname' => $this->sanitizeFormPostField( 'f_name', 'text', 200, 'newsletter' ),
				'lname' => $this->sanitizeFormPostField( 'l_name', 'text', 200, 'newsletter' ),
				'email' => $this->sanitizeFormPostField( 'email', 'email', 254, 'newsletter' ),
			);

			array_push( $newsletter_saved, $newsletter_data );
			$newsletter_saved = $this->limitSavedFormEntries( $newsletter_saved, 'advgb_newsletter_saved' );

			update_option( 'advgb_newsletter_saved', $newsletter_saved, false );
			wp_send_json( $newsletter_data, 200 );
			// phpcs:enable
        }

        /**
         * Rate limit public form submissions by visitor.
         *
         * @param string $form_type Form type.
         *
         * @return void
         */
        private function rateLimitFormSubmission( $form_type )
        {
            $limit  = (int) apply_filters( 'advgb_form_submission_rate_limit_count', 5, $form_type );
            $window = (int) apply_filters( 'advgb_form_submission_rate_limit_window', 5 * MINUTE_IN_SECONDS, $form_type );

            if ( $limit < 1 || $window < 1 ) {
                return;
            }

            $fingerprint = $this->getFormSubmissionFingerprint();
            if ( $fingerprint === '' ) {
                return;
            }

            $transient_key = 'advgb_form_rate_' . md5( $form_type . '|' . $fingerprint );
            $attempts      = (int) get_transient( $transient_key );

            if ( $attempts >= $limit ) {
                wp_send_json( __( 'Too many submissions. Please try again later.', 'advanced-gutenberg' ), 429 );
            }

            set_transient( $transient_key, $attempts + 1, $window );
        }

        /**
         * Get a stable visitor fingerprint for public form rate limiting.
         *
         * @return string
         */
        private function getFormSubmissionFingerprint()
        {
            if ( is_user_logged_in() ) {
                return 'user:' . get_current_user_id();
            }

            if ( empty( $_SERVER['REMOTE_ADDR'] ) ) {
                return '';
            }

            $remote_addr = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
            if ( ! filter_var( $remote_addr, FILTER_VALIDATE_IP ) ) {
                return '';
            }

            return 'ip:' . $remote_addr;
        }

        /**
         * Sanitize and size-limit a public form POST field.
         *
         * @param string $field      Field name.
         * @param string $type       Sanitizer type.
         * @param int    $max_length Maximum retained length.
         * @param string $form_type  Form type.
         *
         * @return string
         */
        private function sanitizeFormPostField( $field, $type, $max_length, $form_type )
        {
            $value = isset( $_POST[ $field ] ) ? wp_unslash( $_POST[ $field ] ) : '';
            if ( is_array( $value ) ) {
                $value = '';
            }

            if ( $type === 'email' ) {
                $value = sanitize_email( $value );
            } elseif ( $type === 'textarea' ) {
                $value = sanitize_textarea_field( $value );
            } else {
                $value = sanitize_text_field( $value );
            }

            $max_length = absint(
                apply_filters( 'advgb_form_field_max_length', $max_length, $field, $form_type )
            );

            if ( $max_length < 1 ) {
                return $value;
            }

            if ( function_exists( 'mb_substr' ) ) {
                return mb_substr( $value, 0, $max_length );
            }

            return substr( $value, 0, $max_length );
        }

        /**
         * Keep saved form options bounded while preserving the newest entries.
         *
         * @param array  $entries     Saved entries.
         * @param string $option_name Option name.
         *
         * @return array
         */
        private function limitSavedFormEntries( $entries, $option_name )
        {
            if ( ! is_array( $entries ) ) {
                return array();
            }

            $max_entries = absint( apply_filters( 'advgb_form_saved_entries_limit', 1000, $option_name ) );
            if ( $max_entries < 1 ) {
                $max_entries = 1;
            }

            if ( count( $entries ) > $max_entries ) {
                $entries = array_slice( $entries, -$max_entries );
            }

            $max_bytes = absint(
                apply_filters( 'advgb_form_saved_option_max_bytes', 5 * MB_IN_BYTES, $option_name )
            );

            while ( $max_bytes > 0 && count( $entries ) > 1 && strlen( maybe_serialize( $entries ) ) > $max_bytes ) {
                array_shift( $entries );
            }

            return $entries;
        }

        /**
         * Ajax for validating login/register form captcha
         *
         * @return boolean,void     Return false if failure, echo json on success
         */
        public function validateLoresForm()
        {
			if (
				! isset( $_POST['nonce'] )
				|| ! wp_verify_nonce(
					sanitize_text_field( wp_unslash( $_POST['nonce'] ) ),
					'advgb_blockform_nonce_field'
				)
			) {
				wp_send_json( __( 'Invalid nonce token!', 'advanced-gutenberg' ), 400 );

				return false;
			}

			if ( ! isset( $_POST['action'] ) ) {
				wp_send_json( __( 'Bad Request!', 'advanced-gutenberg' ), 400 );

				return false;
			}

			if ( isset( $_POST['captcha'] ) ) {
				$recaptcha_config = get_option( 'advgb_recaptcha_config' );
				if ( ! isset( $recaptcha_config['recaptcha_secret_key'] ) || ! isset( $recaptcha_config['recaptcha_site_key'] ) ) {
					wp_send_json( __( 'Server error. Try again later!', 'advanced-gutenberg' ), 500 );
				}

				$captcha    = $_POST['captcha'];
				$secret_key = $recaptcha_config['recaptcha_secret_key'];
				$verify     = wp_remote_get( "https://www.google.com/recaptcha/api/siteverify?secret={$secret_key}&response={$captcha}" );

				if ( ! is_array( $verify ) || ! isset( $verify['body'] ) ) {
					wp_send_json( __( 'Cannot validate captcha', 'advanced-gutenberg' ), 400 );
				}

				$verified = json_decode( $verify['body'] );
				if ( ! $verified->success ) {
					wp_send_json( __( 'Captcha validation error', 'advanced-gutenberg' ), 400 );
				}

				wp_send_json( __( 'Captcha validated', 'advanced-gutenberg' ), 200 );
			}

			wp_send_json( __( 'Captcha is empty', 'advanced-gutenberg' ), 400 );
			// phpcs:enable
        }

        /**
         * Handle failed login from our login form and redirect to that login page
         *
         * @return void
         */
        public function handleLoginFailed()
        {
            $from_advgb = isset($_POST['advgb_login_form']); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- redirect
            if (! empty($_SERVER['HTTP_REFERER']) && $from_advgb) {
                $redirect = add_query_arg(
                    'login',
                    'failed',
                    $_SERVER['HTTP_REFERER']
                ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
                wp_safe_redirect($redirect);
                exit;
            }
        }

        /**
         * Register back-end styles and script for later use
         *
         * @return void
         */
        public function registerStylesScripts()
        {
            if (! wp_doing_ajax()) {
                // Register CSS
                wp_register_style(
                    'advgb_admin_styles',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/style.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_style(
                    'advgb_admin_menu_styles',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/admin-menu.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_style(
                    'advgb_qtip_style',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/jquery.qtip.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_style(
                    'codemirror_css',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/codemirror/lib/codemirror.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_style(
                    'codemirror_hint_style',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/codemirror/addon/hint/show-hint.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_style(
                    'minicolors_css',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/jquery.minicolors.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_style(
                    'material_icon_font',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/fonts/material-icons.min.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_style(
                    'material_icon_font_custom',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/fonts/material-icons-custom.min.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_style(
                    'slick_style',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/slick.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_style(
                    'slick_theme_style',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/slick-theme.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_style(
                    'advgb_custom_styles_css',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/custom-styles.css',
                    [],
                    ADVANCED_GUTENBERG_VERSION
                );

                // Register JS
                // @TODO - Check if we really need all the dependencies from 'advgb_main_js'
                wp_register_script(
                    'advgb_main_js',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/main.min.js',
                    array(
                        'jquery',
                        'wp-block-editor',
                        'wp-blocks',
                        'wp-element',
                        'wp-data',
                        'wp-components',
                        'wp-core-data',
                        'wp-block-library',
                        'wp-editor',
                        'wp-edit-post',
                        'wp-plugins'
                    ),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_script(
                    'advgb_update_list',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/update-block-list.js',
                    array( 'jquery' ),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_script(
                    'advgb_settings_js',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/settings.min.js',
                    array( 'wp-i18n' ),
                    ADVANCED_GUTENBERG_VERSION
                );
				wp_set_script_translations(
                    'advgb_settings_js',
                    'advanced-gutenberg',
                    plugin_dir_path(ADVANCED_GUTENBERG_PLUGIN) . 'languages'
                );
                wp_register_script(
                    'advgb_custom_styles_js',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/custom-styles.js',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_script(
                    'qtip_js',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/jquery.qtip.min.js',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_script(
                    'advgb_codemirror_js',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/codemirror/lib/codemirror.js',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_script(
                    'codemirror_hint',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/codemirror/addon/hint/show-hint.js',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_script(
                    'codemirror_mode_css',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/codemirror/mode/css/css.js',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_script(
                    'codemirror_hint_css',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/codemirror/addon/hint/css-hint.js',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_script(
                    'less_js',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/less.js',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_script(
                    'minicolors_js',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/jquery.minicolors.min.js',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_script(
                    'slick_js',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/slick.min.js',
                    array( 'jquery' ),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_script(
                    'advgb_masonry_js',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/isotope.pkgd.min.js',
                    array( 'jquery' ),
                    ADVANCED_GUTENBERG_VERSION
                );

                $saved_settings = get_option('advgb_settings');
                if (isset($saved_settings['editor_width']) && $saved_settings['editor_width']) {
                    wp_add_inline_style(
                        'dashicons',
                        'body:not(.advgb-editor-width-default) #editor .edit-post-visual-editor__post-title-wrapper > .wp-block,body:not(.advgb-editor-width-default) #editor .block-editor-writing-flow > .block-editor-block-list__layout > .wp-block{max-width:' . $saved_settings['editor_width'] . '%;width:' . $saved_settings['editor_width'] . '%;margin-left:auto;margin-right:auto}'
                    );
                }
            }
        }

        /**
         * Register front-end styles and script for later use
         *
         * @return void
         */
        public function registerStylesScriptsFrontend()
        {
            if (Utilities::settingIsEnabled('enable_advgb_blocks')) {
                wp_register_script(
                    'advgb_blocks_frontend_scripts',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/frontend.js',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );

                // Pro
                if (defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                    if (
                        method_exists(
                            'PPB_AdvancedGutenbergPro\Utils\Definitions',
                            'advgb_pro_register_scripts_frontend'
                        )
                    ) {
                        PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_register_scripts_frontend();
                    }
                }
            }

            wp_register_style(
                'colorbox_style',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/colorbox.css',
                array(),
                ADVANCED_GUTENBERG_VERSION
            );
            wp_register_style(
                'slick_style',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/slick.css'
            );
            wp_register_style(
                'slick_theme_style',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/slick-theme.css',
                [ 'dashicons' ],
                ADVANCED_GUTENBERG_VERSION
            );
            wp_register_style(
                'material_icon_font',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/fonts/material-icons.min.css'
            );
            wp_register_style(
                'material_icon_font_custom',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/fonts/material-icons-custom.min.css'
            );

            if (Utilities::settingIsEnabled('enable_advgb_blocks')) {
                wp_register_style(
                    'advgb_columns_styles',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/columns.css',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
                wp_register_style(
                    'advgb_recent_posts_styles',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/recent-posts.css',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );
            }

            wp_register_script(
                'colorbox_js',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/jquery.colorbox.min.js',
                array( 'jquery' ),
                ADVANCED_GUTENBERG_VERSION
            );
            wp_register_script(
                'slick_js',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/slick.min.js',
                array( 'jquery' ),
                ADVANCED_GUTENBERG_VERSION
            );
            wp_register_script(
                'advgb_masonry_js',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/isotope.pkgd.min.js',
                array( 'jquery' ),
                ADVANCED_GUTENBERG_VERSION
            );

            $saved_settings = get_option('advgb_settings');
            if (isset($saved_settings['enable_blocks_spacing']) && $saved_settings['enable_blocks_spacing']) {
                $blocks_spacing = isset($saved_settings['blocks_spacing']) ? $saved_settings['blocks_spacing'] : 0;

                wp_add_inline_style(
                    'dashicons',
                    '.entry-content > * {margin-bottom: ' . $blocks_spacing . 'px !important}'
                );
            }
        }

        /**
         * Get list of submenu pages
         *
         * @return array
         * @since 3.0.0
         */
        public function subAdminPages()
        {
            /* Duplicate first submenu from parent to generate a different menu title.
             * 'Blocks' -> 'Dashboard'
             */
            $submenu_pages = [
                [
                    'slug'     => 'advgb_main',
                    'title'    => esc_html__('Dashboard', 'advanced-gutenberg'),
                    'callback' => 'loadMainPage',
                    'order'    => 1,
                    'enabled'  => true
                ],
                [
                    'slug'     => 'advgb_block_access',
                    'title'    => esc_html__('Block Permissions', 'advanced-gutenberg'),
                    'callback' => 'loadBlockAccessPage',
                    'order'    => 2,
                    'enabled'  => Utilities::settingIsEnabled('enable_block_access')
                ],
                [
                    'slug'     => 'advgb_block_settings',
                    'title'    => esc_html__('Extra Blocks', 'advanced-gutenberg'),
                    'callback' => 'loadBlockSettingsPage',
                    'order'    => 3,
                    'enabled'  => Utilities::settingIsEnabled('enable_advgb_blocks')
                ],
                [
                    'slug'     => 'advgb_custom_styles',
                    'title'    => esc_html__('Block Styles', 'advanced-gutenberg'),
                    'callback' => 'loadCustomStylesPage',
                    'order'    => 4,
                    'enabled'  => Utilities::settingIsEnabled('enable_custom_styles')
                ],
                [
                    'slug'     => 'advgb_block_controls',
                    'title'    => esc_html__('Block Controls', 'advanced-gutenberg'),
                    'callback' => 'loadBlockControlsPage',
                    'order'    => 5,
                    'enabled'  => Utilities::settingIsEnabled('block_controls')
                ],
                [
                    'slug'     => 'advgb_block_usage',
                    'title'    => esc_html__('Block Usage', 'advanced-gutenberg'),
                    'callback' => 'loadBlockUsagePage',
                    'order'    => 6,
                    'enabled'  => Utilities::settingIsEnabled('enable_block_usage')
                ],
                [
                    'slug'     => 'edit.php?post_type=wp_block',
                    'title'    => esc_html__('Reusable Blocks', 'advanced-gutenberg'),
                    'callback' => '',
                    'order'    => 7,
                    'enabled'  => Utilities::settingIsEnabled('reusable_blocks')
                ],
                [
                'slug'     => 'edit.php?post_type=advgb_insert_block',
                'title'    => esc_html__( 'Auto Insert Blocks', 'advanced-gutenberg' ),
                'callback' => '',
                'order'    => 8,
                'enabled'  => Utilities::settingIsEnabled( 'auto_insert_blocks' )
                ],
                [
                    'slug'     => 'advgb_settings',
                    'title'    => esc_html__('Settings', 'advanced-gutenberg'),
                    'callback' => 'loadSettingsPage',
                    'order'    => 9,
                    'enabled'  => true
                ]
            ];

            return $submenu_pages;
        }

        /**
         * Register admin menu pages
         *
         * @return void
         */
        public function registerMainMenu()
        {
            if (! current_user_can('manage_options')) {
                return false;
            }

            global $submenu;

            if (empty($GLOBALS['admin_page_hooks']['advgb_main'])) {
                add_menu_page(
                    esc_html__('Blocks', 'advanced-gutenberg'),
                    esc_html__('Blocks', 'advanced-gutenberg'),
                    'manage_options',
                    'advgb_main',
                    [ $this, 'loadMainPage' ],
                    'dashicons-layout',
                    20
                );

                $submenu_pages = $this->subAdminPages();
                foreach ($submenu_pages as $page) {
                    $hook = add_submenu_page(
                        'advgb_main',
                        $page['title'],
                        $page['title'],
                        'manage_options',
                        $page['slug'],
                        // slug should use underscores, not hyphen due we generate automatic function names based on it
                        ! empty($page['callback']) ? [ $this, $page['callback'] ] : '',
                        $page['order']
                    );

                    /* Hooks to generate function names for each page and call them to save data.
                     * e.g. advgb_block_access_save_page */
                    $function_name = $page['slug'] . '_save_page';
                    if (
                        ! empty($hook)
                        && method_exists($this, $function_name)
                    ) {
                        // e.g. 'load-blocks_page_advgb_block_access'
                        add_action('load-' . $hook, [ $this, $function_name ]);
                    }
                }

                /* Add CSS classes to these submenus to dynamically show/hide them
                 * through main page enable/disable features
                 * e.g. <li class="advgb_custom_styles-menu-item"><a href="admin.php?page=advgb_custom_styles" class="advgb_custom_styles-menu-item">Block Styles</a></li>
                 */
                $submenu_slugs            = [];
                $submenu_slugs_conditions = [];
                foreach ($submenu_pages as $page) {
                    $submenu_slugs[]            = $page['slug'];
                    $submenu_slugs_conditions[] = [ $page['slug'], $page['enabled'] ];
                }

                foreach ($submenu['advgb_main'] as $key => $value) {
                    if (in_array($submenu['advgb_main'][ $key ][2], $submenu_slugs)) {
                        $slug_ = $submenu['advgb_main'][ $key ][2];

                        // Add a class to hide menu if feature is disabled on Dashboard
                        foreach ($submenu_slugs_conditions as $item) {
                            if ($item[0] === $slug_) {
                                $showHide = $item[1] === false ? ' advgb-hide-menu-item' : '';
                                break;
                            }
                        }

                        $submenu['advgb_main'][ $key ][4] = $slug_ . '-menu-item' . $showHide;
                    }
                }
            }
        }

        /**
         * Output feature boxes in main admin page
         *
         * @param array $features List of features
         *
         * @return void
         * @since 3.0.0
         */
        public function featuresBoxes($features)
        {
            ?>
            <div class="advgb-features-boxes advgb-features-boxes--<?php
            echo( defined('ADVANCED_GUTENBERG_PRO_LOADED') ? 'ispro' : 'isfree' ) ?>">
                <?php
                foreach ($features as $feature) : ?>
                    <div class="advgb-feature-box<?php
                    echo( ! $feature['access'] ? ' advgb-feature-box--disabled' : '' ); ?>">
                        <h3>
                            <?php
                            echo $feature['title'];
                            echo ! $feature['access'] ? ' <span>Pro</span>' : '';
                            ?>
                        </h3>
                        <div class="advgb-feature-description">
                            <?php
                            echo $feature['description'] ?>
                        </div>
                        <div class="advgb-feature-setting">
                            <div class="advgb-switch-button">
                                <label class="switch">
                                    <input type="checkbox"
                                           name=""
                                           value="1"
                                    <?php
                                    if ($feature['access']) {
                                        echo $this->getOptionSetting(
                                            'advgb_settings',
                                            $feature['name'],
                                            'checkbox',
                                            $feature['default']
                                        ) . ' data-feature="' . $feature['name'];
                                    } else {
                                        echo ' disabled';
                                    }
                                    ?>">
                                    <span class="slider<?php
                                    echo( ! $feature['access'] ? ' slider--disabled' : '' ); ?>"></span>
                                </label>
                            </div>
                        </div>
                    </div>
                    <?php
                endforeach; ?>
            </div>
            <?php
        }

        /**
         * Load common JS and CSS for admin pages
         *
         * @return void
         * @since 3.0.0
         */
        public static function commonAdminPagesAssets()
        {
            wp_enqueue_script('advgb_main_js');
            wp_enqueue_script('advgb_settings_js');
            wp_enqueue_script('minicolors_js');
            wp_enqueue_script('qtip_js');

            Utilities::enqueueToolTipsAssets();

            wp_enqueue_style('advgb_admin_styles');
            wp_enqueue_style('advgb_qtip_style');
            wp_enqueue_style('minicolors_css');

            $promoBlocks = [];
            if (!defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                $promoBlocks = PublishPress\Blocks\Utilities::getProBlocks();
            }
            wp_localize_script(
                'advgb_main_js',
                'advgbMainI18n',
                [
                    'promoLink' => ADVANCED_GUTENBERG_UPGRADE_LINK,
                    'upgradeText'   => __( 'Upgrade to Pro', 'advanced-gutenberg' ),
                    'proText'   => __( 'Pro', 'advanced-gutenberg' ),
                    'promoBlocks' => $promoBlocks
                ]
            );
        }

        /**
         * Main page
         *
         * @return void
         * @since 3.0.0
         */
        public function loadMainPage()
        {
            if (! current_user_can('activate_plugins')) {
                return false;
            }

            self::commonAdminPagesAssets();

            wp_localize_script(
                'advgb_main_js',
                'advgb_main_dashboard',
                [
                    'ajaxurl' => admin_url('admin-ajax.php'),
                    'nonce'   => wp_create_nonce('advgb_main_features_nonce')
                ]
            );

            $this->loadPage('main');
        }

        /**
         * Settings page
         *
         * @return void
         * @since 3.0.0
         */
        public function loadSettingsPage()
        {
            if (! current_user_can('activate_plugins')) {
                return false;
            }

            self::commonAdminPagesAssets();
            $this->loadPage('settings');
        }

        /**
         * Block access page
         *
         * @return void
         * @since 3.0.0
         */
        public function loadBlockAccessPage()
        {
            // Check users permissions
            if (! current_user_can('administrator')) {
                return false;
            }

            // Block access is disabled
            if (! Utilities::settingIsEnabled('enable_block_access')) {
                wp_die(
                    sprintf(
                        esc_html__(
                            'This feature is disabled. In order to use, please enable back through %sDashboard%s.',
                            'advanced-gutenberg'
                        ),
                        '<a href="' . admin_url('admin.php?page=advgb_main') . '">',
                        '</a>'
                    )
                );
            }

            self::commonAdminPagesAssets();

            /* Access current user blocks and saved blocks to build 2 javascript objects.
             * 'advgbCUserRole' object for current user role from form dropdown
             * 'advgb_blocks_list' object with all the saved blocks in 'advgb_blocks_list' option
             */
            $this->blocksFeatureData(
                'access',
                // The object name to store the active/inactive blocks. To see it in browser console: advgbCUserRole.access
                'advgb_blocks_user_roles' // Database option to check current user role's active/inactive blocks
            );

            // Render form
            $this->blocksFeatureForm(
                'access', // Feature name in lowercase
                __('Block Permissions', 'advanced-gutenberg') // Name of the feature
            );
        }

        /**
         * Block usage page
         *
         * @return void
         * @since 3.0.0
         */
        public function loadBlockUsagePage()
        {
            // Check users permissions
            if (! current_user_can('administrator')) {
                return false;
            }

            // Block usage is disabled
            if (! Utilities::settingIsEnabled('enable_block_usage')) {
                wp_die(
                    sprintf(
                        esc_html__(
                            'This feature is disabled. In order to use, please enable back through %sDashboard%s.',
                            'advanced-gutenberg'
                        ),
                        '<a href="' . admin_url('admin.php?page=advgb_main') . '">',
                        '</a>'
                    )
                );
            }

            self::commonAdminPagesAssets();

            /* Access current user blocks and saved blocks to build 2 javascript objects.
             * 'advgbCUserRole' object for current user role from form dropdown
             * 'advgb_blocks_list' object with all the saved blocks in 'advgb_blocks_list' option
             */
            $this->blocksFeatureData(
                'access',
                // The object name to store the active/inactive blocks. To see it in browser console: advgbCUserRole.access
                'advgb_blocks_user_roles' // Database option to check current user role's active/inactive blocks
            );

            $this->blocksUsageData();

            $this->blocksUsagePage();
        }

        /**
         * Block controls page
         *
         * @return void
         * @since 3.1.0
         */
        public function loadBlockControlsPage()
        {
            // Check users permissions
            if (! current_user_can('administrator')) {
                return false;
            }

            // Block controls is disabled
            if (! Utilities::settingIsEnabled('block_controls')) {
                wp_die(
                    sprintf(
                        esc_html__(
                            'This feature is disabled. In order to use, please enable back through %sDashboard%s.',
                            'advanced-gutenberg'
                        ),
                        '<a href="' . admin_url('admin.php?page=advgb_main') . '">',
                        '</a>'
                    )
                );
            }

            self::commonAdminPagesAssets();

            self::commonAdminPagesAssets();

            // Output blocks through javascript
            PublishPress\Blocks\Controls::adminData();

            $this->loadPage('block-controls');
        }

        /**
         * Block settings page
         *
         * @return void
         * @since 3.0.0
         */
        public function loadBlockSettingsPage()
        {
            if (! current_user_can('activate_plugins')) {
                return false;
            }

            // PublishPress blocks is disabled
            if (! Utilities::settingIsEnabled('enable_advgb_blocks')) {
                wp_die(
                    sprintf(
                        esc_html__(
                            'This feature is disabled. In order to use, please enable back through %sDashboard%s.',
                            'advanced-gutenberg'
                        ),
                        '<a href="' . admin_url('admin.php?page=advgb_main') . '">',
                        '</a>'
                    )
                );
            }

            self::commonAdminPagesAssets();
            $this->loadPage('block-settings');
        }

        /**
         * Email & form page
         *
         * @return void
         * @since 3.0.0
         */
        public function loadEmailFormPage()
        {
            if (! current_user_can('activate_plugins')) {
                return false;
            }

            self::commonAdminPagesAssets();
            $this->loadPage('email-form');
        }

        /**
         * Custom styles page
         *
         * @return void
         * @since 3.0.0
         */
        public function loadCustomStylesPage()
        {
            if (! current_user_can('activate_plugins')) {
                return false;
            }

            // Custom styles is disabled
            if (! Utilities::settingIsEnabled('enable_custom_styles')) {
                wp_die(
                    sprintf(
                        esc_html__(
                            'This feature is disabled. In order to use, please enable back through %sDashboard%s.',
                            'advanced-gutenberg'
                        ),
                        '<a href="' . admin_url('admin.php?page=advgb_main') . '">',
                        '</a>'
                    )
                );
            }

            wp_enqueue_script('less_js');
            wp_enqueue_script('advgb_codemirror_js');
            wp_enqueue_script('codemirror_hint');
            wp_enqueue_script('codemirror_mode_css');
            wp_enqueue_script('codemirror_hint_css');
            wp_enqueue_script('advgb_custom_styles_js');

            wp_localize_script(
                'advgb_custom_styles_js',
                'advgbCustomStyles',
                [
                    'isProActive' => Utilities::isProActive(),
                ]
            );

            wp_enqueue_style( 'advgb_custom_styles_css' );
            wp_enqueue_style('codemirror_css');
            wp_enqueue_style('codemirror_hint_style');

            self::commonAdminPagesAssets();
            $this->loadPage('custom-styles');
        }

        /**
         * PublishPress admin footer
         *
         * @return void
         * @since 3.0.0
         */
        public function adminFooter($footer)
        {
            global $current_screen;

            // When free and pro are active, avoid displaying our footer twice
            if (defined('ADVANCED_GUTENBERG_FOOTER_DISPLAYED')) {
                return $footer;
            }

            // Only display in PublishPress Blocks admin pages
            $pages = [
                'toplevel_page_advgb_main',
                'blocks_page_advgb_block_access',
                'blocks_page_advgb_block_usage',
                'blocks_page_advgb_block_settings',
                'blocks_page_advgb_custom_styles',
                'blocks_page_advgb_settings',
                'blocks_page_advgb_block_controls'
            ];
            if (! in_array($current_screen->base, $pages)) {
                return $footer;
            }

            $html = '';
            if (! defined('ADVANCED_GUTENBERG_PRO_LOADED') || Utilities::settingIsEnabled('enable_pp_branding')) {
                $html .= '<div class="advgb-footer">
                    <footer>
                        <div class="advgb-rating">
                            <a href="https://wordpress.org/support/plugin/advanced-gutenberg/reviews/#new-post"
                                target="_blank"
                                rel="noopener noreferrer"
                                class="ag-footer-link"
                            >' .
                         sprintf(
                             __(
                                 'If you like %sPublishPress Blocks%s please leave us a %s rating. Thank you!',
                                 'advanced-gutenberg'
                             ),
                             '<strong>',
                             '</strong>',
                             str_repeat('<span class="dashicons dashicons-star-filled"></span>', 5)
                         )
                         . '</a>
                        </div>
                        <hr>
                        <nav>
                            <ul>
                                <li>
                                    <a href="https://publishpress.com"
                                        target="_blank"
                                        rel="noopener noreferrer"
                                        title="' . esc_attr__('About PublishPress Blocks', 'advanced-gutenberg') . '"
                                        class="ag-footer-link"
                                    >' .
                         __('About', 'advanced-gutenberg')
                         . '</a>
                                </li>
                                <li>
                                    <a href="https://publishpress.com/knowledge-base/installation/"
                                        target="_blank"
                                        rel="noopener noreferrer"
                                        title="' . esc_attr__('Documentation', 'advanced-gutenberg') . '"
                                        class="ag-footer-link"
                                    >' .
                         __('Documentation', 'advanced-gutenberg')
                         . '
                                    </a>
                                </li>
                                <li>
                                    <a href="https://publishpress.com/contact"
                                        target="_blank"
                                        rel="noopener noreferrer"
                                        title="' . esc_attr__('Contact the PublishPress team', 'advanced-gutenberg') . '"
                                        class="ag-footer-link"
                                    >' .
                         __('Contact', 'advanced-gutenberg')
                         . '</a>
                                </li>
                            </ul>
                        </nav>
                        <div class="advgb-pressshack-logo">
                            <a href="https://publishpress.com" target="_blank" rel="noopener noreferrer">
                                <img src="' . esc_url(ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/images/publishpress-logo.png') . '"
                                 alt="' . esc_attr__('PublishPress Blocks logo', 'advanced-gutenberg') . '">
                            </a>
                        </div>
                    </footer>
                </div>';
            }

            // $footer is the "Thank you for creating with WordPress" text
            $footer = $html . $footer;

            if (! defined('ADVANCED_GUTENBERG_FOOTER_DISPLAYED')) {
                define('ADVANCED_GUTENBERG_FOOTER_DISPLAYED', true);
            }

            return $footer;
        }

        /**
         * Admin menu styles
         *
         * @return void
         * @since 3.1.0
         */
        public function adminMenuStyles()
        {
            wp_enqueue_style('advgb_admin_menu_styles');
        }

        /**
         * Let's save a trigger option when a new plugin has been activated
         * We use the boolean value of advgb_maybe_new_blocks option
         * to trigger an update for advgb_blocks_list option through initBlocksList()
         *
         * @return void
         * @since 3.1.4.2
         *
         */
        public function maybeNewBlocks($plugin, $network_activation)
        {
            update_option('advgb_maybe_new_blocks', intval(true), false);
        }

        /**
         * Register meta data to use on editor sidebar
         *
         * @return void
         */
        public function registerPostMeta()
        {
            register_post_meta(
                '',
                'advgb_blocks_editor_width',
                array(
                    'show_in_rest' => true,
                    'single'       => true,
                    'type'         => 'string',
                )
            );

            register_post_meta(
                '',
                'advgb_blocks_columns_visual_guide',
                array(
                    'show_in_rest' => true,
                    'single'       => true,
                    'type'         => 'string',
                )
            );
        }

        /**
         * Get a setting from a database option and return a working value
         * to output in an HTML form
         *
         * @param string $option Database option name. e.g. 'advgb_settings'
         * @param mixed $name Setting name - e.g. 'lorem' from advgb_settings option
         * @param string $type $setting field type. 'checkbox' or 'text'
         * @param mixed $default Default value when $setting doesn't exist in $option
         *
         * @return mixed
         * @since 3.0.0
         */
        public function getOptionSetting($option, $name, $type, $default)
        {
            $settings = get_option($option);
            switch ($type) {
                case 'checkbox':
                    $result = isset($settings[ $name ]) && $settings[ $name ] ? 'checked' : '';
                    if (! isset($settings[ $name ]) && $default === 1) {
                        $result = 'checked';
                    }
                    break;
                case 'text': // For input types: text, number and textarea
                    $result = isset($settings[ $name ]) && ! empty($settings[ $name ]) ? $settings[ $name ] : $default;
                    break;
                case 'array':
                    $result = isset($settings[ $name ]) && ! empty($settings[ $name ]) ? (array) $settings[ $name ] : $default;
                    break;
            }

            return $result;
        }

        /**
         * Convert Editor Width value into a string
         *
         * @param int $value Editor width number
         *
         * @return string
         */
        public function getAdvgbEditorWidth($value)
        {
            $result = '';

            switch ($value) {
                default:
                    $result = 'default';
                    break;
                case '75':
                    $result = 'large';
                    break;
                case '95':
                    $result = 'full';
                    break;
            }

            return $result;
        }

        /**
         * Get Global Columns Visual Guide
         *
         * @deprecated 3.2.0 - Use colsVisualGuideGlobal() instead
         *
         * @param int $value Columns Visual Guide check
         *
         * @return string
         */
        public function getAdvgbColsVisualGuideGlobal($value)
        {
            return ( isset($value) && ( $value == 0 ) ) ? 'disable' : 'enable';
        }

        /**
         * Get Global Columns Visual Guide (new method)
         *
         * @since 3.2.0
         *
         * @return string
         */
        public function colsVisualGuideGlobal()
        {
            $saved_settings = get_option('advgb_settings');

            return isset($saved_settings['enable_columns_visual_guide'])
                && ! (bool) $saved_settings['enable_columns_visual_guide']
                ? 'disable'
                : 'enable';
        }

        /**
         * Set body classes for Editor width and Columns visual guide
         *
         * @param string $classes CSS class from body
         */
        public function setAdvgEditorBodyClassses($classes)
        {
            $saved_settings = get_option('advgb_settings');

            if ('post' === get_current_screen()->base) {
                $saved_settings = get_option('advgb_settings');
                global $post;
                $editorWidth        = get_post_meta($post->ID, 'advgb_blocks_editor_width', true);
                $editorColsVG       = get_post_meta($post->ID, 'advgb_blocks_columns_visual_guide', true);
                $editorWidthGlobal  = isset($saved_settings['editor_width'])
                                      && ! empty($saved_settings['editor_width'])
                    ? $this->getAdvgbEditorWidth($saved_settings['editor_width'])
                    : 'default';
                $editorColsVGGlobal = $this->colsVisualGuideGlobal();

                // Editor width
                if (isset($editorWidth) && ! empty($editorWidth)) {
                    // Editor width - Post meta
                    $classes .= ' advgb-editor-width-' . $editorWidth . ' ';
                } else {
                    // Editor width - Global configuration
                    $classes .= ' advgb-editor-width-' . $editorWidthGlobal . ' ';
                }

                // Columns visual guide
                if (isset($editorColsVG) && ! empty($editorColsVG)) {
                    // Columns visual guide - Post meta
                    $classes .= ' advgb-editor-col-guide-' . $editorColsVG . ' ';
                } else {
                    // Columns visual guide - Global configuration
                    $classes .= ' advgb-editor-col-guide-' . $editorColsVGGlobal . ' ';
                }

                return $classes;
            } elseif ('widgets' === get_current_screen()->id) {
                // Use global Columns Visual Guide in Appearance > Widgets
                $editorColsVGGlobal = $this->colsVisualGuideGlobal();
                $classes            .= ' advgb-editor-col-guide-' . $editorColsVGGlobal;
            }

            return $classes;
        }

        /**
         * Save settings page data
         *
         * @return mixed
         * @since 3.0.0
         */
        public function advgb_settings_save_page()
        {
            if (! current_user_can('activate_plugins')) {
                return false;
            }

            // General settings
            if (isset($_POST['save_settings_general'])) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- we check nonce below
                if (
                    ! wp_verify_nonce(
                        sanitize_key($_POST['advgb_settings_general_nonce_field']),
                        'advgb_settings_general_nonce'
                    )
                ) {
                    return false;
                }

                $advgb_settings = get_option('advgb_settings');

                $advgb_settings['enable_blocks_spacing']       = isset($_POST['enable_blocks_spacing']) ? 1 : 0;
                $advgb_settings['disable_wpautop']             = isset($_POST['disable_wpautop']) ? 1 : 0; // @TODO Remove later
                $advgb_settings['enable_columns_visual_guide'] = isset($_POST['enable_columns_visual_guide']) ? 1 : 0;
                $advgb_settings['blocks_spacing']              = (int) $_POST['blocks_spacing'];
                $advgb_settings['blocks_icon_color']           = sanitize_hex_color($_POST['blocks_icon_color']);
                $advgb_settings['editor_width']                = sanitize_text_field($_POST['editor_width']);

                // Pro
                if (defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                    if (
                        method_exists(
                            'PPB_AdvancedGutenbergPro\Utils\Definitions',
                            'advgb_pro_setting_set_value'
                        )
                    ) {
                        $advgb_settings['enable_pp_branding'] = PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_setting_set_value('enable_pp_branding');
                    }
                }

                update_option('advgb_settings', $advgb_settings);

                if (isset($_REQUEST['_wp_http_referer'])) {
                    wp_safe_redirect(admin_url('admin.php?page=advgb_settings&tab=general&save=success'));
                    exit;
                }
            } // Images settings
            elseif (isset($_POST['save_settings_images'])) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- we check nonce below
                if (
                    ! wp_verify_nonce(
                        sanitize_key($_POST['advgb_settings_images_nonce_field']),
                        'advgb_settings_images_nonce'
                    )
                ) {
                    return false;
                }

                $advgb_settings = get_option('advgb_settings');

                $advgb_settings['gallery_lightbox']         = isset($_POST['gallery_lightbox']) ? 1 : 0;
                $advgb_settings['gallery_lightbox_caption'] = (int) $_POST['gallery_lightbox_caption'];
                $advgb_settings['rp_default_thumb']         = [
                    'url' => esc_url_raw($_POST['post_default_thumb']),
                    'id'  => (int) $_POST['post_default_thumb_id']
                ];

                update_option('advgb_settings', $advgb_settings);

                if (isset($_REQUEST['_wp_http_referer'])) {
                    wp_safe_redirect(admin_url('admin.php?page=advgb_settings&tab=images&save=success'));
                    exit;
                }
            } // Images settings
            elseif (isset($_POST['save_settings_block_features'])) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- we check nonce below
                if (
                    ! wp_verify_nonce(
                        sanitize_key($_POST['advgb_settings_block_features_nonce_field']),
                        'advgb_settings_block_features_nonce'
                    )
                ) {
                    return false;
                }

                $advgb_settings = get_option('advgb_settings');

                $advgb_settings['block_features_settings'] = isset($_POST['block_features_settings']) ? map_deep($_POST['block_features_settings'], 'sanitize_text_field') : [];
                $advgb_settings['setting_last_saved_role'] = isset($_POST['setting_last_saved_role']) ? sanitize_key($_POST['setting_last_saved_role']) : '';

                update_option('advgb_settings', $advgb_settings);

                if (isset($_REQUEST['_wp_http_referer'])) {
                    wp_safe_redirect(admin_url('admin.php?page=advgb_settings&tab=block-features&save=success'));
                    exit;
                }
            } // Maps settings
            elseif (isset($_POST['save_settings_maps'])) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- we check nonce below
                if (
                    ! wp_verify_nonce(
                        sanitize_key($_POST['advgb_settings_maps_nonce_field']),
                        'advgb_settings_maps_nonce'
                    )
                ) {
                    return false;
                }

                $advgb_settings = get_option('advgb_settings');

                $advgb_settings['google_api_key'] = sanitize_text_field($_POST['google_api_key']);

                update_option('advgb_settings', $advgb_settings);

                if (isset($_REQUEST['_wp_http_referer'])) {
                    wp_safe_redirect(admin_url('admin.php?page=advgb_settings&tab=maps&save=success'));
                    exit;
                }
            } // Email & forms settings
            elseif (isset($_POST['save_email_config'])) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- we check nonce below
                if (! isset($_POST['advgb_email_config_nonce_field'])) {
                    return false;
                }

                if (
                    ! wp_verify_nonce(
                        sanitize_key($_POST['advgb_email_config_nonce_field']),
                        'advgb_email_config_nonce'
                    )
                ) {
                    return false;
                }

                $save_config                                = [];
                $save_config['contact_form_sender_name']    = sanitize_text_field($_POST['contact_form_sender_name']);
                $save_config['contact_form_sender_email']   = sanitize_email($_POST['contact_form_sender_email']);
                $save_config['contact_form_email_title']    = sanitize_text_field($_POST['contact_form_email_title']);
                $save_config['contact_form_email_receiver'] = sanitize_email($_POST['contact_form_email_receiver']);

                update_option('advgb_email_sender', $save_config);

                if (isset($_REQUEST['_wp_http_referer'])) {
                    wp_safe_redirect(
                        admin_url('admin.php?page=advgb_settings&tab=forms&save=success')
                    );
                    exit; // @TODO - Do we really need this?
                }
            } // reCAPTCHA settings
            elseif (isset($_POST['save_recaptcha_config'])) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- we check nonce below
                if (! isset($_POST['advgb_captcha_nonce_field'])) {
                    return false;
                }

                if (
                    ! wp_verify_nonce(
                        sanitize_key($_POST['advgb_captcha_nonce_field']),
                        'advgb_captcha_nonce'
                    )
                ) {
                    return false;
                }

                $save_config = [];
                if (isset($_POST['recaptcha_enable'])) {
                    $save_config['recaptcha_enable'] = 1;
                } else {
                    $save_config['recaptcha_enable'] = 0;
                }
                $save_config['recaptcha_site_key']   = sanitize_text_field($_POST['recaptcha_site_key']);
                $save_config['recaptcha_secret_key'] = sanitize_text_field($_POST['recaptcha_secret_key']);
                $save_config['recaptcha_language']   = sanitize_text_field($_POST['recaptcha_language']);
                $save_config['recaptcha_theme']      = sanitize_text_field($_POST['recaptcha_theme']);

                update_option('advgb_recaptcha_config', $save_config);

                if (isset($_REQUEST['_wp_http_referer'])) {
                    wp_safe_redirect(
                        admin_url('admin.php?page=advgb_settings&tab=recaptcha&save=success')
                    );
                    exit;
                }
            } // Data export
            elseif (isset($_POST['block_data_export'])) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- we check nonce below
                if (
                    ! wp_verify_nonce(
                        sanitize_key($_POST['advgb_export_data_nonce_field']),
                        'advgb_export_data_nonce'
                    )
                ) {
                    return false;
                }

                $postValue  = sanitize_text_field($_POST['block_data_export']);
                $postValue  = explode('.', $postValue);
                $dataExport = $postValue[0];
                $dataType   = $postValue[1];

                if ($dataExport === 'contact_form') {
                    $dataSaved = get_option('advgb_contacts_saved');
                    if (! is_array($dataSaved) || ! $dataSaved) {
                        return false;
                    }

                    return $this->downloadContactFormData( $dataSaved, $dataType );
                } elseif ($dataExport === 'newsletter') {
                    $dataSaved = get_option('advgb_newsletter_saved');
                    if (! is_array($dataSaved) || ! $dataSaved) {
                        return false;
                    }

                    return $this->downloadNewsletterData( $dataSaved, $dataType );
                }

                return false;
            }

            return false;
        }

        /**
         * Save block access page data
         * Name is build in registerMainMenu() > $function_name
         *
         * @return boolean true on success, false on failure
         * @since 3.0.0
         */
        public function advgb_block_access_save_page()
        {
            if (! current_user_can('activate_plugins')) {
                return false;
            }

            if ( isset( $_POST['advgb_block_access_save'] ) ) {
                // Save Block Access for single role
                $this->blocksFeatureSave(
                    'access',
                    'advgb_blocks_user_roles'
                );
                return true;
            }

            if ( isset( $_POST['advgb_block_access_save_all_roles'] ) ) {
                // Save Block Access for all roles
                $this->blocksFeatureSaveAllRoles(
                    'access',
                    'advgb_blocks_user_roles'
                );
                return true;
            }

            return false;
        }

        /**
         * Save block controls page data
         * Name is build in registerMainMenu() > $function_name
         *
         * @return boolean true on success, false on failure
         * @since 3.1.0
         */
        public function advgb_block_controls_save_page()
        {
            PublishPress\Blocks\Controls::save();
        }

        /**
         * Load Block Styles in <head> in frontend
         *
         * @return void
         */
        public function loadCustomStylesFrontend()
        {
            $post_content = get_the_content();
            $this->getCustomStylesContent($post_content);
            // @TODO Check for Custom styles in use in Widgets
        }

        /**
         * Get Block Styles in use in Contennt
         *
         * @return string
         */
        public function getCustomStylesContent($content) {
            if (!Utilities::settingIsEnabled('enable_custom_styles')) {
                return '';
            }
            $custom_styles = get_option('advgb_custom_styles', AdvancedGutenbergBlockStyles::$default_custom_styles);

            if (is_array($custom_styles)) {
                $css = '';

                foreach ($custom_styles as $styles) {
                    if (isset($styles['generated_css']) && !empty($styles['generated_css'])) {
                        $css .= $styles['generated_css'];
                    } else {
                        // Fallback: generate CSS on the fly for legacy data
                        $css .= AdvancedGutenbergBlockStyles::generate_final_css($styles['css'], $styles['name']);
                    }
                }

                if (!empty($css)) {
                    echo '<style type="text/css">' . AdvancedGutenbergBlockStyles::sanitize_css($css) . '</style>';
                }
            }
        }

        private function getAdminEditorCustomStyles() {

            $content = '';
            $custom_styles = get_option('advgb_custom_styles', AdvancedGutenbergBlockStyles::$default_custom_styles);

            if (is_array($custom_styles)) {
                foreach ($custom_styles as $styles) {
                    // post editor
                    $class_name = '.block-editor-writing-flow .' . $styles['name'];
                    // resusable block editor
                    $class_name .= ', .editor-visual-editor iframe .' . $styles['name'];
                    $class_name .= ', .block-editor-iframe__body .' . $styles['name'];

                    if (isset($styles['generated_css']) && !empty($styles['generated_css'])) {
                        $admin_css = str_replace('.' . $styles['name'], $class_name, $styles['generated_css']);
                        $content .= $admin_css;
                    } else {
                        // Fallback: generate CSS on the fly for legacy data
                        $content .= AdvancedGutenbergBlockStyles::generate_final_css($styles['css'], $class_name);
                    }
                }
            }

            return $content;

        }

        /**
         * Load Block Styles in <head> in admin
         *
         * @return void
         */
        public function loadCustomStylesAdmin() {
            if (!Utilities::settingIsEnabled('enable_custom_styles')) {
                return;
            }

            $custom_styles = $this->getAdminEditorCustomStyles();

            if (!empty($custom_styles)) {
                echo '<style type="text/css">' . AdvancedGutenbergBlockStyles::sanitize_css($custom_styles) . '</style>';
            }
        }

        public function addCustomStylesToReusableBlocks() {

            if (!Utilities::settingIsEnabled('enable_custom_styles')) {
                return;
            }

            if (get_post_type() === 'wp_block') {
                add_filter('block_editor_settings_all', function($settings) {

                    $custom_styles = $this->getAdminEditorCustomStyles();

                    if (!empty($custom_styles)) {
                        if (!isset($settings['styles'])) {
                            $settings['styles'] = [];
                        }

                        $settings['styles'][] = [
                            'css' => $custom_styles,
                        ];
                    }

                    return $settings;
                }, 20);
            }
        }

        /**
         * Set blocks spacing in editor
         *
         * @return void
         */
        public function setBlocksSpacingAdmin()
        {
            $saved_settings = get_option('advgb_settings');

            if (isset($saved_settings['enable_blocks_spacing']) && $saved_settings['enable_blocks_spacing']) {
                $blocks_spacing = isset($saved_settings['blocks_spacing']) ? $saved_settings['blocks_spacing'] : 0;
                echo '<style type="text/css">.editor-styles-wrapper [data-block] { margin-bottom: ' . esc_html($blocks_spacing) . 'px !important; }</style>';
            }
        }

        /**
         * Save block [feature] by user role - e.g. access feature means enable/disable blocks in editor
         *
         * @param string $feature Feature name in lowercase - e.g. 'access'
         * @param string $option Database option to update - e.g. 'advgb_blocks_user_roles'
         *
         * @return void
         * @since 3.0.0
         */
        public function blocksFeatureSave($feature, $option)
        {
            // Check nonce field exist
            if (! isset($_POST[ 'advgb_block_' . $feature . '_nonce_field' ])) {
                return false;
            }
            // Verify nonce
            if (
                ! wp_verify_nonce(
                    sanitize_key($_POST[ 'advgb_block_' . $feature . '_nonce_field' ]),
                    'advgb_nonce'
                )
            ) {
                return false;
            }

            if (! current_user_can('administrator')) {
                return false;
            }

            $user_role = !empty($_POST['user_role']) ? sanitize_text_field($_POST['user_role']) : '';

            if (
                isset($_POST['blocks_list'])
                && isset($_POST['active_blocks'])
                && is_array($_POST['active_blocks'])
                && isset($_POST['user_role'])
                && ! empty($_POST['user_role'])
            ) {
                // @TODO - Check if user role exists - https://gist.github.com/hlashbrooke/8f901da7c6f0d107add7
                $blocks_list     = array_map(
                    'sanitize_text_field',
                    json_decode(stripslashes($_POST['blocks_list'])) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
                );
                $active_blocks   = array_map('sanitize_text_field', $_POST['active_blocks']);
                $inactive_blocks = array_values(array_diff($blocks_list, $active_blocks));

                // Save feature by role
                $block_feature_by_role                                  = get_option($option);
                $block_feature_by_role[ $user_role ]['active_blocks']   = isset($active_blocks) ? $active_blocks : '';
                $block_feature_by_role[ $user_role ]['inactive_blocks'] = isset($inactive_blocks) ? $inactive_blocks : '';

                update_option($option, $block_feature_by_role, false);

                // Redirect with success message
                wp_safe_redirect(
                    add_query_arg(
                        [
                            'user_role' => $user_role,
                            'save'      => 'success'
                        ],
                        wp_get_referer()
                    )
                );
            } else {
                // Redirect with error message / Nothing was saved
                wp_safe_redirect(
                    add_query_arg(
                        [
                            'user_role' => $user_role,
                            'save'      => 'error'
                        ],
                        wp_get_referer()
                    )
                );
            }
        }

        /**
         * Save blocks feature for all roles
         *
         * @param string $feature        Feature name in lowercase
         * @param string $database_option Database option to update
         *
         * @return void
         * @since 3.5.2
         */
        public function blocksFeatureSaveAllRoles( $feature, $database_option ) {
            // Check nonce field exist
            if (! isset($_POST[ 'advgb_block_' . $feature . '_nonce_field' ])) {
                return false;
            }
            // Verify nonce
            if (
                ! wp_verify_nonce(
                    sanitize_key($_POST[ 'advgb_block_' . $feature . '_nonce_field' ]),
                    'advgb_nonce'
                )
            ) {
                return false;
            }

            if (! current_user_can('administrator')) {
                return false;
            }

            $user_role = !empty($_POST['user_role']) ? sanitize_text_field($_POST['user_role']) : '';

            if (
                isset($_POST['blocks_list'])
                && isset($_POST['active_blocks'])
                && is_array($_POST['active_blocks'])
                && isset($_POST['user_role'])
                && ! empty($_POST['user_role'])
            ) {
                $blocks_list     = array_map(
                    'sanitize_text_field',
                    json_decode(stripslashes($_POST['blocks_list'])) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
                );
                $active_blocks   = isset( $_POST['active_blocks'] ) ? array_map('sanitize_text_field', $_POST['active_blocks']) : [];
                $inactive_blocks = array_values(array_diff($blocks_list, $active_blocks));

                $all_roles = wp_roles()->roles;

                $blocks_user_roles = get_option( $database_option, array() );

                foreach ( $all_roles as $role_key => $role_data ) {
                    $blocks_user_roles[ $role_key ] = array(
                        'active_blocks'   => $active_blocks,
                        'inactive_blocks' => $inactive_blocks,
                    );
                }

                // Save to database
                update_option( $database_option, $blocks_user_roles, false );

                // Redirect with success message
                wp_safe_redirect(
                    add_query_arg(
                        [
                            'user_role' => $user_role,
                            'save'      => 'success'
                        ],
                        wp_get_referer()
                    )
                );
            } else {
                // Redirect with error message / Nothing was saved
                wp_safe_redirect(
                    add_query_arg(
                        [
                            'user_role' => $user_role,
                            'save'      => 'error'
                        ],
                        wp_get_referer()
                    )
                );
            }
        }

        /**
         * Return current select user role
         *
         * @return string
         * @since 2.14.1
         *
         */
        public function advgbBlocksFeatureCUserRole()
        {
            if (isset($_REQUEST['user_role']) && ! empty($_REQUEST['user_role'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- advgb_nonce in place
                return sanitize_text_field($_REQUEST['user_role']); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- advgb_nonce in place
            } else {
                return 'administrator';
            }
        }

        public function blocksUsageData()
        {

            // Block categories
            $blockCategories = array();
            if (function_exists('get_block_categories')) {
                $blockCategories = get_block_categories(get_post());
            } elseif (function_exists('gutenberg_get_block_categories')) {
                $blockCategories = gutenberg_get_block_categories(get_post());
            }

            // Block types
            $block_type_registry = \WP_Block_Type_Registry::get_instance();
            foreach ($block_type_registry->get_all_registered() as $block_name => $block_type) {
                if (! empty($block_type->editor_script)) {
                    wp_enqueue_script($block_type->editor_script);
                }
            }

            /* Get blocks saved in advgb_blocks_list option to include the ones that are missing
             * as result of javascript method wp.blocks.getBlockTypes()
             * e.g. blocks registered only via PHP
             */
            $saved_blocks = [];
            $advgb_blocks_list = get_option('advgb_blocks_list');
            if ($advgb_blocks_list && is_array($advgb_blocks_list)) {
                $saved_blocks = $advgb_blocks_list;
            } else {
                $saved_blocks = [];
            }
            wp_localize_script(
                'advgb_main_js',
                'advgb_blocks_list',
                $saved_blocks
            );

            $saved_blocks   = array_merge(
                $saved_blocks,
                (array) get_option('advgb_blocks_list')
            );


            wp_enqueue_style('wp-components');

            wp_enqueue_style(
                'advgb_block_usage_styles',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/block-usage.css',
                ['wp-components'],
                ADVANCED_GUTENBERG_VERSION
            );

            wp_enqueue_script(
                'advgb_block_usage',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/pages/block-usage.js',
                ['wp-element', 'wp-components', 'wp-api-fetch', 'wp-i18n'],
                ADVANCED_GUTENBERG_VERSION,
                true
            );


            $localize_data = [
                'ajaxUrl' => admin_url('admin-ajax.php'),
                'nonce' => wp_create_nonce('block_usage_nonce'),
                'blockCategories' => $blockCategories,
                'saved_blocks' => $saved_blocks,
                'postTypes' => $this->get_editor_post_types(),
                'isProActive' => Utilities::isProActive(),
                'promoLink' => ADVANCED_GUTENBERG_UPGRADE_LINK,
                'upgradeText'   => __( 'Upgrade to Pro', 'advanced-gutenberg' ),
                 'proText'   => __( 'Pro', 'advanced-gutenberg' ),
                'initialData' => [
                    'usage' => [],
                    'lastScanDate' => '',
                    'lastSelectedBlock' => '',
                    'posts' => []
                ],
                'currentUser' => [
                    'canEditPosts' => current_user_can('edit_posts')
                ]
            ];

            wp_localize_script(
                'advgb_block_usage',
                'advgb_block_usage_data',
                $localize_data
            );

            wp_set_script_translations(
                'advgb_block_usage',
                'advanced-gutenberg',
                plugin_dir_path(ADVANCED_GUTENBERG_PLUGIN) . 'languages'
            );
        }

        public function get_editor_post_types()
        {
            $post_types = get_post_types(['show_in_rest' => true], 'objects');
            $result = [];

            foreach ($post_types as $post_type) {
                if (post_type_supports($post_type->name, 'editor')) {
                    $result[$post_type->name] = $post_type->labels->singular_name;
                }
            }

            return $result;
        }

        /**
         * Access current user blocks and saved blocks to build 2 javascript objects.
         * 'advgbCUserRole' object for current user role from form dropdown
         * 'advgb_blocks_list' object with all the saved blocks in 'advgb_blocks_list' option
         *
         * @param string $feature The object name to store the active/inactive blocks - e.g. 'access' => advgbCUserRole.access
         * @param string $option Database option to check current user role's active/inactive blocks - e.g. 'advgb_blocks_user_roles'
         * @param array $exclude Blocks to exclude from appearing in the feature form (is different to inactive_blocks!). e.g. ['core/paragraph','core/list']
         *
         * @return void
         * @since 3.0.0
         */
        public function blocksFeatureData($feature, $option, $exclude = [])
        {
            // Build blocks form and add filters functions
            wp_add_inline_script(
                'advgb_main_js',
                "window.addEventListener('load', function () {
                    advgbGetBlocksFeature(
                        advgbCUserRole.{$feature}.inactive_blocks,
                        '#advgb_block_{$feature}_nonce_field',
                        'advgb_block_{$feature}',
                        " . wp_json_encode($exclude) . "
                    );
                });"
            );
            do_action('enqueue_block_editor_assets');

            // Block categories
            $blockCategories = array();
            if (function_exists('get_block_categories')) {
                $blockCategories = get_block_categories(get_post());
            } elseif (function_exists('gutenberg_get_block_categories')) {
                $blockCategories = gutenberg_get_block_categories(get_post());
            }
            wp_add_inline_script(
                'wp-blocks',
                sprintf('wp.blocks.setCategories( %s );', wp_json_encode($blockCategories)),
                'after'
            );

            // Block types
            $block_type_registry = \WP_Block_Type_Registry::get_instance();
            foreach ($block_type_registry->get_all_registered() as $block_name => $block_type) {
                if (! empty($block_type->editor_script)) {
                    wp_enqueue_script($block_type->editor_script);
                }
            }

            /* Get blocks saved in advgb_blocks_list option to include the ones that are missing
             * as result of javascript method wp.blocks.getBlockTypes()
             * e.g. blocks registered only via PHP
             */
            $advgb_blocks_list = get_option('advgb_blocks_list');
            if ($advgb_blocks_list && is_array($advgb_blocks_list)) {
                $saved_blocks = $advgb_blocks_list;
            } else {
                $saved_blocks = [];
            }
            wp_localize_script(
                'advgb_main_js',
                'advgb_blocks_list',
                $saved_blocks
            );

            // Current role
            $current_user_role = $this->advgbBlocksFeatureCUserRole();

            // Active and inactive blocks for current user role
            $block_feature_by_role = get_option($option);
            if (
                ! empty($block_feature_by_role[ $current_user_role ])
                && is_array($block_feature_by_role[ $current_user_role ])
            ) {
                wp_localize_script(
                    'wp-blocks',
                    'advgbCUserRole',
                    [
                        'user_role' => $current_user_role,
                        $feature    => [
                            'active_blocks'   => $block_feature_by_role[ $current_user_role ]['active_blocks'],
                            'inactive_blocks' => $block_feature_by_role[ $current_user_role ]['inactive_blocks']
                        ]
                    ]
                );
            } else {
                // Nothing saved in database for current user role. Set empty (access to all blocks)
                wp_localize_script(
                    'wp-blocks',
                    'advgbCUserRole',
                    [
                        'user_role' => $current_user_role,
                        $feature    => [
                            'active_blocks'   => [],
                            'inactive_blocks' => []
                        ]
                    ]
                );
            }
        }

        /**
         * Get the blocks feature form - e.g. Block Access
         *
         * @param string $feature Feature name in lowercase - e.g. 'access'
         * @param string $label Name of the feature with text-domain - e.g. __('Block Permissions', 'advanced-gutenberg')
         *
         * @return void
         * @since 3.0.0
         */
        public function blocksFeatureForm($feature, $label)
        {
            // Current role
            $current_user_role = $this->advgbBlocksFeatureCUserRole();
            ?>
            <div class="publishpress-admin wrap">
                <?php
                if (isset($_GET['save']) && $_GET['save'] === 'success') { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display message, no action ?>
                    <div id="message" class="updated fade">
                        <p>
                            <?php
                            printf(__('%s saved successfully!', 'advanced-gutenberg'), $label); ?>
                        </p>
                    </div>
                    <?php
                } elseif (isset($_GET['save']) && $_GET['save'] === 'error') { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- advgb_nonce in place
                    ?>
                    <div class="error">
                        <p>
                            <?php
                            printf(
                                __('%s can\'t be saved. Please try again.', 'advanced-gutenberg'),
                                $label
                            );
                            ?>
                        </p>
                    </div>
                    <?php
                } else {
                    // Nothing to do here
                }
                ?>
                <header>
                    <h1 class="wp-heading-inline">
                        <?php
                        echo $label; ?>
                    </h1>
                </header>
                <div class="wrap">
                    <form method="post">
                        <?php
                        wp_nonce_field('advgb_nonce', 'advgb_block_' . $feature . '_nonce_field'); ?>
                        <div class="advgb-roles-wrapper">
                            <?php
                            // Get current page slug
                            if (isset($_GET['page']) && $_GET['page']) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
                                $page_ = sanitize_text_field($_GET['page']);
                                ?>
                                <input type="hidden" name="advgb_page_slug" id="advgb_page_slug" value="<?php
                                echo esc_attr($page_) ?>"/>
                                <?php
                            } ?>
                            <input type="hidden" name="advgb_feature" id="advgb_feature" value="<?php
                            echo $feature ?>"/>
                            <div>
                                <select name="user_role" id="user_role">
                                    <?php
                                    global $wp_roles;
                                    $roles_list = $wp_roles->get_names();
                                    foreach ($roles_list as $roles => $role_name) :
                                        $role_name = translate_user_role($role_name);
                                        ?>
                                        <option value="<?php
                                        echo esc_attr($roles); ?>" <?php
                                        selected($current_user_role, $roles); ?>>
                                            <?php
                                            echo esc_html($role_name); ?>
                                        </option>
                                        <?php
                                    endforeach;
                                    ?>
                                </select>
                            </div>
                            <div class="advgb-search-wrapper">
                                <input type="text"
                                       class="blocks-search-input advgb-search-input"
                                       placeholder="<?php
                                        esc_attr_e('Search blocks', 'advanced-gutenberg') ?>"
                                >
                            </div>
                            <div class="advgb-toggle-wrapper">
                                <?php
                                _e('Enable or disable all blocks', 'advanced-gutenberg') ?>
                                <div class="advgb-switch-button">
                                    <label class="switch">
                                        <input type="checkbox" name="toggle_all_blocks" id="toggle_all_blocks">
                                        <span class="slider"></span>
                                    </label>
                                </div>
                            </div>
                            <div class="inline-button-wrapper">
                                <span class="advgb-enable-one-block-msg" style="display: none;">
                                    <span>
                                        <span>
                                            <?php
                                            esc_attr_e(
                                                'To save this configuration, enable at least one block.',
                                                'advanced-gutenberg'
                                            )
                                            ?>
                                        </span>
                                        <span class="dashicons dashicons-warning"></span>
                                    </span>
                                </span>
                                <button type="submit" name="advgb_block_<?php
                                        echo $feature ?>_save" class="button button-primary save-profile-button">
                                    <?php esc_html_e( 'Save Role Block Permissions', 'advanced-gutenberg' ); ?>
                                </button>
                                <button type="submit" name="advgb_block_<?php
                                        echo $feature ?>_save_all_roles" class="button button-secondary save-profile-button" style="margin-left: 10px;">
                                    <?php esc_html_e( 'Save Permission for all Roles', 'advanced-gutenberg' ); ?>
                                </button>
                            </div>
                        </div>

                        <!-- Blocks list -->
                        <div class="tab-content block-list-tab">
                            <div class="advgb-block-feature-loading-msg" style="display: block;">
                                <?php
                                _e('Loading...', 'advanced-gutenberg') ?>
                            </div>
                            <div class="blocks-section">
                                <input type="hidden" name="blocks_list" id="blocks_list"/>
                            </div>
                        </div>

                        <!-- Save button -->
                        <div class="advgb-form-buttons-bottom">
                            <button type="submit" name="advgb_block_<?php
                                    echo $feature ?>_save" class="button button-primary save-profile-button">
                                <?php esc_html_e( 'Save Role Block Permissions', 'advanced-gutenberg' ); ?>
                            </button>
                            <button type="submit" name="advgb_block_<?php
                                    echo $feature ?>_save_all_roles" class="button button-secondary save-profile-button" style="margin-left: 10px;">
                                <?php esc_html_e( 'Save Permission for all Roles', 'advanced-gutenberg' ); ?>
                            </button>
                            <span class="advgb-enable-one-block-msg" style="display: none;">
                                <span>
                                    <span class="dashicons dashicons-warning"></span>
                                    <span>
                                        <?php
                                        esc_attr_e(
                                            'To save this configuration, enable at least one block.',
                                            'advanced-gutenberg'
                                        )
                                        ?>
                                    </span>
                                </span>
                            </span>
                        </div>
                    </form>
                </div>
            </div>
            <?php
        }

        /**
         * Block Usage page
         */
        public function blocksUsagePage()
        {
            ?>
            <div class="publishpress-admin wrap">
                <header>
                    <h1 class="wp-heading-inline">
                        <?php esc_html_e('Block Usage', 'advanced-gutenberg'); ?>
                    </h1>
                    <button class="page-title-action button button-secondary" id="header-scan-button" style="vertical-align: unset;" disabled style="opacity: 0.5; cursor: not-allowed;">
                        <?php esc_html_e('Scan Block Usage', 'advanced-gutenberg'); ?>
                    </button>
                </header>

                <div class="wrap">
                    <div class="tab-content block-list-tab" id="advgb-block-usage-app">
                        <div class="advgb-block-feature-loading-msg" style="display: block;">
                            <?php _e('Loading...', 'advanced-gutenberg') ?>
                        </div>
                    </div>
                </div>
            </div>
            <?php
        }

        /**
         * Download block form data
         *
         * @return mixed
         */
        private function downloadBlockFormData()
        {
            // Verify nonce
            if (
                ! wp_verify_nonce(
                    sanitize_text_field($_POST['advgb_export_data_nonce_field']),
                    'advgb_export_data_nonce'
                )
            ) {
                return false;
            }

            $postValue  = sanitize_text_field($_POST['block_data_export']);
            $postValue  = explode('.', $postValue);
            $dataExport = $postValue[0];
            $dataType   = $postValue[1];

            if ($dataExport === 'contact_form') {
                $dataSaved = get_option('advgb_contacts_saved');
                if (! is_array($dataSaved) || ! $dataSaved) {
                    return false;
                }

                return $this->downloadContactFormData( $dataSaved, $dataType );
            } elseif ($dataExport === 'newsletter') {
                $dataSaved = get_option('advgb_newsletter_saved');
                if (! is_array($dataSaved) || ! $dataSaved) {
                    return false;
                }

                return $this->downloadNewsletterData( $dataSaved, $dataType );
            }

            return false;
        }

        /**
         * Download saved contact form entries.
         *
         * @param array  $data_saved Saved data.
         * @param string $data_type  Export type.
         *
         * @return false
         */
        private function downloadContactFormData( $data_saved, $data_type )
        {
            switch ( $data_type ) {
                case 'csv':
                    $rows = array();
                    $int  = 1;

                    foreach ( $data_saved as $data_val ) {
                        $rows[] = array(
                            $int,
                            $this->getSavedFormField( $data_val, 'date' ),
                            $this->getSavedFormField( $data_val, 'name' ),
                            $this->getSavedFormField( $data_val, 'email' ),
                            $this->getSavedFormField( $data_val, 'msg' ),
                        );
                        $int++;
                    }

                    $this->sendCsvDownload(
                        'advgb_contact_form-' . date( 'm-d-Y' ) . '.csv',
                        array( '#', 'Date', 'Name', 'Email', 'Message' ),
                        $rows
                    );
                    break;

                case 'json':
                    $this->sendJsonDownload( 'advgb_contact_form-' . date( 'm-d-Y' ) . '.json', $data_saved );
                    break;
            }

            return false;
        }

        /**
         * Download saved newsletter entries.
         *
         * @param array  $data_saved Saved data.
         * @param string $data_type  Export type.
         *
         * @return false
         */
        private function downloadNewsletterData( $data_saved, $data_type )
        {
            switch ( $data_type ) {
                case 'csv':
                    $rows = array();
                    $int  = 1;

                    foreach ( $data_saved as $data_val ) {
                        $rows[] = array(
                            $int,
                            $this->getSavedFormField( $data_val, 'date' ),
                            $this->getSavedFormField( $data_val, 'fname' ),
                            $this->getSavedFormField( $data_val, 'lname' ),
                            $this->getSavedFormField( $data_val, 'email' ),
                        );
                        $int++;
                    }

                    $this->sendCsvDownload(
                        'advgb_newsletter-' . date( 'm-d-Y' ) . '.csv',
                        array( '#', 'Date', 'First Name', 'Last Name', 'Email' ),
                        $rows
                    );
                    break;

                case 'json':
                    $this->sendJsonDownload( 'advgb_newsletter-' . date( 'm-d-Y' ) . '.json', $data_saved );
                    break;
            }

            return false;
        }

        /**
         * Send a CSV download using fputcsv.
         *
         * @param string $filename Download filename.
         * @param array  $headers  CSV headers.
         * @param array  $rows     CSV rows.
         *
         * @return void
         */
        private function sendCsvDownload( $filename, $headers, $rows )
        {
            header( 'Content-Type: text/csv; charset=utf-8' );
            header( 'Content-Disposition: attachment; filename=' . $filename );
            header( 'Pragma: no-cache' );
            header( 'Expires: 0' );

            $output = fopen( 'php://output', 'w' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
            if ( $output === false ) {
                exit;
            }

            fputcsv( $output, $headers, ',', '"', '\\' );

            foreach ( $rows as $row ) {
                fputcsv( $output, $this->neutralizeCsvRow( $row ), ',', '"', '\\' );
            }

            fclose( $output ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
            exit;
        }

        /**
         * Send a JSON download.
         *
         * @param string $filename Download filename.
         * @param array  $data     Export data.
         *
         * @return void
         */
        private function sendJsonDownload( $filename, $data )
        {
            header( 'Content-Type: application/json; charset=utf-8' );
            header( 'Content-Disposition: attachment; filename=' . $filename );
            header( 'Pragma: no-cache' );
            header( 'Expires: 0' );

            echo wp_json_encode( $data ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            exit;
        }

        /**
         * Get a saved form field without raising notices for legacy malformed rows.
         *
         * @param mixed  $entry Saved entry.
         * @param string $field Field name.
         *
         * @return string
         */
        private function getSavedFormField( $entry, $field )
        {
            if ( ! is_array( $entry ) || ! isset( $entry[ $field ] ) ) {
                return '';
            }

            return $entry[ $field ];
        }

        /**
         * Neutralize each CSV cell that spreadsheet apps may evaluate as a formula.
         *
         * @param array $row CSV row.
         *
         * @return array
         */
        private function neutralizeCsvRow( $row )
        {
            $neutralized = array();

            foreach ( $row as $value ) {
                $neutralized[] = $this->neutralizeCsvCell( $value );
            }

            return $neutralized;
        }

        /**
         * Prefix spreadsheet formula-leading CSV cells with a single quote.
         *
         * @param mixed $value CSV cell value.
         *
         * @return string
         */
        private function neutralizeCsvCell( $value )
        {
            if ( is_array( $value ) || is_object( $value ) ) {
                $value = wp_json_encode( $value );
                $value = $value === false ? '' : $value;
            }

            $value = (string) $value;
            if ( $value === '' ) {
                return '';
            }

            if ( preg_match( '/^[\t\r\n]/', $value ) || preg_match( '/^[\s]*[=+\-@]/', $value ) ) {
                return "'" . $value;
            }

            return $value;
        }

        /**
         * Retrieve the active and inactive blocks for users regard to PublishPress Blocks access
         *
         * @return array
         */
        public function getUserRoleBlocksData()
        {

            $user_roles_data = [
                'blocks' => false,
                'user_block_features' => false
            ];

            $blocks_data_completed = false;

            // Get user role
            if (is_multisite() && is_super_admin()) {
                /* Since a super admin in a child site from a multiste network doesn't have roles
                 * so we set 'administrator' as role */
                $current_user_role = 'administrator';
            } else {
                $current_user = wp_get_current_user();

                if (empty($current_user->roles) || empty($current_user->roles[0])) {
                    return $user_roles_data;
                }

                if (count($current_user->roles) === 1) {
                    // User has 1 user role
                    $current_user_role = $current_user->roles[0]; // string
                } elseif (count($current_user->roles) > 1) {
                    // User has 2 roles or more
                    $current_user_role = $current_user->roles; // array
                } else {
                    // Nothing to do here - no user roles
                    return $user_roles_data;
                }
            }

            // user block features
            $block_features_settings = $this->getOptionSetting('advgb_settings', 'block_features_settings', 'array', []);
            $block_features_settings_data = [];
            if (!empty($block_features_settings)) {
                foreach ($current_user->roles as $user_role) {
                    if (isset($block_features_settings[$user_role])) {
                        $role_settings = $block_features_settings[$user_role];
                        // Merge disable_block_adding
                        if (!empty($role_settings["disable_block_adding"])) {
                            $block_features_settings_data["disable_block_adding"] = $role_settings["disable_block_adding"];
                        }
                        // Merge disable_pattern_directory
                        if (!empty($role_settings["disable_pattern_directory"])) {
                            $block_features_settings_data["disable_pattern_directory"] = $role_settings["disable_pattern_directory"];
                        }
                        // Merge disable_openverse
                        if (!empty($role_settings["disable_openverse"])) {
                            $block_features_settings_data["disable_openverse"] = $role_settings["disable_openverse"];
                        }
                    }
                }
            }
            $user_roles_data['user_block_features'] = $block_features_settings_data;

            if (!Utilities::settingIsEnabled('enable_block_access')) {
                $blocks_data_completed = true;
            }

            if (!$blocks_data_completed) {
                // All saved blocks (even the ones possibly not detected by Block Permissions)
                $all_blocks = get_option('advgb_blocks_list');

                // Get the array from advgb_blocks_user_roles with all the Block permissions roles
                $advgb_blocks_user_roles = ! empty(get_option('advgb_blocks_user_roles')) ? get_option('advgb_blocks_user_roles') : [];

                // User has 1 user role - string
                if (gettype($current_user_role) === 'string') {
                    // Get the array from advgb_blocks_user_roles option that match current user role
                    $advgb_blocks_user_roles = array_key_exists(
                        $current_user_role,
                        $advgb_blocks_user_roles
                    ) ? (array) $advgb_blocks_user_roles[ $current_user_role ] : [];
                } else {
                    // User has 2 roles or more - array
                    $active_r_ = $inactive_r_ = [];
                    foreach ($current_user_role as $cur_) {
                        // Get the array from advgb_blocks_user_roles option that match current user role
                        if (array_key_exists($cur_, $advgb_blocks_user_roles)) {
                            $active_r_   = array_merge(
                                $active_r_,
                                (array) $advgb_blocks_user_roles[ $cur_ ]['active_blocks']
                            );
                            $inactive_r_ = array_merge(
                                $inactive_r_,
                                (array) $advgb_blocks_user_roles[ $cur_ ]['inactive_blocks']
                            );
                        }
                    }

                    // Remove duplicates
                    $active_r_   = array_unique($active_r_);
                    $inactive_r_ = array_unique($inactive_r_);

                    /* Remove active blocks if also exists as inactive in any of the assigned roles;
                    * only blocks activated in all the assigned roles will remain as active.
                    *
                    * Example:
                    *
                    * User has "Lorem" and "Ipsum" roles  assigned
                    *
                    * "Dolor block" is enabled for "Lorem" role but disabled for "Ipsum" role,
                    * then "Dolor block" is set as inactive [X].
                    *
                    * "Dolor block" is enabled for "Lorem" and also for "Ipsum" role,
                    * then "Dolor block" is set as active [✓].
                    * */
                    $active_r_ = array_diff($active_r_, $inactive_r_);

                    $advgb_blocks_user_roles = [
                        'active_blocks'   => array_values($active_r_),
                        'inactive_blocks' => array_values($inactive_r_)
                    ];
                }

                if (is_array($advgb_blocks_user_roles) && count($advgb_blocks_user_roles) > 0) {
                    if (
                        is_array($advgb_blocks_user_roles['active_blocks']) &&
                        is_array($advgb_blocks_user_roles['inactive_blocks'])
                    ) {
                        // Include the blocks stored in advgb_blocks_list option but not detected by Block Access
                        foreach ($all_blocks as $one_block) {
                            if (
                                ! in_array($one_block['name'], $advgb_blocks_user_roles['active_blocks']) &&
                                ! in_array($one_block['name'], $advgb_blocks_user_roles['inactive_blocks'])
                            ) {
                                array_push($advgb_blocks_user_roles['active_blocks'], $one_block['name']);
                            }
                        }
                    }

                    $user_roles_data['blocks'] = $advgb_blocks_user_roles;
                    $blocks_data_completed = true;
                }
            }

            if (!$blocks_data_completed) {
                // If advgb_blocks_user_roles option doesn't exists, then allow all blocks
                if (! is_array($all_blocks)) {
                    $all_blocks = array();
                } else {
                    // Extract block name only and skip the other properties (title, icon, category)
                    foreach ($all_blocks as $block_key => $block_value) {
                        $all_blocks[ $block_key ] = $all_blocks[ $block_key ]['name'];
                    }

                    // Include Legacy Widget for execution; this is not saved in db
                    array_push($all_blocks, 'core/legacy-widget');

                    // Remove duplicated just in case
                    $all_blocks = array_unique($all_blocks);
                }

                /* Make sure specific blocks are included as active - Since 2.11.6
                * core/widget-group added since 3.1.4.2
                * core/legacy-widget removed since 3.1.5
                */
                $include_blocks = [
                    'core/widget-group'
                ];

                foreach ($include_blocks as $item) {
                    if (! in_array($item, $all_blocks)) {
                        array_push(
                            $all_blocks,
                            $item
                        );
                    }
                }

                $user_roles_data['blocks'] = [
                    'active_blocks'   => $all_blocks,
                    'inactive_blocks' => array()
                ];
            }

            return $user_roles_data;
        }

        /**
         * Register block config page
         *
         * @return void
         */
        public function registerBlockConfigPage()
        {
            $advgb_block = array(
                'accordions',
                'button',
                'image',
                'list',
                'table',
                'video',
                'contact-form',
                'container',
                'count-up',
                'images-slider',
                'map',
                'newsletter',
                'recent-posts',
                'social-links',
                'summary',
                'adv-tabs',
                'testimonial',
                'woo-products',
                'columns',
                'column',
                'login-form',
                'search-bar',
                'icon',
                'infobox'
            );

            foreach ($advgb_block as $block) {
                add_submenu_page(
                    'admin.php?',
                    __('Block Config', 'advanced-gutenberg'),
                    __('Block Config', 'advanced-gutenberg'),
                    'manage_options',
                    'advgb-' . $block,
                    array( $this, 'loadBlockConfigView' )
                );
            }
        }

        /**
         * Function to get and load the block config view
         *
         * @param string $block View to load
         *
         * @return void
         */
        public function loadBlockConfigView($block = '')
        {
            if (! $block) {
                $block = sanitize_text_field($_GET['page']); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- view only
            }

            $core_styles = [ 'common', 'buttons', 'forms', 'edit' ];
            foreach ($core_styles as $style) {
                wp_enqueue_style($style);
            }

            wp_enqueue_style(
                'minicolors_css',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/jquery.minicolors.css'
            );
            wp_enqueue_style(
                'block_config_css',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/block-config.css'
            );
            $loadingImage = ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/images/loading.gif';
            wp_add_inline_style(
                'block_config_css',
                '#advgb-loading-screen-image {background-image: url(' . $loadingImage . ')}'
            );

            wp_enqueue_script(
                'minicolors_js',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/jquery.minicolors.min.js',
                array(),
                ADVANCED_GUTENBERG_VERSION
            );
            wp_enqueue_script(
                'block_config_js',
                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/block-config.js',
                array( 'jquery' ),
                ADVANCED_GUTENBERG_VERSION
            );

            $blocks_settings_list = PublishPress\Blocks\Configuration::defaultConfig();

            $advgb_blocks_default_config = get_option('advgb_blocks_default_config');
            $current_block               = $block;

            if (! isset($blocks_settings_list[ $current_block ])) {
                wp_die(esc_html(__(
                    'Default configuration for this block is not available.',
                    'advanced-gutenberg'
                )));

                return;
            }

            $current_block_settings       = $blocks_settings_list[ $current_block ];
            $current_block_settings_value = array();

            if ($advgb_blocks_default_config !== false) {
                if (isset($advgb_blocks_default_config[ $current_block ])) {
                    $current_block_settings_value = $advgb_blocks_default_config[ $current_block ];
                }
            }

            require_once(plugin_dir_path(__FILE__) . 'pages/block-settings/block-config.php');
        }

        /**
         * Function to get and load the page
         *
         * @param string $page Page to load
         *
         * @return void
         * @since 3.0.0
         */
        public function loadPage($page)
        {
            if (file_exists(plugin_dir_path(__FILE__) . 'pages/' . $page . '.php')) {
                include_once(plugin_dir_path(__FILE__) . 'pages/' . $page . '.php');
            }
        }

        /**
         * Function to get and load a tab inside a page
         *
         * @param string $page Page folder where tab files are stored
         * @param string $tab Tab to load
         *
         * @return void
         * @since 3.0.0
         */
        public function loadPageTab($page, $tab, $default = 'general')
        {

            $valid_tab = true;
            if (!preg_match('/^[a-zA-Z0-9_-]+$/', $tab)) {
                $valid_tab = false;
            }
            if ($valid_tab && file_exists(plugin_dir_path(__FILE__) . 'pages/' . $page . '/' . $tab . '.php')) {
                include_once(plugin_dir_path(__FILE__) . 'pages/' . $page . '/' . $tab . '.php');
            } elseif (
                $valid_tab &&
                defined('ADVANCED_GUTENBERG_BASE_PRO_PATH') &&
                file_exists(ADVANCED_GUTENBERG_BASE_PRO_PATH . '/incl/pages/' . $page . '/' . $tab . '.php')
            ) {
                // Maybe is a pro page? Look in another location
                include_once(ADVANCED_GUTENBERG_BASE_PRO_PATH . '/incl/pages/' . $page . '/' . $tab . '.php');
            } else {
                wp_add_inline_style(
                    'advgb_admin_styles',
                    '.publishpress-admin .nav-tab-wrapper { display: none !important; }'
                );
                printf(
                    __('Page not found. Go to %sDashboard%s', 'advanced-gutenberg'),
                    '<a href="' . admin_url('admin.php?page=advgb_main') . '">',
                    '</a>'
                );
            }
        }

        /**
         * Function to build tabs menu
         *
         * @param string $page Page slug. e.g. 'advgb_settings'
         * @param string $active Active tab slug. e.g. 'recaptcha'
         * @param array $tabs Tabs list
         *
         * @return string
         * @since 3.0.0
         */
        public function buildTabs($page, $active, $tabs)
        {
            if (! is_array($tabs) || empty($tabs)) {
                return '';
            }

            $html = '<ul class="nav-tab-wrapper">';
            foreach ($tabs as $tab) {
                $html .= '<li class="nav-tab' . ( $tab['slug'] === $active ? ' nav-tab-active' : '' ) . '">
                    <a href="' . admin_url('admin.php?page=' . $page . '&tab=' . $tab['slug']) . '">
                        ' . esc_html($tab['title']) . '
                    </a>
                </li>';
            }
            $html .= '</ul>';

            return $html;
        }

        /**
         * Function to load assets for post/page on front-end before gutenberg rendering
         *
         * @param array $block Block data
         *
         * @return array       New block data
         */
        public function contentPreRender($block)
        {
            // Search for needed blocks then add styles to it
            $style = $this->addBlocksStyles($block);

            /* Content Display block doesn't render styles
             * as the rest of blocks as first level block (not as a child),
             * so we add the inline CSS in head */
            if (
                $block['blockName'] === 'advgb/recent-posts'
                && ! empty($style)
            ) {
                wp_add_inline_style(
                    'advgb_recent_posts_styles',
                    strip_tags($style)
                );
            } else {
                // Rest of the blocks
                array_push($block['innerContent'], $style);
            }

            return $block;
        }

        /**
         * Recursive loop to find nested blocks and load their blocks's CSS and media files
         *
         * @param object $block Nested block
         * @param string $style_html CSS Styles
         * @param integer $level Nested block level
         *
         * @return  string              CSS Styles
         * @since   2.6.1
         */
        public function advgb_getNestedBlocksStyles($block, $level = 2, &$style_html = array())
        {
            if (isset($block['innerBlocks'])) {
                foreach ($block['innerBlocks'] as $key => $inner_block) {
                    // Get styles
                    $new_style_html = $this->advgb_SetStylesForBlocks(
                        $inner_block['attrs'],
                        $inner_block['blockName']
                    );

                    // Add the styles to the array
                    $style_html[] = $new_style_html;
                    //echo str_repeat("--", $level) . $inner_block['blockName'] . ' [ ' . $level . ' ]<br>';

                    self::advgb_getNestedBlocksStyles($inner_block, $level + 1, $style_html);
                }
            }

            $final_styles = $style_html;
            if (! is_string($final_styles)) {
                // Convert array to string
                $final_styles = implode('', array_unique($style_html));
            }

            //echo '<code>' . $final_styles . '</code>'; // This output is correct!

            return $final_styles;
        }

        /**
         * @TODO Remove later
         * Check to disable autop used to prevent unwanted paragraphs to blocks
         *
         * @param string $filter_name filter name; 'the_content' or 'widget_block_content'
         *
         * @return void
         */
        public function checkToDisableWpautop($filter_name)
        {
            $saved_settings = false;
            if (has_filter($filter_name, 'wpautop')) {
                if (! $saved_settings) {
                    $saved_settings = get_option('advgb_settings');
                }

                if (! empty($saved_settings['disable_wpautop'])) {
                    remove_filter($filter_name, 'wpautop');
                }
            }
        }

        /**
         * Add nonce to blocks with form tag
         *
         * @param string $content Post content
         *
         * @return string
         */
        public function addNonceToFormBlocks($block)
        {
            $nonce_field = '<input type="hidden" name="advgb_blockform_nonce_field" value="' . wp_create_nonce('advgb_blockform_nonce_field') . '">';

            $block = str_replace(
                '<div class="advgb-form-submit-wrapper"',
                $nonce_field . '<div class="advgb-form-submit-wrapper"',
                $block
            );

            $block = str_replace(
                '<div class="advgb-lores-field advgb-lores-submit-wrapper"',
                $nonce_field . '<div class="advgb-lores-field advgb-lores-submit-wrapper"',
                $block
            );

            return $block;
        }

        /**
         * Load assets for post/page on front-end after gutenberg rendering
         *
         * @param string $content Post content
         *
         * @return string
         */
        public function addFrontendContentAssets($content)
        {
            $this->checkToDisableWpautop('the_content');
            $this->setFrontendAssets($content);
            $content = $this->groupStylesTag($content);

            return $content;
        }

        /**
         * Load assets for widgets on front-end after gutenberg rendering
         *
         * @param string $text Widget content
         *
         * @return string
         */
        public function addFrontendWidgetAssets($text)
        {
            $this->checkToDisableWpautop('widget_block_content');
            $this->setFrontendAssets($text);
            $text = $this->groupStylesTag($text, false);

            return $text;
        }

        /**
         * Set frontend assets and styles for posts
         *
         * @param string $content Post content
         *
         * @return string
         */
        public function setFrontendAssets($content)
        {
            wp_enqueue_script(
                'jquery',
                'https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'
            ); // @TODO - Load locally

            // Preview in Customizer > Widgets
            if (isset($_GET['customize_theme'])) {
                wp_enqueue_style('colorbox_style');
                wp_enqueue_style('slick_style');
                wp_enqueue_style('slick_theme_style');

                wp_enqueue_script('colorbox_js');
                wp_enqueue_script('slick_js');
                wp_enqueue_script('advgb_masonry_js');

                wp_enqueue_script(
                    'advgb_widgets_customizer_js',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/widgets-customizer.js',
                    array(
                        'colorbox_js',
                        'slick_js',
                        'advgb_masonry_js'
                    ),
                    ADVANCED_GUTENBERG_VERSION
                );

                // Pro
                if (defined('ADVANCED_GUTENBERG_PRO_LOADED') && Utilities::settingIsEnabled('enable_advgb_blocks')) {
                    if (
                        method_exists(
                            'PPB_AdvancedGutenbergPro\Utils\Definitions',
                            'advgb_pro_widgets_customizer_frontend'
                        )
                    ) {
                        PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_widgets_customizer_frontend();
                    }
                }

                // Patch for Twenty Twenty-One
                $this->fixCssGridFooterWidgets();
            }

            // @TODO Support for Site Editor generated pages
            if (strpos($content, 'wp-block-advgb-count-up') !== false) {
                $content = preg_replace_callback(
                    '@<div[^>]*?advgb\-count\-up\-columns.*?(</p></div>)@s',
                    array( $this, 'decodeHtmlEntity' ),
                    $content
                );
            }

            // @TODO Support for Site Editor generated pages
            if (strpos($content, 'advgb-accordion-wrapper') !== false) {
                $content = preg_replace_callback(
                    '@<div[^>]*?advgb\-accordion\-wrapper.*?(</div></div>.?</div>)@s',
                    array( $this, 'decodeHtmlEntity' ),
                    $content
                );
            }

            // @TODO Support for Site Editor generated pages
            if (strpos($content, 'advgb-tabs-wrapper') !== false) {
                // Fix broken tags: &lt;strong> and &lt;em>
                $content = preg_replace_callback(
                    array(
                        '@<ul class="advgb-tabs-panel">(.*?)&lt;(?:strong|em)>(.*?)&lt;/(?:strong|em)>(.*?)</ul>@s',
                        '@<div class="advgb-tab-body-header">(.*?)&lt;(?:strong|em)>(.*?)&lt;/(?:strong|em)>(.*?)</div>@s'
                    ),
                    array( $this, 'decodeHtmlEntity' ),
                    $content
                );
            }

            // @TODO Support for Site Editor generated pages
            if (strpos($content, 'advgb-testimonial') !== false) {
                $content = preg_replace_callback(
                    '@<div[^>]*?advgb\-testimonial.*?(</p></div></div>)@s',
                    array( $this, 'decodeHtmlEntity' ),
                    $content
                );
            }

            return $content;
        }

        /**
         * Add styles for Adv Button and Adv List
         *
         * @param array $block Block data
         *
         * @return string HTML style
         */
        public function addBlocksStyles($block)
        {
            $style_html = '';
            $blockName  = $block['blockName'];
            $blockAttrs = $block['attrs'];

            if ($blockName) {
                // Get styles for parent blocks
                $style_html .= $this->advgb_SetStylesForBlocks($blockAttrs, $blockName);

                // Parse styles for nested blocks in WP 5.5+
                global $wp_version;
                if ($wp_version >= 5.5) {
                    // Check blocks in 2nd level and beyond
                    $style_html .= $this->advgb_getNestedBlocksStyles($block);
                }
            }

            $style_html = $style_html ? '<style type="text/css" class="advgb-blocks-styles-renderer">' . $style_html . '</style>' : '';

            return preg_replace('/\s\s+/', '', $style_html);
        }

        /**
         * Find all style tag and append them in the end of content
         *
         * @param string $content Content to be prettify
         * @param boolean $is_post if the content is false, is a widget
         *
         * @return string          New prettified string
         */
        public function groupStylesTag($content, $is_post = true)
        {
            // Group styles tag in the end of the content
            preg_match_all('/(<style.*?>)(.*?)(<\/style>)/mis', $content, $styles_html);
            $styles_tag = '';
            if (count($styles_html[0])) {
                foreach ($styles_html[0] as $key => $style_html) {
                    $content    = str_replace($style_html, '', $content);
                    $styles_tag .= $styles_html[2][ $key ];
                }
            }

            if ($styles_tag) {
                $content .= '<style class="advgb-styles-renderer' . ( $is_post === false ? '-widget' : '' ) . '">' . $styles_tag . '</style>';
            }

            return $content;
        }

        /**
         * Convert html entity to real character
         *
         * @param string $match Matched string
         *
         * @return mixed
         */
        public function decodeHtmlEntity($match)
        {
            return str_replace('&lt;', '<', $match[0]);
        }

        /**
         * Function to load external plugins for tinyMCE
         *
         * @param array $plgs External plugins
         *
         * @return array
         */
        public function addTinyMceExternal(array $plgs)
        {
            $plgs['customstyles'] = ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/customstyles/plugin.js';

            return $plgs;
        }

        /**
         * Function to add buttons for tinyMCE toolbars
         *
         * @param array $buttons TinyMCE buttons
         *
         * @return array
         */
        public function addTinyMceButtons(array $buttons)
        {
            array_push($buttons, 'customstyles');

            return $buttons;
        }

        /**
         * Render html for block config settings fields
         *
         * @param array $fieldset Array of field to render
         * @param array $data Data will load as value to field
         *
         * @return boolean        Echo html content
         */
        public function renderBlockConfigFields($fieldset, $data)
        {
            $html = '';
            foreach ($fieldset as $category) {
                $html .= '<div class="block-config-category">';
                $html .= '<h3 class="block-config-category-title">' . esc_html($category['label']) . '</h3>';
                $html .= '<table class="form-table">';

                foreach ($category['settings'] as $setting) {
                    $settingValue = $this->setConfigValue($data, $setting['name']);

                    if ($setting['type'] === 'hidden') {
                        $html .= '<input type="hidden" class="block-config-input" name="' . esc_attr($setting['name']) . '" value="' . esc_attr($setting['value']) . '" />';
                        continue;
                    }

                    $html .= '<tr>';
                    $html .= '<th scope="row">';
                    $html .= '<label for="setting-' . esc_attr($setting['name']) . '" class="advgb-setting-label">' . esc_html($setting['title']) . '</label>';
                    $html .= '</th>';
                    $html .= '<td>';

                    switch ($setting['type']) {
                        case 'text':
                        case 'number':
                            $html .= '<input type="' . esc_attr($setting['type']) . '" class="block-config-input" id="setting-' . esc_attr($setting['name']) . '" name="' . esc_attr($setting['name']) . '" ';
                            if ($setting['type'] === 'number' && ( isset($setting['min']) || isset($setting['max']) )) {
                                $html .= ' min="' . esc_attr($setting['min']) . '" max="' . esc_attr($setting['max']) . '" ';
                            }
                            $html .= ' value="' . esc_attr($settingValue) . '" />';
                            break;
                        case 'color':
                            $html .= '<input type="text" class="minicolors minicolors-input block-config-input" id="setting-' . esc_attr($setting['name']) . '" name="' . esc_attr($setting['name']) . '" value="' . esc_attr($settingValue) . '" />';
                            break;
                        case 'select':
                            $html .= '<select class="block-config-input" id="setting-' . esc_attr($setting['name']) . '" name="' . esc_attr($setting['name']) . '">';
                            $html .= '<option value="">' . __('Default', 'advanced-gutenberg') . '</option>';

                            foreach ($setting['options'] as $option) {
                                $selected = $option['value'] === $settingValue ? 'selected' : '';
                                $html     .= '<option value="' . esc_attr($option['value']) . '" ' . $selected . '>' . esc_html($option['label']) . '</option>';
                            }

                            $html .= '</select>';
                            break;
                        case 'checkbox':
                            $checked = (int) $settingValue === 1 ? 'checked' : '';
                            $html    .= '<input type="checkbox" value="1" class="block-config-input" id="setting-' . esc_attr($setting['name']) . '" name="' . esc_attr($setting['name']) . '" ' . $checked . '/>';
                            break;
                        default:
                            $html .= '<div>' . __('Type field not defined', 'advanced-gutenberg') . '</div>';
                            break;
                    }

                    $html .= '</td>';
                    $html .= '</tr>';
                }

                $html .= '</table>';
                $html .= '</div>';
            }

            echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- already escaped

            return true;
        }

        /**
         * Load reCaptcha v2 scripts
         *
         * @return void
         */
        public function loadRecaptchaApi()
        {
            $recaptcha_config = get_option('advgb_recaptcha_config');
            if (! is_admin() && isset($recaptcha_config['recaptcha_enable']) && $recaptcha_config['recaptcha_enable']) {
                $lang = $recaptcha_config['recaptcha_language'] ? '&hl=' . $recaptcha_config['recaptcha_language'] : '';
                wp_enqueue_script(
                    'advgb_recaptcha_js',
                    'https://www.google.com/recaptcha/api.js?onload=advgbRecaptchaInit&render=explicit' . $lang
                );

                if (isset($recaptcha_config['recaptcha_site_key']) && $recaptcha_config['recaptcha_site_key']) {
                    wp_enqueue_script(
                        'advgb_recaptcha_init_js',
                        ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/recaptcha.js'
                    );

                    wp_localize_script('advgb_recaptcha_init_js', 'advgbGRC', array(
                        'site_key' => $recaptcha_config['recaptcha_site_key'],
                        'theme'    => $recaptcha_config['recaptcha_theme'],
                    ));
                }
            }
        }

        /**
         * Load Google Maps script
         *
         * @return void
         */
        public function loadGoogleMapApi()
        {
            $saved_settings = get_option('advgb_settings');
            if (isset($saved_settings['google_api_key']) && ! empty($saved_settings['google_api_key'])) {
                wp_enqueue_script(
                    'advgb_map_api',
                    'https://maps.googleapis.com/maps/api/js?key=' . $saved_settings['google_api_key']
                );
            }
        }

        /**
         * Add CSS patch when using Twenty Twenty-One in footer with Slick slideshow
         * https://core.trac.wordpress.org/ticket/53649
         * https://github.com/kenwheeler/slick/issues/3415
         *
         * @return void
         */
        public function fixCssGridFooterWidgets()
        {
            $ctheme = wp_get_theme();
            if ('Twenty Twenty-One' == $ctheme->name || 'Twenty Twenty-One' == $ctheme->parent_theme) {
                wp_add_inline_style(
                    'advgb_blocks_styles',
                    '@media only screen and (min-width: 652px) {
                        .widget-area {
                            grid-template-columns: repeat(2, minmax( 0, 1fr ));
                        }
                    }
                    @media only screen and (min-width: 1024px) {
                        .widget-area {
                            grid-template-columns: repeat(3, minmax( 0, 1fr ));
                        }
                    }'
                );
            }
        }

        /**
         * Check if a setting is enabled
         *
         * @param string $setting The setting from advgb_settings option field
         * @deprecated 3.2.0 Use Utilities::settingIsEnabled() instead
         *
         * @return boolean
         */
        public function settingIsEnabled($setting)
        {
            return Utilities::settingIsEnabled($setting);
        }

        /**
         * Set value to config field
         *
         * @param array $valueList Array of values to set
         * @param string $valueToGet Value field to set
         * @param mixed $default Default value if value field from list not set
         *
         * @return string           Value after check
         */
        private function setConfigValue($valueList, $valueToGet, $default = '')
        {
            $valueReturn = $default;
            if (gettype($valueList) === 'array') {
                if (isset($valueList[ $valueToGet ])) {
                    $valueReturn = $valueList[ $valueToGet ];
                }
            }

            return $valueReturn;
        }

        /**
         * Dynamically load the blocks's CSS and media files
         *
         * @param   $blockName
         * @param   $blockAttrs
         *
         * @return  string      CSS Styles
         * @since   2.4.2
         */
        public function advgb_SetStylesForBlocks($blockAttrs, $blockName)
        {
            $availableBlocks = array(
                'advgb/adv-tabs',
                'advgb/adv-tab',
                'advgb/columns',
                'advgb/column',
                'advgb/image',
                'advgb/icon',
                'advgb/accordions',
                'advgb/accordion-item',
                'advgb/table',
                'advgb/infobox',
                'advgb/button',
                'advgb/login-form',
                'advgb/count-up',
                'advgb/summary',
                'advgb/contact-form',
                'advgb/images-slider',
                'advgb/map',
                'advgb/newsletter',
                'advgb/testimonial',
                'advgb/list',
                'advgb/video',
                'advgb/recent-posts',
                'advgb/search-bar',
                'advgb/social-links',
                'advgb/woo-products',
                'advgb/tabs',
                'core/gallery' // Core block
            );

            // Pro
            if (defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                if (method_exists('PPB_AdvancedGutenbergPro\Utils\Definitions', 'advgb_pro_get_blocks')) {
                    $availableProBlocks = PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_get_blocks();
                    foreach ($availableProBlocks as $availableProBlock) {
                        array_push(
                            $availableBlocks,
                            $availableProBlock
                        );
                    }
                }
            }

            // Load common CSS
            if (in_array($blockName, $availableBlocks) && Utilities::settingIsEnabled('enable_advgb_blocks')) {
                wp_enqueue_style(
                    'advgb_blocks_styles',
                    ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/css/blocks.css',
                    array(),
                    ADVANCED_GUTENBERG_VERSION
                );

                // Pro
                if (defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                    if (
                        method_exists(
                            'PPB_AdvancedGutenbergPro\Utils\Definitions',
                            'advgb_pro_enqueue_main_styles'
                        )
                    ) {
                        PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_enqueue_main_styles();
                    }
                }
            }

            $html_style = '';

            switch ($blockName) {
                case 'advgb/list':
                    // Styles
                    $html_style = $this->advgb_AdvancedListStyles($blockAttrs);

                    // Assets
                    wp_enqueue_style('dashicons');
                    break;

                case 'advgb/button':
                    // Styles
                    $html_style = $this->advgb_AdvancedButtonStyles($blockAttrs);

                    // Pro - Assets
                    if (defined('ADVANCED_GUTENBERG_PRO_LOADED') && Utilities::settingIsEnabled('enable_advgb_blocks')) {
                        if (
                            isset($blockAttrs['iconDisplay'])
                             && method_exists(
                                 'PPB_AdvancedGutenbergPro\Utils\Definitions',
                                 'advgb_pro_enqueue_styles_frontend_advbutton'
                             )
                        ) {
                            PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_enqueue_styles_frontend_advbutton();
                        }

                        if (
                            method_exists(
                                'PPB_AdvancedGutenbergPro\Utils\Definitions',
                                'advgb_pro_enqueue_font_styles_frontend'
                            )
                        ) {
                            PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_enqueue_font_styles_frontend(
                                'advgb/button',
                                $blockAttrs
                            );
                        }
                    }

                    break;

                case 'advgb/column':
                case 'advgb/columns':
                    // Styles
                    $html_style = $this->advgb_AdvancedColumnsStyles($blockAttrs, $blockName);

                    // Assets
                    wp_enqueue_style('advgb_columns_styles');

                    break;

                case 'advgb/login-form':
                    // Assets
                    $html_style = $this->advgb_AdvancedLoginRegisterStyles($blockAttrs);

                    // Assets
                    wp_enqueue_style('dashicons');
                    wp_enqueue_script('jquery-effects-slide');
                    wp_enqueue_script(
                        'advgb_lores_js',
                        ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/login-form/frontend.js',
                        [ 'jquery' ],
                        ADVANCED_GUTENBERG_VERSION
                    );
                    wp_localize_script(
                        'advgb_lores_js',
                        'advgbLoresForm',
                        [
                            'ajax_url'              => admin_url('admin-ajax.php'),
                            'login_url'             => wp_login_url(),
                            'register_url'          => wp_registration_url(),
                            'lostpwd_url'           => wp_lostpassword_url(),
                            'home_url'              => home_url(),
                            'admin_url'             => admin_url(),
                            'register_enabled'      => get_option('users_can_register'),
                            'unregistrable_notice'  => __(
                                'User registration is currently not allowed.',
                                'advanced-gutenberg'
                            ),
                            'captcha_empty_warning' => __('Captcha must be checked!', 'advanced-gutenberg'),
                            'login_failed_notice'   => __('Username or password is incorrect!', 'advanced-gutenberg'),
                        ]
                    );
                    $this->loadRecaptchaApi();

                    break;

                case 'advgb/search-bar':
                    // Styles
                    $html_style = $this->advgb_AdvancedSearchBarStyles($blockAttrs);

                    break;

                case 'advgb/image':
                    // Styles
                    $html_style = $this->advgb_AdvancedImageStyles($blockAttrs);

                    // Assets
                    if (array_key_exists('openOnClick', $blockAttrs)) {
                        if ($blockAttrs['openOnClick'] == 'lightbox') {
                            // Lightbox
                            wp_enqueue_style('colorbox_style');
                            wp_enqueue_script('colorbox_js');
                            wp_enqueue_script(
                                'advgbImageLightbox_js',
                                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/advimage/lightbox.js',
                                [ 'jquery' ],
                                ADVANCED_GUTENBERG_VERSION
                            );
                        } elseif ($blockAttrs['openOnClick'] == 'url') {
                            // Custom URL
                            wp_enqueue_script(
                                'advgbImageCustomURL_js',
                                ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/advimage/url.js',
                                [ 'jquery' ],
                                ADVANCED_GUTENBERG_VERSION
                            );
                        } else {
                            // Nothing to do here
                        }
                    }
                    break;

                case 'advgb/testimonial':
                    // Styles
                    $html_style = $this->advgb_AdvancedTestimonialStyles($blockAttrs);

                    // Assets
                    wp_enqueue_style('dashicons');

                    // When sliderView exists...
                    if (array_key_exists('sliderView', $blockAttrs)) {
                        wp_enqueue_style('slick_style');
                        wp_enqueue_style('slick_theme_style');
                        wp_enqueue_script('slick_js');
                        wp_enqueue_script(
                            'advgb_testimonial_frontend',
                            ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/testimonial/frontend.js',
                            [ 'jquery' ],
                            ADVANCED_GUTENBERG_VERSION
                        );

                        // Patch for Twenty Twenty-One
                        $this->fixCssGridFooterWidgets();
                    }
                    break;

                case 'advgb/adv-tabs':
                    // Styles
                    $html_style = $this->advgb_AdvancedTabsStyles($blockAttrs);

                    // Assets
                    wp_enqueue_script('jquery-ui-tabs');
                    wp_enqueue_script(
                        'advgb_tabs_js',
                        ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/advtabs/frontend.js',
                        array( 'jquery' ),
                        ADVANCED_GUTENBERG_VERSION
                    );

                    // Pro
                    if (
                        defined('ADVANCED_GUTENBERG_PRO_LOADED')
                         && method_exists(
                             'PPB_AdvancedGutenbergPro\Utils\Definitions',
                             'advgb_pro_inline_scripts_frontend'
                         )
                    ) {
                        PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_inline_scripts_frontend(
                            'advgb/adv-tabs'
                        );
                    }

                    break;

                case 'advgb/icon':
                    // Styles
                    $html_style = $this->advgb_AdvancedIconStyles($blockAttrs);

                    // Assets
                    wp_enqueue_style('material_icon_font');

                    break;

                case 'advgb/infobox':
                    // Styles
                    $html_style = $this->advgb_AdvancedInfoBoxStyles($blockAttrs);

                    // Assets
                    wp_enqueue_style('material_icon_font');

                    break;

                case 'advgb/count-up':
                    // Assets
                    wp_enqueue_script('advgb_blocks_frontend_scripts');

                    break;

                case 'advgb/video':
                    // Assets - When openInLightbox doesn't exist means lightbox is enabled
                    if (! array_key_exists('openInLightbox', $blockAttrs)) {
                        wp_enqueue_style('colorbox_style');
                        wp_enqueue_script('colorbox_js');
                        wp_enqueue_script(
                            'advgbVideoLightbox_js',
                            ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/advvideo/lightbox.js',
                            [ 'jquery' ],
                            ADVANCED_GUTENBERG_VERSION
                        );
                    }

                    break;

                case 'advgb/map':
                    // Assets
                    wp_enqueue_script(
                        'advgb_gmap_js',
                        ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/map/frontend.js',
                        [],
                        ADVANCED_GUTENBERG_VERSION
                    );
                    $this->loadGoogleMapApi();

                    break;

                case 'advgb/summary':
                    // Assets
                    wp_enqueue_script(
                        'summary_minimized',
                        ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/summary/summaryMinimized.js',
                        [ 'jquery' ],
                        ADVANCED_GUTENBERG_VERSION
                    );

                    break;

                case 'advgb/accordions':
                    // Assets
                    wp_enqueue_script('jquery-ui-accordion');
                    wp_enqueue_script(
                        'adv_accordion_js',
                        ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/advaccordion/frontend.js',
                        [
                            'jquery',
                            'jquery-ui-accordion'
                        ],
                        ADVANCED_GUTENBERG_VERSION
                    );

                    // Pro
                    if (
                        defined('ADVANCED_GUTENBERG_PRO_LOADED')
                         && method_exists(
                             'PPB_AdvancedGutenbergPro\Utils\Definitions',
                             'advgb_pro_inline_scripts_frontend'
                         )
                    ) {
                        PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_inline_scripts_frontend('advgb/accordion-item');
                    }

                    break;

                case 'advgb/woo-products':
                    // Assets - When viewType is slider
                    if (array_key_exists('viewType', $blockAttrs) && $blockAttrs['viewType'] == 'slider') {
                        wp_enqueue_style('slick_style');
                        wp_enqueue_style('slick_theme_style');
                        wp_enqueue_script('slick_js');
                        wp_enqueue_script(
                            'advgb_woo_products_js',
                            ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/woo-products/slider.js',
                            [ 'jquery' ],
                            ADVANCED_GUTENBERG_VERSION
                        );

                        // Patch for Twenty Twenty-One
                        $this->fixCssGridFooterWidgets();
                    }

                    break;

                case 'advgb/images-slider':
                    // Assets
                    wp_enqueue_style('slick_style');
                    wp_enqueue_style('slick_theme_style');
                    wp_enqueue_script('slick_js');
                    wp_enqueue_script(
                        'advgbImageSliderLightbox_frontent_js',
                        ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/images-slider/frontend.js',
                        [ 'jquery' ],
                        ADVANCED_GUTENBERG_VERSION
                    );

                    if (
                        defined('ADVANCED_GUTENBERG_PRO_LOADED')
                         && method_exists(
                             'PPB_AdvancedGutenbergPro\Utils\Definitions',
                             'advgb_pro_inline_scripts_frontend'
                         )
                    ) {
                        $script = PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_inline_scripts_frontend(
                            'advgb/images-slider',
                            $blockAttrs
                        );

                        if (! empty($script)) {
                            wp_add_inline_script(
                                'advgbImageSliderLightbox_frontent_js',
                                $script
                            );
                        }
                    }

                    // When lightbox is enabled
                    if (
                        array_key_exists('actionOnClick', $blockAttrs)
                         && $blockAttrs['actionOnClick'] == 'lightbox'
                    ) {
                        wp_enqueue_style('colorbox_style');
                        wp_enqueue_script('colorbox_js');
                        wp_enqueue_script(
                            'advgbImageSliderLightbox_js',
                            ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/images-slider/lightbox.js',
                            [],
                            ADVANCED_GUTENBERG_VERSION
                        );
                    }

                    // Pro
                    if (defined('ADVANCED_GUTENBERG_PRO_LOADED') && Utilities::settingIsEnabled('enable_advgb_blocks')) {
                        if (
                            method_exists(
                                'PPB_AdvancedGutenbergPro\Utils\Definitions',
                                'advgb_pro_enqueue_font_styles_frontend'
                            )
                        ) {
                            PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_enqueue_font_styles_frontend(
                                'advgb/images-slider',
                                $blockAttrs
                            );
                        }
                    }

                    // Patch for Twenty Twenty-One
                    $this->fixCssGridFooterWidgets();

                    break;

                case 'advgb/contact-form':
                    // Assets
                    wp_enqueue_script(
                        'advgbContactForm_js',
                        ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/contact-form/frontend.js',
                        [ 'jquery' ],
                        ADVANCED_GUTENBERG_VERSION
                    );
                    wp_localize_script(
                        'advgbContactForm_js',
                        'advgbContactForm',
                        [
                            'ajax_url' => admin_url('admin-ajax.php')
                        ]
                    );
                    $this->loadRecaptchaApi();

                    break;

                case 'advgb/newsletter':
                    // Assets
                    wp_enqueue_script(
                        'advgbNewsletter_js',
                        ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/newsletter/frontend.js',
                        [
                            'jquery',
                            'wp-i18n'
                        ],
                        ADVANCED_GUTENBERG_VERSION
                    );
                    wp_localize_script(
                        'advgbNewsletter_js',
                        'advgbNewsletter',
                        [
                            'ajax_url' => admin_url('admin-ajax.php')
                        ]
                    );
                    $this->loadRecaptchaApi();

                    wp_set_script_translations(
                        'advgbNewsletter_js',
                        'advanced-gutenberg',
                        plugin_dir_path(ADVANCED_GUTENBERG_PLUGIN) . 'languages'
                    );

                    break;

                case 'advgb/recent-posts':
                    // Styles
                    $html_style = $this->advgb_AdvancedRecentPostsStyles($blockAttrs);

                    // Assets
                    wp_enqueue_style('dashicons');
                    wp_enqueue_style('advgb_recent_posts_styles');

                    if (
                        array_key_exists('postView', $blockAttrs)
                         && $blockAttrs['postView'] == 'slider'
                    ) {
                        // Slider view
                        wp_enqueue_style('slick_style');
                        wp_enqueue_style('slick_theme_style');
                        wp_enqueue_script('slick_js');
                        wp_enqueue_script(
                            'advgb_recent_posts_slider_js',
                            ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/recent-posts/slider.js',
                            [ 'jquery' ],
                            ADVANCED_GUTENBERG_VERSION
                        );

                        // Pro
                        if (
                            defined('ADVANCED_GUTENBERG_PRO_LOADED')
                             && method_exists(
                                 'PPB_AdvancedGutenbergPro\Utils\Definitions',
                                 'advgb_pro_inline_scripts_frontend'
                             )
                        ) {
                            $script = PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_inline_scripts_frontend(
                                'advgb/recent-posts',
                                $blockAttrs
                            );

                            if (! empty($script)) {
                                wp_add_inline_script(
                                    'advgb_recent_posts_slider_js',
                                    $script
                                );
                            }
                        }

                        // Patch for Twenty Twenty-One
                        $this->fixCssGridFooterWidgets();
                    } elseif (
                        array_key_exists('postView', $blockAttrs)
                               && $blockAttrs['postView'] == 'masonry'
                    ) {
                        // Masonry view
                        wp_enqueue_script('advgb_masonry_js');
                        wp_enqueue_script(
                            'advgb_recent_posts_masonry_js',
                            ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/blocks/recent-posts/masonry.js',
                            [
                                'jquery',
                                'advgb_masonry_js'
                            ],
                            ADVANCED_GUTENBERG_VERSION
                        );
                    }

                    // Pro
                    if (defined('ADVANCED_GUTENBERG_PRO_LOADED') && Utilities::settingIsEnabled('enable_advgb_blocks')) {
                        if (
                            method_exists(
                                'PPB_AdvancedGutenbergPro\Utils\Definitions',
                                'advgb_pro_enqueue_font_styles_frontend'
                            )
                        ) {
                            PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_enqueue_font_styles_frontend(
                                'advgb/recent-posts',
                                $blockAttrs
                            );
                        }
                    }

                    break;

                case 'advgb/countdown':
                    // Assets - Pro
                    if (defined('ADVANCED_GUTENBERG_PRO_LOADED') && Utilities::settingIsEnabled('enable_advgb_blocks')) {
                        if (
                            method_exists(
                                'PPB_AdvancedGutenbergPro\Utils\Definitions',
                                'advgb_pro_enqueue_scripts_frontend_countdown'
                            )
                        ) {
                            PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_enqueue_scripts_frontend_countdown();
                        }
                    }

                    break;

                case 'core/gallery':
                    // Assets
                    $saved_settings = get_option('advgb_settings', []);
                    if (isset($saved_settings['gallery_lightbox']) && $saved_settings['gallery_lightbox']) {
                        wp_enqueue_style('colorbox_style');
                        wp_enqueue_script('colorbox_js');
                        wp_enqueue_script(
                            'gallery_lightbox_js',
                            ADVANCED_GUTENBERG_PLUGIN_DIR_URL . 'assets/js/gallery.colorbox.init.js',
                            [ 'jquery' ],
                            ADVANCED_GUTENBERG_VERSION
                        );
                        wp_localize_script(
                            'gallery_lightbox_js',
                            'advgb',
                            [
                                'imageCaption' => $saved_settings['gallery_lightbox_caption']
                            ]
                        );
                    }

                    break;

                default:
                    // Nothing to do here

                    break;
            }

            // Styles and assets from Pro blocks
            if (defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                if (
                    method_exists(
                        'PPB_AdvancedGutenbergPro\Utils\Definitions',
                        'advgb_pro_set_styles_for_blocks'
                    )
                ) {
                    $html_style .= PPB_AdvancedGutenbergPro\Utils\Definitions::advgb_pro_set_styles_for_blocks(
                        $blockAttrs,
                        $blockName
                    );
                }
            }

            return $html_style;
        }

        /**
         * Styles for Adv. Lists Block
         *
         * @param   $blockAttrs The block attributes
         *
         * @return  string      Inline CSS
         * @since    2.4.2
         */
        public function advgb_AdvancedListStyles($blockAttrs)
        {
            $block_class = $blockAttrs['id'];
            $font_size   = isset($blockAttrs['fontSize']) ? esc_html(intval($blockAttrs['fontSize'])) : 16;
            $icon_size   = isset($blockAttrs['iconSize']) ? esc_html(intval($blockAttrs['iconSize'])) : 16;
            $icon_color  = isset($blockAttrs['iconColor']) ? esc_html($blockAttrs['iconColor']) : '#000';
            $margin      = isset($blockAttrs['margin']) ? esc_html(intval($blockAttrs['margin'])) : 2;
            $padding     = isset($blockAttrs['padding']) ? esc_html(intval($blockAttrs['padding'])) : 2;
            $line_height = isset($blockAttrs['lineHeight']) ? esc_html(intval($blockAttrs['lineHeight'])) : 18;

            $style_html = '.wp-block-advgb-list ul.' . $block_class . ' > li{';
            $style_html .= 'font-size:' . $font_size . 'px;';
            $style_html .= '}';
            if (isset($blockAttrs['icon']) && ! empty($blockAttrs['icon'])) {
                $style_html .= '.wp-block-advgb-list ul.' . $block_class . ' > li{';
                $style_html .= 'padding-left:' . ( $icon_size + $padding ) . 'px;margin-left:0;';
                $style_html .= '}';
                $style_html .= '.wp-block-advgb-list ul.' . $block_class . ' > li:before{';
                $style_html .= 'font-size:' . $icon_size . 'px;';
                $style_html .= 'color:' . $icon_color . ';';
                $style_html .= 'line-height:' . $line_height . 'px;';
                $style_html .= 'margin:' . $margin . 'px;';
                $style_html .= 'padding:' . $padding . 'px;';
                $style_html .= 'margin-left:-' . ( $icon_size + $padding + $margin ) . 'px';
                $style_html .= '}';
            }

            return $style_html;
        }

        /**
         * Styles for Adv. Button Block
         *
         * @param   $blockAttrs The block attributes
         *
         * @return  string      Inline CSS
         * @since    2.4.2
         */
        public function advgb_AdvancedButtonStyles($blockAttrs)
        {
            // Decide to include or not CSS color property for outlined styles
            if (
                ! isset($blockAttrs['textColor'])
                && isset($blockAttrs['className'])
                && (
                    strpos($blockAttrs['className'], 'is-style-squared-outline') !== false
                    || strpos($blockAttrs['className'], 'is-style-outlined') !== false
                )
            ) {
                $enable_text_color = false;
            } else {
                $enable_text_color = true;
            }

            $block_class    = esc_html($blockAttrs['id']);
            $font_size      = isset($blockAttrs['textSize']) ? esc_html(intval($blockAttrs['textSize'])) : 18;
            $color          = isset($blockAttrs['textColor']) ? esc_html($blockAttrs['textColor']) : '#fff';
            $bg_color       = isset($blockAttrs['bgColor']) ? esc_html($blockAttrs['bgColor']) : '#2196f3';
            $mg_top         = isset($blockAttrs['marginTop']) ? esc_html(intval($blockAttrs['marginTop'])) : 0;
            $mg_right       = isset($blockAttrs['marginRight']) ? esc_html(intval($blockAttrs['marginRight'])) : 0;
            $mg_bottom      = isset($blockAttrs['marginBottom']) ? esc_html(intval($blockAttrs['marginBottom'])) : 0;
            $mg_left        = isset($blockAttrs['marginLeft']) ? esc_html(intval($blockAttrs['marginLeft'])) : 0;
            $pd_top         = isset($blockAttrs['paddingTop']) ? esc_html(intval($blockAttrs['paddingTop'])) : 10;
            $pd_right       = isset($blockAttrs['paddingRight']) ? esc_html(intval($blockAttrs['paddingRight'])) : 30;
            $pd_bottom      = isset($blockAttrs['paddingBottom']) ? esc_html(intval($blockAttrs['paddingBottom'])) : 10;
            $pd_left        = isset($blockAttrs['paddingLeft']) ? esc_html(intval($blockAttrs['paddingLeft'])) : 30;
            $border_width   = isset($blockAttrs['borderWidth']) ? esc_html(intval($blockAttrs['borderWidth'])) : 1;
            $border_color   = isset($blockAttrs['borderColor']) ? esc_html($blockAttrs['borderColor']) : '';
            $border_style   = isset($blockAttrs['borderStyle']) ? esc_html($blockAttrs['borderStyle']) : 'none';
            $border_radius  = isset($blockAttrs['borderRadius']) ? esc_html(intval($blockAttrs['borderRadius'])) : 50;
            $hover_t_color  = isset($blockAttrs['hoverTextColor']) ? esc_html($blockAttrs['hoverTextColor']) : '';
            $hover_bg_color = isset($blockAttrs['hoverBgColor']) ? esc_html($blockAttrs['hoverBgColor']) : '';
            $hover_sh_color = isset($blockAttrs['hoverShadowColor']) ? esc_html($blockAttrs['hoverShadowColor']) : '#ccc';
            $hover_sh_h     = isset($blockAttrs['hoverShadowH']) ? esc_html(intval($blockAttrs['hoverShadowH'])) : 1;
            $hover_sh_v     = isset($blockAttrs['hoverShadowV']) ? esc_html(intval($blockAttrs['hoverShadowV'])) : 1;
            $hover_sh_blur  = isset($blockAttrs['hoverShadowBlur']) ? esc_html(intval($blockAttrs['hoverShadowBlur'])) : 12;
            $hover_sh_sprd  = isset($blockAttrs['hoverShadowSpread']) ? esc_html(intval($blockAttrs['hoverShadowSpread'])) : 0;
            $hover_opacity  = isset($blockAttrs['hoverOpacity']) ? esc_html(intval($blockAttrs['hoverOpacity']) / 100) : 1;
            $transition_spd = isset($blockAttrs['transitionSpeed']) ? esc_html(floatval($blockAttrs['transitionSpeed']) / 1000) : 0.2;

            $style_html = '.' . $block_class . '{';
            $style_html .= 'font-size:' . $font_size . 'px;';
            if ($enable_text_color == true) {
                $style_html .= 'color:' . $color . ' !important;';
            }
            $style_html .= 'background-color:' . $bg_color . ' !important;';
            $style_html .= 'margin:' . $mg_top . 'px ' . $mg_right . 'px ' . $mg_bottom . 'px ' . $mg_left . 'px !important;';
            $style_html .= 'padding:' . $pd_top . 'px ' . $pd_right . 'px ' . $pd_bottom . 'px ' . $pd_left . 'px;';
            $style_html .= 'border-width:' . $border_width . 'px !important;';
            if (! empty($border_color)) {
                $style_html .= 'border-color:' . $border_color . ' !important;';
            }
            $style_html .= 'border-style:' . $border_style . ( $border_style === 'none' ? '' : ' !important' ) . ';';
            $style_html .= 'border-radius:' . $border_radius . 'px !important;';
            $style_html .= '}';

            $style_html .= '.' . $block_class . ':hover{';
            if (! empty($hover_t_color)) {
                $style_html .= 'color:' . $hover_t_color . ' !important;';
            }
            if (! empty($hover_bg_color)) {
                $style_html .= 'background-color:' . $hover_bg_color . ' !important;';
            }
            $style_html .= 'box-shadow:' . $hover_sh_h . 'px ' . $hover_sh_v . 'px ' . $hover_sh_blur . 'px ' . $hover_sh_sprd . 'px ' . $hover_sh_color . ';';
            $style_html .= 'opacity:' . $hover_opacity . ';';
            $style_html .= 'transition:all ' . $transition_spd . 's ease;';
            $style_html .= '}';

            if (! defined('ADVANCED_GUTENBERG_PRO_LOADED')) {
                $style_html .= '.' . $block_class . ' > i {';
                $style_html .= 'display: none !important;';
                $style_html .= '}';
            }

            return $style_html;
        }

        /**
         * Styles for Adv. Columns Block
         *
         * @param   $blockAttrs The block attributes
         * @param   $blockName  The block name
         *
         * @return  string      Inline CSS
         * @since    2.4.2
         */
        public function advgb_AdvancedColumnsStyles($blockAttrs, $blockName)
        {
            $colID       = esc_html($blockAttrs['colId'] ?? '');
            $marginUnit  = 'px';
            $paddingUnit = 'px';
            if ($blockName === 'advgb/column') {
                $colID = $colID . '>.advgb-column-inner';
            }

            if (isset($blockAttrs['marginUnit'])) {
                $marginUnit = esc_html($blockAttrs['marginUnit']);
            }

            if (isset($blockAttrs['paddingUnit'])) {
                $paddingUnit = esc_html($blockAttrs['paddingUnit']);
            }

            $style_html = '#' . $colID . '{';
            $style_html .= isset($blockAttrs['textAlign']) ? 'text-align:' . esc_html($blockAttrs['textAlign']) . ';' : '';
            $style_html .= isset($blockAttrs['marginTop']) ? 'margin-top:' . esc_html($blockAttrs['marginTop']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['marginRight']) ? 'margin-right:' . esc_html($blockAttrs['marginRight']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['marginBottom']) ? 'margin-bottom:' . esc_html($blockAttrs['marginBottom']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['marginLeft']) ? 'margin-left:' . esc_html($blockAttrs['marginLeft']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingTop']) ? 'padding-top:' . esc_html($blockAttrs['paddingTop']) . $paddingUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingRight']) ? 'padding-right:' . esc_html($blockAttrs['paddingRight']) . $paddingUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingBottom']) ? 'padding-bottom:' . esc_html($blockAttrs['paddingBottom']) . $paddingUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingLeft']) ? 'padding-left:' . esc_html($blockAttrs['paddingLeft']) . $paddingUnit . ';' : '';
            $style_html .= '}';

            if ($blockName === 'advgb/column') {
                $childColID    = esc_html($blockAttrs['colId']);
                $childColWidth = isset($blockAttrs['width']) ? intval($blockAttrs['width']) : 0;
                if ($childColWidth !== 0) {
                    $style_html .= '#' . $childColID . '{width: ' . $childColWidth . '%;}';
                }
            }

            // Styles for tablet
            $style_html .= '@media screen and (max-width: 1023px) {';
            $style_html .= '#' . $colID . '{';
            $style_html .= isset($blockAttrs['marginTopT']) ? 'margin-top:' . esc_html($blockAttrs['marginTopT']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['marginRightT']) ? 'margin-right:' . esc_html($blockAttrs['marginRightT']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['marginBottomT']) ? 'margin-bottom:' . esc_html($blockAttrs['marginBottomT']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['marginLeftT']) ? 'margin-left:' . esc_html($blockAttrs['marginLeftT']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingTopT']) ? 'padding-top:' . esc_html($blockAttrs['paddingTopT']) . $paddingUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingRightT']) ? 'padding-right:' . esc_html($blockAttrs['paddingRightT']) . $paddingUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingBottomT']) ? 'padding-bottom:' . esc_html($blockAttrs['paddingBottomT']) . $paddingUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingLeftT']) ? 'padding-left:' . esc_html($blockAttrs['paddingLeftT']) . $paddingUnit . ';' : '';
            $style_html .= '}';
            $style_html .= '}';

            // Styles for mobile
            $style_html .= '@media screen and (max-width: 767px) {';
            $style_html .= '#' . $colID . '{';
            $style_html .= isset($blockAttrs['textAlignM']) ? 'text-align:' . esc_html($blockAttrs['textAlignM']) . ';' : '';
            $style_html .= isset($blockAttrs['marginTopM']) ? 'margin-top:' . esc_html($blockAttrs['marginTopM']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['marginRightM']) ? 'margin-right:' . esc_html($blockAttrs['marginRightM']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['marginBottomM']) ? 'margin-bottom:' . esc_html($blockAttrs['marginBottomM']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['marginLeftM']) ? 'margin-left:' . esc_html($blockAttrs['marginLeftM']) . $marginUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingTopM']) ? 'padding-top:' . esc_html($blockAttrs['paddingTopM']) . $paddingUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingRightM']) ? 'padding-right:' . esc_html($blockAttrs['paddingRightM']) . $paddingUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingBottomM']) ? 'padding-bottom:' . esc_html($blockAttrs['paddingBottomM']) . $paddingUnit . ';' : '';
            $style_html .= isset($blockAttrs['paddingLeftM']) ? 'padding-left:' . esc_html($blockAttrs['paddingLeftM']) . $paddingUnit . ';' : '';
            $style_html .= '}';
            $style_html .= '}';

            return $style_html;
        }

        /**
         * Styles for Login / Register Block
         *
         * @param   $blockAttrs The block attributes
         *
         * @return  string      Inline CSS
         * @since    2.4.2
         */
        public function advgb_AdvancedLoginRegisterStyles($blockAttrs)
        {
            $block_class    = esc_html($blockAttrs['submitButtonId']);
            $hover_t_color  = isset($blockAttrs['submitHoverColor']) ? esc_html($blockAttrs['submitHoverColor']) : '';
            $hover_bg_color = isset($blockAttrs['submitHoverBgColor']) ? esc_html($blockAttrs['submitHoverBgColor']) : '';
            $hover_sh_color = isset($blockAttrs['submitHoverShadow']) ? esc_html($blockAttrs['submitHoverShadow']) : '#ccc';
            $hover_sh_h     = isset($blockAttrs['submitHoverShadowH']) ? esc_html(intval($blockAttrs['submitHoverShadowH'])) : 1;
            $hover_sh_v     = isset($blockAttrs['submitHoverShadowV']) ? esc_html(intval($blockAttrs['submitHoverShadowV'])) : 1;
            $hover_sh_blur  = isset($blockAttrs['submitHoverShadowBlur']) ? esc_html(intval($blockAttrs['submitHoverShadowBlur'])) : 12;
            $hover_sh_sprd  = isset($blockAttrs['submitHoverShadowSpread']) ? esc_html(intval($blockAttrs['submitHoverShadowSpread'])) : 0;
            $hover_opacity  = isset($blockAttrs['submitHoverOpacity']) ? esc_html(intval($blockAttrs['submitHoverOpacity']) / 100) : 1;
            $transition_spd = isset($blockAttrs['submitHoverTranSpeed']) ? esc_html(floatval($blockAttrs['submitHoverTranSpeed']) / 1000) : 0.2;

            $style_html = '.' . $block_class . ':hover{';
            if (! empty($hover_t_color)) {
                $style_html .= 'color:' . $hover_t_color . ' !important;';
            }
            if (! empty($hover_bg_color)) {
                $style_html .= 'background-color:' . $hover_bg_color . ' !important;';
            }
            $style_html .= 'box-shadow:' . $hover_sh_h . 'px ' . $hover_sh_v . 'px ' . $hover_sh_blur . 'px ' . $hover_sh_sprd . 'px ' . $hover_sh_color . ' !important;';
            $style_html .= 'opacity:' . $hover_opacity . ';';
            $style_html .= 'transition:all ' . $transition_spd . 's ease;';
            $style_html .= '}';

            return $style_html;
        }

        /**
         * Styles for Search Bar Block
         *
         * @param   $blockAttrs The block attributes
         *
         * @return  string      Inline CSS
         * @since    2.4.2
         */
        public function advgb_AdvancedSearchBarStyles($blockAttrs)
        {
            $block_class    = esc_html($blockAttrs['searchBtnId']);
            $hover_t_color  = isset($blockAttrs['searchBtnHoverColor']) ? esc_html($blockAttrs['searchBtnHoverColor']) : '';
            $hover_bg_color = isset($blockAttrs['searchBtnHoverBgColor']) ? esc_html($blockAttrs['searchBtnHoverBgColor']) : '';
            $hover_sh_color = isset($blockAttrs['searchBtnHoverShadow']) ? esc_html($blockAttrs['searchBtnHoverShadow']) : '#ccc';
            $hover_sh_h     = isset($blockAttrs['searchBtnHoverShadowH']) ? esc_html(intval($blockAttrs['searchBtnHoverShadowH'])) : 1;
            $hover_sh_v     = isset($blockAttrs['searchBtnHoverShadowV']) ? esc_html(intval($blockAttrs['searchBtnHoverShadowV'])) : 1;
            $hover_sh_blur  = isset($blockAttrs['searchBtnHoverShadowBlur']) ? esc_html(intval($blockAttrs['searchBtnHoverShadowBlur'])) : 12;
            $hover_sh_sprd  = isset($blockAttrs['searchBtnHoverShadowSpread']) ? esc_html(intval($blockAttrs['searchBtnHoverShadowSpread'])) : 0;
            $hover_opacity  = isset($blockAttrs['searchBtnHoverOpacity']) ? esc_html(intval($blockAttrs['searchBtnHoverOpacity']) / 100) : 1;
            $transition_spd = isset($blockAttrs['searchBtnHoverTranSpeed']) ? esc_html(floatval($blockAttrs['searchBtnHoverTranSpeed']) / 1000) : 0.2;

            $style_html = '.' . $block_class . ':hover{';
            if (! empty($hover_t_color)) {
                $style_html .= 'color:' . $hover_t_color . ' !important;';
            }
            if (! empty($hover_bg_color)) {
                $style_html .= 'background-color:' . $hover_bg_color . ' !important;';
            }
            $style_html .= 'box-shadow:' . $hover_sh_h . 'px ' . $hover_sh_v . 'px ' . $hover_sh_blur . 'px ' . $hover_sh_sprd . 'px ' . $hover_sh_color . ' !important;';
            $style_html .= 'opacity:' . $hover_opacity . ';';
            $style_html .= 'transition:all ' . $transition_spd . 's ease;';
            $style_html .= '}';

            return $style_html;
        }

        /**
         * Styles for Adv. Image Block
         *
         * @param   $blockAttrs The block attributes
         *
         * @return  string      Inline CSS
         * @since    2.4.2
         */
        public function advgb_AdvancedImageStyles($blockAttrs)
        {
            $style_html = '';

            if (array_key_exists('blockIDX', $blockAttrs)) {
                $block_class     = esc_html($blockAttrs['blockIDX']);
                $default_opacity = isset($blockAttrs['defaultOpacity']) ? esc_html($blockAttrs['defaultOpacity']) : 40;
                $hover_opacity   = isset($blockAttrs['overlayOpacity']) ? esc_html($blockAttrs['overlayOpacity']) : 20;

                $style_html .= '.' . $block_class . '.advgb-image-block .advgb-image-overlay{';
                $style_html .= 'opacity:' . ( $default_opacity / 100 ) . ' !important;';
                $style_html .= '}';

                $style_html .= '.' . $block_class . '.advgb-image-block:hover .advgb-image-overlay{';
                $style_html .= 'opacity:' . ( $hover_opacity / 100 ) . ' !important;';
                $style_html .= '}';
            }

            return $style_html;
        }

        /**
         * Styles for Adv. Testimonial Block
         *
         * @param   $blockAttrs The block attributes
         *
         * @return  string      Inline CSS
         * @since    2.4.2
         */
        public function advgb_AdvancedTestimonialStyles($blockAttrs)
        {
            $style_html = '';

            if (array_key_exists('pid', $blockAttrs)) {
                $block_id   = $blockAttrs['pid'];
                $dots_color = isset($blockAttrs['sliderDotsColor']) ? $blockAttrs['sliderDotsColor'] : '#000';

                $style_html .= '#' . $block_id . ' .slick-dots li button:before{';
                $style_html .= 'color:' . $dots_color . ' !important;';
                $style_html .= '}';
            }

            return $style_html;
        }

        /**
         * Styles for Adv. Tabs Block
         *
         * @param   $blockAttrs The block attributes
         *
         * @return  string      Inline CSS
         * @since    2.4.2
         */
        public function advgb_AdvancedTabsStyles($blockAttrs)
        {
            $block_class           = isset($blockAttrs['pid']) ? esc_html($blockAttrs['pid']) : 'wp-block-advgb-adv-tabs';
            $active_tab_bg_color   = isset($blockAttrs['activeTabBgColor']) ? esc_html($blockAttrs['activeTabBgColor']) : '#5954d6';
            $active_tab_text_color = isset($blockAttrs['activeTabTextColor']) ? esc_html($blockAttrs['activeTabTextColor']) : '#fff';

            $style_html = '.' . $block_class . ' ul.advgb-tabs-panel li.advgb-tab.advgb-tab-active {';
            $style_html .= 'background-color:' . $active_tab_bg_color . ' !important;';
            $style_html .= 'color:' . $active_tab_text_color . ' !important;';
            $style_html .= '}';

            $style_html .= '#' . $block_class . ' .advgb-tab-body-header.header-active, .' . $block_class . ' .advgb-tab-body-header.header-active{';
            $style_html .= 'background-color:' . $active_tab_bg_color . ' !important;';
            $style_html .= 'color:' . $active_tab_text_color . ' !important;';
            $style_html .= '}';

            return $style_html;
        }

        /**
         * Styles for Recent Posts Block
         *
         * @param   $blockAttrs The block attributes
         *
         * @return  void
         * @since   2.13.3
         */
        public function advgb_AdvancedRecentPostsStyles($blockAttrs)
        {
            if (! isset($blockAttrs['id'])) {
                return;
            }

            $block_class         = esc_html($blockAttrs['id']);
            $post_view           = isset($blockAttrs['postView']) && ! empty($blockAttrs['postView']) ? esc_html($blockAttrs['postView']) : 'grid';
            $frontpage_style     = isset($blockAttrs['frontpageStyle']) && ! empty($blockAttrs['frontpageStyle']) ? esc_html($blockAttrs['frontpageStyle']) : 'default';
            $slider_style        = isset($blockAttrs['sliderStyle']) && ! empty($blockAttrs['sliderStyle']) ? esc_html($blockAttrs['sliderStyle']) : 'default';
            $image_overlay_color = isset($blockAttrs['imageOverlayColor']) ? esc_html($blockAttrs['imageOverlayColor']) : '#000';
            $image_opacity       = isset($blockAttrs['imageOpacity']) ? esc_html($blockAttrs['imageOpacity']) : 1;

            $style_html = '';

            // Only for headline style, slider and frontpage view
            if (
                ( $post_view === 'frontpage' && $frontpage_style === 'headline' )
                || ( $post_view === 'slider' && $slider_style === 'headline' )
            ) {
                $style_html .= '.' . $block_class . '.advgb-recent-posts-block.style-headline .advgb-recent-posts .advgb-recent-post .advgb-post-thumbnail {';
                $style_html .= 'background:' . $image_overlay_color . ';';
                $style_html .= '}';
                $style_html .= '.' . $block_class . '.advgb-recent-posts-block.style-headline .advgb-recent-posts .advgb-recent-post .advgb-post-thumbnail a img {';
                $style_html .= 'opacity:' . $image_opacity . ';';
                $style_html .= '}';
            }

            return $style_html;
        }

        /**
         * Styles for Adv. Icon Block
         *
         * @param   $blockAttrs The block attributes
         *
         * @return  string      Inline CSS
         * @since    2.4.2
         */
        public function advgb_AdvancedIconStyles($blockAttrs)
        {
            $block_id      = esc_html($blockAttrs['blockIDX']);
            $i             = 0;
            $default_items = array();
            $item          = array(
                'icon'          => 'info',
                'iconType'      => 'material',
                'size'          => 120,
                'color'         => '#111111',
                'style'         => 'default',
                'bgColor'       => '',
                'borderColor'   => '#111',
                'borderSize'    => 2,
                'borderRadius'  => 0,
                'paddingTop'    => 20,
                'paddingBottom' => 20,
                'paddingLeft'   => 20,
                'paddingRight'  => 20,
                'marginTop'     => 0,
                'marginBottom'  => 0,
                'marginLeft'    => 0,
                'marginRight'   => 0,
                'paddingUnit'   => 'px',
                'marginUnit'    => 'px',
                'link'          => '',
                'linkTarget'    => '_self',
                'title'         => ''
            );
            while ($i < 10) {
                array_push($default_items, $item);
                $i++;
            }
            $items      = ! isset($blockAttrs['items']) ? $default_items : $blockAttrs['items']; // Escaped in the foreach loop
            $text_align = ! isset($blockAttrs['tAlign']) ? 'center' : esc_html($blockAttrs['tAlign']);

            $style_html = '#' . $block_id . ' .advgb-icons, .' . $block_id . ' .advgb-icons {';
            $style_html .= 'text-align: ' . $text_align . ';';
            $style_html .= '}';

            foreach ($items as $k => $item) {
                $style_html .= '#' . $block_id . ' .advgb-item-' . $k . ' .advgb-icon, .' . $block_id . ' .advgb-item-' . $k . ' .advgb-icon {';
                $style_html .= 'display: flex;';
                $style_html .= 'align-items:center;';

                $style_html .= 'margin-top: ' . esc_html($item['marginTop']) . esc_html($item['marginUnit']) . ';';
                $style_html .= 'margin-bottom: ' . esc_html($item['marginBottom']) . esc_html($item['marginUnit']) . ';';
                $style_html .= 'margin-left: ' . esc_html($item['marginLeft']) . esc_html($item['marginUnit']) . ';';
                $style_html .= 'margin-right: ' . esc_html($item['marginRight']) . esc_html($item['marginUnit']) . ';';

                $style_html .= $item['style'] === 'default' ? 'padding-top: 0;' : 'padding-top: ' . esc_html($item['paddingTop']) . esc_html($item['paddingUnit']) . ';';
                $style_html .= $item['style'] === 'default' ? 'padding-bottom: 0;' : 'padding-bottom: ' . esc_html($item['paddingBottom']) . esc_html($item['paddingUnit']) . ';';
                $style_html .= $item['style'] === 'default' ? 'padding-left: 0;' : 'padding-left: ' . esc_html($item['paddingLeft']) . esc_html($item['paddingUnit']) . ';';
                $style_html .= $item['style'] === 'default' ? 'padding-right: 0;' : 'padding-right: ' . esc_html($item['paddingRight']) . esc_html($item['paddingUnit']) . ';';

                $style_html .= $item['style'] === 'default' ? 'border-width: 0;' : 'border-width: ' . esc_html($item['borderSize']) . 'px;';
                $style_html .= 'border-style: solid;';
                $style_html .= 'border-color: ' . esc_html($item['borderColor']) . ';';
                $style_html .= 'border-radius: ' . esc_html($item['borderRadius']) . '%;';

                $style_html .= isset($item['bgColor']) ? 'background-color: ' . esc_html($item['bgColor']) . ';' : 'background-color: transparent;';

                $style_html .= '}';

                $style_html .= '#' . $block_id . ' .advgb-item-' . $k . ' .advgb-icon > i, .' . $block_id . ' .advgb-item-' . $k . ' .advgb-icon > i{';
                $style_html .= 'font-size: ' . $item['size'] . 'px;';
                $style_html .= 'color: ' . $item['color'] . ';';
                $style_html .= '}';
            }

            return $style_html;
        }

        /**
         * Styles for Info Box Block
         *
         * @param   $blockAttrs The block attributes
         *
         * @return  string      Inline CSS
         * @since    2.4.2
         */
        public function advgb_AdvancedInfoBoxStyles($blockAttrs)
        {
            $block_id = esc_html($blockAttrs['blockIDX']);

            $container_bg = isset($blockAttrs['containerBackground']) ? esc_html($blockAttrs['containerBackground']) : '#f5f5f5';

            $container_padding_unit = isset($blockAttrs['containerPaddingUnit']) ? esc_html($blockAttrs['containerPaddingUnit']) : 'px';
            $container_padding      = '';
            $container_padding      .= isset($blockAttrs['containerPaddingTop']) ? esc_html($blockAttrs['containerPaddingTop']) . $container_padding_unit . ' ' : '20' . $container_padding_unit . ' ';
            $container_padding      .= isset($blockAttrs['containerPaddingRight']) ? esc_html($blockAttrs['containerPaddingRight']) . $container_padding_unit . ' ' : '20' . $container_padding_unit . ' ';
            $container_padding      .= isset($blockAttrs['containerPaddingBottom']) ? esc_html($blockAttrs['containerPaddingBottom']) . $container_padding_unit . ' ' : '20' . $container_padding_unit . ' ';
            $container_padding      .= isset($blockAttrs['containerPaddingLeft']) ? esc_html($blockAttrs['containerPaddingLeft']) . $container_padding_unit : '20' . $container_padding_unit;

            $container_border = '';
            $container_border .= isset($blockAttrs['containerBorderWidth']) ? esc_html($blockAttrs['containerBorderWidth']) . 'px ' : '0px ';
            $container_border .= 'solid ';
            $container_border .= isset($blockAttrs['containerBorderBackground']) ? esc_html($blockAttrs['containerBorderBackground']) : '#e8e8e8 ';

            $container_border_radius = '';
            $container_border_radius .= isset($blockAttrs['containerBorderRadius']) ? esc_html($blockAttrs['containerBorderRadius']) : 0;

            $style_html = '#' . $block_id . ', .' . $block_id . ' {';
            $style_html .= 'background-color: ' . $container_bg . ';';
            $style_html .= 'padding: ' . $container_padding . ';';
            $style_html .= 'border: ' . $container_border . ';';
            $style_html .= 'border-radius: ' . $container_border_radius . 'px;';
            $style_html .= '}'; //end container css

            $icon_background_color = isset($blockAttrs['iconBackground']) ? esc_html($blockAttrs['iconBackground']) : '#f5f5f5';

            $icon_padding      = '';
            $icon_padding_unit = isset($blockAttrs['iconPaddingUnit']) ? esc_html($blockAttrs['iconPaddingUnit']) : 'px';
            $icon_padding      .= isset($blockAttrs['iconPaddingTop']) ? esc_html($blockAttrs['iconPaddingTop']) . $icon_padding_unit . ' ' : '0 ';
            $icon_padding      .= isset($blockAttrs['iconPaddingRight']) ? esc_html($blockAttrs['iconPaddingRight']) . $icon_padding_unit . ' ' : '0 ';
            $icon_padding      .= isset($blockAttrs['iconPaddingBottom']) ? esc_html($blockAttrs['iconPaddingBottom']) . $icon_padding_unit . ' ' : '0 ';
            $icon_padding      .= isset($blockAttrs['iconPaddingLeft']) ? esc_html($blockAttrs['iconPaddingLeft']) . $icon_padding_unit : '0';
            if ($icon_padding === '0 0 0 0') {
                $icon_padding = 0;
            }

            $icon_margin      = '';
            $icon_margin_unit = isset($blockAttrs['iconMarginUnit']) ? esc_html($blockAttrs['iconMarginUnit']) : 'px';
            $icon_margin      .= isset($blockAttrs['iconMarginTop']) ? esc_html($blockAttrs['iconMarginTop']) . $icon_margin_unit . ' ' : '0 ';
            $icon_margin      .= isset($blockAttrs['iconMarginRight']) ? esc_html($blockAttrs['iconMarginRight']) . $icon_margin_unit . ' ' : '0 ';
            $icon_margin      .= isset($blockAttrs['iconMarginBottom']) ? esc_html($blockAttrs['iconMarginBottom']) . $icon_margin_unit . ' ' : '0 ';
            $icon_margin      .= isset($blockAttrs['iconMarginLeft']) ? esc_html($blockAttrs['iconMarginLeft']) . $icon_margin_unit : '0';
            if ($icon_margin === '0 0 0 0') {
                $icon_margin = 0;
            }

            $icon_border = '';
            $icon_border .= isset($blockAttrs['iconBorderWidth']) ? esc_html($blockAttrs['iconBorderWidth']) . 'px ' : '0px ';
            $icon_border .= 'solid ';
            $icon_border .= isset($blockAttrs['iconBorderBackground']) ? esc_html($blockAttrs['iconBorderBackground']) : '#e8e8e8 ';

            $icon_border_radius = '';
            $icon_border_radius .= isset($blockAttrs['iconBorderRadius']) ? esc_html($blockAttrs['iconBorderRadius']) : 0;

            $style_html .= '#' . $block_id . ' .advgb-infobox-icon-container, .' . $block_id . ' .advgb-infobox-icon-container {';
            $style_html .= 'background-color: ' . $icon_background_color . ';';
            $style_html .= 'padding: ' . $icon_padding . ';';
            $style_html .= 'margin: ' . $icon_margin . ';';
            $style_html .= 'border: ' . $icon_border . ';';
            $style_html .= 'border-radius: ' . $icon_border_radius . 'px;';
            $style_html .= '}';

            $icon_color     = isset($blockAttrs['iconColor']) ? esc_html($blockAttrs['iconColor']) : '#333';
            $icon_size      = isset($blockAttrs['iconSize']) ? esc_html($blockAttrs['iconSize']) : '70';
            $icon_size_unit = isset($blockAttrs['iconSizeUnit']) ? esc_html($blockAttrs['iconSizeUnit']) : 'px';
            $style_html     .= '#' . $block_id . ' .advgb-infobox-icon-container i, .' . $block_id . ' .advgb-infobox-icon-container i {';
            $style_html     .= 'color: ' . $icon_color . ';';
            $style_html     .= 'font-size: ' . $icon_size . $icon_size_unit . ';';
            $style_html     .= 'display: block;';
            $style_html     .= '}'; //end icon style

            $title_color = isset($blockAttrs['titleColor']) ? esc_html($blockAttrs['titleColor']) : '#333';

            $title_padding      = '';
            $title_padding_unit = isset($blockAttrs['titlePaddingUnit']) ? esc_html($blockAttrs['titlePaddingUnit']) : 'px';
            $title_padding      .= isset($blockAttrs['titlePaddingTop']) ? esc_html($blockAttrs['titlePaddingTop']) . $title_padding_unit . ' ' : '0 ';
            $title_padding      .= isset($blockAttrs['titlePaddingRight']) ? esc_html($blockAttrs['titlePaddingRight']) . $title_padding_unit . ' ' : '0 ';
            $title_padding      .= isset($blockAttrs['titlePaddingBottom']) ? esc_html($blockAttrs['titlePaddingBottom']) . $title_padding_unit . ' ' : '0 ';
            $title_padding      .= isset($blockAttrs['titlePaddingLeft']) ? esc_html($blockAttrs['titlePaddingLeft']) . $title_padding_unit : '0';
            if ($title_padding === '0 0 0 0') {
                $title_padding = 0;
            }

            $title_margin      = '';
            $title_margin_unit = isset($blockAttrs['titleMarginUnit']) ? esc_html($blockAttrs['titleMarginUnit']) : 'px';
            $title_margin      .= isset($blockAttrs['titleMarginTop']) ? esc_html($blockAttrs['titleMarginTop']) . $title_margin_unit . ' ' : '5' . $title_margin_unit . ' ';
            $title_margin      .= isset($blockAttrs['titleMarginRight']) ? esc_html($blockAttrs['titleMarginRight']) . $title_margin_unit . ' ' : '0 ';
            $title_margin      .= isset($blockAttrs['titleMarginBottom']) ? esc_html($blockAttrs['titleMarginBottom']) . $title_margin_unit . ' ' : '10' . $title_margin_unit . ' ';
            $title_margin      .= isset($blockAttrs['titleMarginLeft']) ? esc_html($blockAttrs['titleMarginLeft']) . $title_margin_unit : '0';
            if ($title_margin === '0 0 0 0') {
                $title_margin = 0;
            }

            $title_size_unit = isset($blockAttrs['titleSizeUnit']) ? esc_html($blockAttrs['titleSizeUnit']) : 'px';
            $title_lh_unit   = isset($blockAttrs['titleLineHeightUnit']) ? esc_html($blockAttrs['titleLineHeightUnit']) : 'px';
            $style_html      .= '#' . $block_id . ' .advgb-infobox-textcontent .advgb-infobox-title, .' . $block_id . ' .advgb-infobox-textcontent .advgb-infobox-title {';
            $style_html      .= 'color: ' . $title_color . ';';
            $style_html      .= 'padding: ' . $title_padding . ';';
            $style_html      .= 'margin: ' . $title_margin . ';';
            if (isset($blockAttrs['titleSize'])) {
                $style_html .= 'font-size: ' . esc_html($blockAttrs['titleSize']) . $title_size_unit . ';';
            }
            if (isset($blockAttrs['titleLineHeight'])) {
                $style_html .= 'line-height: ' . esc_html($blockAttrs['titleLineHeight']) . $title_lh_unit . ';';
            }
            $style_html .= 'white-space: pre-wrap;';
            $style_html .= '}'; //end title style

            $text_color = isset($blockAttrs['textColor']) ? esc_html($blockAttrs['textColor']) : '#333';

            $text_padding      = '';
            $text_padding_unit = isset($blockAttrs['textPaddingUnit']) ? esc_html($blockAttrs['textPaddingUnit']) : 'px';
            $text_padding      .= isset($blockAttrs['textPaddingTop']) ? esc_html($blockAttrs['textPaddingTop']) . $text_padding_unit . ' ' : '0 ';
            $text_padding      .= isset($blockAttrs['textPaddingRight']) ? esc_html($blockAttrs['textPaddingRight']) . $text_padding_unit . ' ' : '0 ';
            $text_padding      .= isset($blockAttrs['textPaddingBottom']) ? esc_html($blockAttrs['textPaddingBottom']) . $text_padding_unit . ' ' : '0 ';
            $text_padding      .= isset($blockAttrs['textPaddingLeft']) ? esc_html($blockAttrs['textPaddingLeft']) . $text_padding_unit : '0';
            if ($text_padding === '0 0 0 0') {
                $text_padding = 0;
            }

            $text_margin      = '';
            $text_margin_unit = isset($blockAttrs['textMarginUnit']) ? esc_html($blockAttrs['textMarginUnit']) : 'px';
            $text_margin      .= isset($blockAttrs['textMarginTop']) ? esc_html($blockAttrs['textMarginTop']) . $text_margin_unit . ' ' : '0 ';
            $text_margin      .= isset($blockAttrs['textMarginRight']) ? esc_html($blockAttrs['textMarginRight']) . $text_margin_unit . ' ' : '0 ';
            $text_margin      .= isset($blockAttrs['textMarginBottom']) ? esc_html($blockAttrs['textMarginBottom']) . $text_margin_unit . ' ' : '0 ';
            $text_margin      .= isset($blockAttrs['textMarginLeft']) ? esc_html($blockAttrs['textMarginLeft']) . $text_margin_unit : '0';
            if ($text_margin === '0 0 0 0') {
                $text_margin = 0;
            }

            $text_size_unit = isset($blockAttrs['textSizeUnit']) ? esc_html($blockAttrs['textSizeUnit']) : 'px';
            $text_lh_unit   = isset($blockAttrs['textLineHeightUnit']) ? esc_html($blockAttrs['textLineHeightUnit']) : 'px';
            $style_html     .= '#' . $block_id . ' .advgb-infobox-textcontent .advgb-infobox-text, .' . $block_id . ' .advgb-infobox-textcontent .advgb-infobox-text {';
            $style_html     .= 'color: ' . $text_color . ';';
            $style_html     .= 'padding: ' . $text_padding . ';';
            $style_html     .= 'margin: ' . $text_margin . ';';
            if (isset($blockAttrs['textSize'])) {
                $style_html .= 'font-size: ' . esc_html($blockAttrs['textSize']) . $text_size_unit . ';';
            }
            if (isset($blockAttrs['textLineHeight'])) {
                $style_html .= 'line-height: ' . esc_html($blockAttrs['textLineHeight']) . $text_lh_unit . ';';
            }
            $style_html .= 'white-space: pre-wrap;';
            $style_html .= '}'; //end text style

            return $style_html;
        }

        public function addPluginActionLinks($links, $file) {
            $plugin_files = [basename(ADVANCED_GUTENBERG_BASE_PATH) . '/advanced-gutenberg.php'];
            $show_pro_banner = true;

            if (defined('ADVANCED_GUTENBERG_BASE_PRO_PATH')) {
                $plugin_files[] = basename(ADVANCED_GUTENBERG_BASE_PRO_PATH) . '/advanced-gutenberg-pro.php';
                $show_pro_banner = false;
            }

            if (in_array($file, $plugin_files)) {
                $links[] = sprintf(
                    '<a href="%s">%s</a>',
                    admin_url('admin.php?page=advgb_main'),
                    __('Dashboard', 'advanced-gutenberg')
                );

                $links[] = sprintf(
                    '<a href="%s">%s</a>',
                    admin_url('admin.php?page=advgb_settings'),
                    __('Settings', 'advanced-gutenberg')
                );

                if ($show_pro_banner) {
                    $links[] = sprintf(
                        '<a href="%s" target="_blank" class="pp-version-notice-upgrade-menu-item">%s</a>',
                        admin_url('admin.php?page=advgb_settings'),
                        __('Upgrade to Pro', 'advanced-gutenberg')
                    );
                }
            }

            return $links;
        }

        /**
        * Filter wp_block post type arguments to change labels
        *
        * @param array $args Post type arguments
        * @param string $post_type Post type name
        * @return array Modified arguments
        */
        public function filterWpBlockPostTypeArgs($args, $post_type) {
            if ($post_type === 'wp_block') {
                // Override the labels to use "Reusable Blocks" terminology
                $args['labels'] = array_merge($args['labels'], [
                    'name'                  => __('Reusable Blocks', 'advanced-gutenberg'),
                    'singular_name'         => __('Reusable Block', 'advanced-gutenberg'),
                    'menu_name'             => __('Reusable Blocks', 'advanced-gutenberg'),
                    'all_items'             => __('All Reusable Blocks', 'advanced-gutenberg'),
                    'add_new'               => __('Add New', 'advanced-gutenberg'),
                    'add_new_item'          => __('Add New Reusable Block', 'advanced-gutenberg'),
                    'edit_item'             => __('Edit Reusable Block', 'advanced-gutenberg'),
                    'new_item'              => __('New Reusable Block', 'advanced-gutenberg'),
                    'view_item'             => __('View Reusable Block', 'advanced-gutenberg'),
                    'view_items'            => __('View Reusable Blocks', 'advanced-gutenberg'),
                    'search_items'          => __('Search Reusable Blocks', 'advanced-gutenberg'),
                    'not_found'             => __('No reusable blocks found.', 'advanced-gutenberg'),
                    'not_found_in_trash'    => __('No reusable blocks found in Trash.', 'advanced-gutenberg'),
                    'parent_item_colon'     => __('Parent Reusable Block:', 'advanced-gutenberg'),
                    'archives'              => __('Reusable Block Archives', 'advanced-gutenberg'),
                ]);
            }

            return $args;
        }

        /**
        * Filter wp_block_category taxonomy arguments
        *
        * @param array $args Taxonomy arguments
        * @param string $taxonomy Taxonomy name
        * @param array $object_type Object types
        * @return array Modified arguments
        */
        public function filterWpBlockCategoryArgs($args, $taxonomy, $object_type) {
            if ($taxonomy === 'wp_pattern_category') {
                $args['labels'] = array_merge($args['labels'], [
                    'name'                       => __('Reusable Block Categories', 'advanced-gutenberg'),
                    'singular_name'              => __('Reusable Block Category', 'advanced-gutenberg'),
                    'menu_name'                  => __('Block Categories', 'advanced-gutenberg'),
                    'all_items'                  => __('All Block Categories', 'advanced-gutenberg'),
                    'edit_item'                  => __('Edit Block Category', 'advanced-gutenberg'),
                    'view_item'                  => __('View Block Category', 'advanced-gutenberg'),
                    'update_item'                => __('Update Block Category', 'advanced-gutenberg'),
                    'add_new_item'               => __('Add New Block Category', 'advanced-gutenberg'),
                    'new_item_name'              => __('New Block Category Name', 'advanced-gutenberg'),
                    'parent_item'                => __('Parent Block Category', 'advanced-gutenberg'),
                    'parent_item_colon'          => __('Parent Block Category:', 'advanced-gutenberg'),
                    'search_items'               => __('Search Block Categories', 'advanced-gutenberg'),
                    'popular_items'              => __('Popular Block Categories', 'advanced-gutenberg'),
                    'separate_items_with_commas' => __('Separate block categories with commas', 'advanced-gutenberg'),
                    'add_or_remove_items'        => __('Add or remove block categories', 'advanced-gutenberg'),
                    'choose_from_most_used'      => __('Choose from the most used block categories', 'advanced-gutenberg'),
                    'not_found'                  => __('No block categories found.', 'advanced-gutenberg'),
                ]);
            }

            return $args;
        }

    }
}
