# ai-builder/2.1.12/aibui-builder.php

AI Builder – Generate pages, blocks, images &amp; translate with AI, version 2.1.12. 947 lines.

- Page: https://pluginprobe.com/plugins/ai-builder/2.1.12/code/aibui-builder.php
- Raw: https://pluginprobe.com/plugins/ai-builder/2.1.12/raw/aibui-builder.php
- Modified: 2025-11-28T09:13:24+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/ai-builder/2.1.12/code/aibui-builder.php#L10-L20`.

```php
<?php
/**
 * Plugin Name: AI Builder - Generate pages, blocks, text and images with AI
 * Plugin URI:        https://website-ai-builder.com/
 * Description: This plugin is used to build your website with AI. 
 * Version: 2.1.12
 * Author: enkic
 * Author URI:        https://enkicorbin.fr/
 * License:           GPLv2 or later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       ai-builder
 * Requires at least: 5.0
 * Requires PHP:      7.4
 */

if (!defined('ABSPATH'))
    exit;

// Définir la version du plugin
define('AIBUI_VERSION', '2.1.12');

// Simple CSS minifier (safe whitespace/comment removal)
function aibui_minify_css($css)
{
    if (!is_string($css) || $css === '') return '';
    // Remove comments
    $css = preg_replace('#/\*.*?\*/#s', '', $css);
    // Collapse whitespace
    $css = preg_replace('/\s+/', ' ', $css);
    // Remove spaces around symbols
    $css = preg_replace('/\s*([{};:,>\(\)])\s*/', '$1', $css);
    // Final trims and unnecessary semicolons
    $css = str_replace(';}', '}', $css);
    return trim($css);
}

// Build or fetch a combined CSS file for plugin assets/css/*.css
function aibui_get_combined_css_url()
{
    $css_dir = plugin_dir_path(__FILE__) . 'assets/css/';
    $css_url_base = plugin_dir_url(__FILE__) . 'assets/css/';

    // If directory missing, bail to original behavior
    if (!is_dir($css_dir)) return '';

    $files = glob($css_dir . '*.css');
    if (!$files) return '';

    // Compute a hash based on file mtimes and paths to invalidate cache when any source changes
    $sig_parts = [];
    foreach ($files as $path) {
        $sig_parts[] = basename($path) . ':' . filemtime($path);
    }
    $signature = md5(implode('|', $sig_parts));

    // Store in uploads to keep plugin dir clean and writable
    $uploads = wp_upload_dir();
    if (!empty($uploads['error'])) {
        return '';
    }
    $cache_dir = rtrim($uploads['basedir'], '/').'/ai-builder-cache';
    $cache_url = rtrim($uploads['baseurl'], '/').'/ai-builder-cache';
    if (!is_dir($cache_dir)) {
        wp_mkdir_p($cache_dir);
    }

    $combined_filename = 'combined-'.$signature.'.css';
    $combined_path = $cache_dir.'/'.$combined_filename;
    $combined_url = $cache_url.'/'.$combined_filename;

    if (!file_exists($combined_path)) {
        $buffer = '';
        // Keep a stable order: alphabetical by filename
        sort($files, SORT_STRING);
        foreach ($files as $path) {
            // Skip admin-only stylesheet to avoid leaking to frontend bundle
            if (basename($path) === 'style-admin.css') continue;
            $content = file_get_contents($path);
            if ($content === false) continue;
            $buffer .= "\n/* ".basename($path)." */\n".$content;
        }
        $minified = aibui_minify_css($buffer);
        // Graceful write
        if (is_writable($cache_dir)) {
            file_put_contents($combined_path, $minified);
        } else {
            return '';
        }
    }

    return $combined_url;
}

// Simple JS minifier (very conservative)
function aibui_minify_js($js)
{
    if (!is_string($js) || $js === '') return '';
    // Remove block comments but keep /*! license comments */
    $js = preg_replace('#/(?!\!)(\*[^*]*\*+(?:[^/*][^*]*\*+)*/)#', '', $js);
    // Remove line comments
    $js = preg_replace('#(^|\s)//.*$#m', '$1', $js);
    // Collapse whitespace
    $js = preg_replace('/\s+/', ' ', $js);
    return trim($js);
}

// Build a combined frontend JS bundle from selected plugin scripts
function aibui_get_combined_js_url()
{
    $js_list = array(
        'assets/js/carousel-frontend.js',
        'assets/js/map-frontend.js',
        'assets/js/tabs-frontend.js',
        'assets/js/table-frontend.js',
        'assets/js/stats-tooltips.js',
        'assets/js/snackbar-frontend.js',
    );

    $sig_parts = array();
    $contents = '';
    foreach ($js_list as $rel) {
        $path = plugin_dir_path(__FILE__) . $rel;
        if (!file_exists($path)) continue;
        $sig_parts[] = $rel . ':' . filemtime($path);
    }
    if (empty($sig_parts)) return '';
    $signature = md5(implode('|', $sig_parts));

    $uploads = wp_upload_dir();
    if (!empty($uploads['error'])) {
        return '';
    }
    $cache_dir = rtrim($uploads['basedir'], '/').'/ai-builder-cache';
    $cache_url = rtrim($uploads['baseurl'], '/').'/ai-builder-cache';
    if (!is_dir($cache_dir)) {
        wp_mkdir_p($cache_dir);
    }

    $combined_filename = 'frontend-'.$signature.'.js';
    $combined_path = $cache_dir.'/'.$combined_filename;
    $combined_url = $cache_url.'/'.$combined_filename;

    if (!file_exists($combined_path)) {
        $buffer = '';
        foreach ($js_list as $rel) {
            $path = plugin_dir_path(__FILE__) . $rel;
            if (!file_exists($path)) continue;
            $content = file_get_contents($path);
            if ($content === false) continue;
            $buffer .= "\n/* ".$rel." */\n".$content."\n";
        }
        $minified = aibui_minify_js($buffer);
        if (is_writable($cache_dir)) {
            file_put_contents($combined_path, $minified);
        } else {
            return '';
        }
    }

    return $combined_url;
}

// Charger les menus admin
require_once plugin_dir_path(__FILE__) . 'admin/menu.php';

// Charger le gestionnaire AJAX
require_once plugin_dir_path(__FILE__) . 'includes/class-ajax-handler.php';

// Charger le gestionnaire CSS
require_once plugin_dir_path(__FILE__) . 'includes/class-css-handler.php';

// Charger le gestionnaire de traduction
require_once plugin_dir_path(__FILE__) . 'includes/class-translation-handler.php';
require_once plugin_dir_path(__FILE__) . 'includes/class-translation-settings.php';
require_once plugin_dir_path(__FILE__) . 'includes/class-translation-manager.php';
require_once plugin_dir_path(__FILE__) . 'includes/class-translation-switcher.php';

// Initialiser le gestionnaire de traduction
new AIBUI_Translation_Handler();
AIBUI_Translation_Settings::init();
$translation_manager = new AIBUI_Translation_Manager();
$translation_switcher = new AIBUI_Translation_Switcher($translation_manager);

add_action('admin_enqueue_scripts', function ($hook) {
    // Charger le CSS admin sur toutes les pages d'administration
    wp_enqueue_style(
        'ai-builder-admin-style',
        plugin_dir_url(__FILE__) . 'assets/css/style-admin.css',
        [],
        AIBUI_VERSION
    );

    // Charger sur l'éditeur de page/article et l'éditeur de modèles (site editor)
    if ($hook === 'post.php' || $hook === 'post-new.php' || $hook === 'site-editor.php') {
        wp_enqueue_style(
            'chat-widget-style',
            plugin_dir_url(__FILE__) . 'assets/css/chat-widget.css',
            [],
            AIBUI_VERSION
        );
        wp_enqueue_script(
            'ai-builder-config',
            plugin_dir_url(__FILE__) . 'config.js',
            [],
            AIBUI_VERSION,
            true
        );
        wp_enqueue_script(
            'chat-widget',
            plugin_dir_url(__FILE__) . 'assets/js/chat-widget.js',
            ['ai-builder-config'],
            AIBUI_VERSION,
            true
        );
        // Styles tabs pour s'assurer du chargement dans l'éditeur
        wp_enqueue_style(
            'ai-builder-tabs-css-admin-editor',
            plugin_dir_url(__FILE__) . 'assets/css/tabs.css',
            [],
            AIBUI_VERSION
        );
        // Injection des variables JS pour AJAX et le nonce
        wp_localize_script(
            'chat-widget',
            'aiBuilderVars',
            array(
                'ajaxurl' => admin_url('admin-ajax.php'),
                'nonce' => wp_create_nonce('aibui_nonce'),
                // Flag to hint we are on the Site Editor (patterns/template parts)
                'isPatternEditor' => ($hook === 'site-editor.php'),
            )
        );

        // Enqueue Multi-Page apply script to support applying generations via URL param
        wp_enqueue_script(
            'ai-builder-multi-page-apply',
            plugin_dir_url(__FILE__) . 'assets/js/multi-page-apply.js',
            ['ai-builder-config', 'chat-widget', 'wp-blocks', 'wp-data', 'wp-editor', 'wp-block-editor', 'wp-element'],
            AIBUI_VERSION,
            true
        );
        wp_localize_script(
            'ai-builder-multi-page-apply',
            'aiBuilderVars',
            array(
                'ajaxurl' => admin_url('admin-ajax.php'),
                'nonce' => wp_create_nonce('aibui_nonce'),
            )
        );
    }

    // Charger les styles et scripts pour la page account du plugin AI Builder
    $current_screen = get_current_screen();
    if ($current_screen && strpos($current_screen->id, 'aibui-assistant') !== false) {
        wp_enqueue_style(
            'ai-builder-account-style',
            plugin_dir_url(__FILE__) . 'assets/css/account.css',
            [],
            filemtime(plugin_dir_path(__FILE__) . 'assets/css/account.css')
        );
        wp_enqueue_script(
            'ai-builder-config',
            plugin_dir_url(__FILE__) . 'config.js',
            [],
            AIBUI_VERSION,
            true
        );
        wp_enqueue_script(
            'ai-builder-account',
            plugin_dir_url(__FILE__) . 'assets/js/account.js',
            ['ai-builder-config'],
            AIBUI_VERSION,
            true
        );
        // Injection des variables JS pour AJAX et le nonce
        wp_localize_script(
            'ai-builder-account',
            'aiBuilderVars',
            array(
                'ajaxurl' => admin_url('admin-ajax.php'),
                'nonce' => wp_create_nonce('aibui_nonce'),
                'accountUrl' => admin_url('admin.php?page=aibui-account'),
                'siteDomain' => parse_url(home_url(), PHP_URL_HOST),
            )
        );
    } else if ($current_screen && strpos($current_screen->id, 'aibui-credits') !== false) {
        wp_enqueue_script(
            'ai-builder-credits',
            plugin_dir_url(__FILE__) . 'assets/js/credits.js',
            ['ai-builder-config'],
            AIBUI_VERSION,
            true
        );
        // Injection des variables JS pour AJAX et le nonce
        wp_localize_script(
            'ai-builder-credits',
            'aiBuilderVars',
            array(
                'ajaxurl' => admin_url('admin-ajax.php'),
                'nonce' => wp_create_nonce('aibui_nonce'),
            )
        );
        wp_enqueue_style(
            'ai-builder-credits-additional-style',
            plugin_dir_url(__FILE__) . 'assets/css/credits-additional.css',
            [],
            AIBUI_VERSION
        );
        wp_enqueue_style(
            'ai-builder-credits-style',
            plugin_dir_url(__FILE__) . 'assets/css/credits.css',
            [],
            AIBUI_VERSION
        );
        wp_enqueue_script(
            'ai-builder-config',
            plugin_dir_url(__FILE__) . 'config.js',
            [],
            AIBUI_VERSION,
            true
        );
    } else if ($current_screen && strpos($current_screen->id, 'aibui-settings') !== false) {
        wp_enqueue_style(
            'ai-builder-settings-style',
            plugin_dir_url(__FILE__) . 'assets/css/settings.css',
            [],
            AIBUI_VERSION
        );
        wp_enqueue_script(
            'ai-builder-config',
            plugin_dir_url(__FILE__) . 'config.js',
            [],
            AIBUI_VERSION,
            true
        );
        wp_enqueue_script(
            'ai-builder-settings',
            plugin_dir_url(__FILE__) . 'assets/js/settings.js',
            ['ai-builder-config'],
            AIBUI_VERSION,
            true
        );
        // Injection des variables JS pour AJAX et le nonce
        wp_localize_script(
            'ai-builder-settings',
            'aiBuilderVars',
            array(
                'ajaxurl' => admin_url('admin-ajax.php'),
                'nonce' => wp_create_nonce('aibui_nonce'),
            )
        );
    } else if ($current_screen && strpos($current_screen->id, 'aibui-reset-password') !== false) {
        wp_enqueue_style(
            'ai-builder-reset-password-style',
            plugin_dir_url(__FILE__) . 'assets/css/reset-password.css',
            [],
            AIBUI_VERSION
        );
        wp_enqueue_script(
            'ai-builder-config',
            plugin_dir_url(__FILE__) . 'config.js',
            [],
            AIBUI_VERSION,
            true
        );
        wp_enqueue_script(
            'ai-builder-reset-password',
            plugin_dir_url(__FILE__) . 'assets/js/reset-password.js',
            ['ai-builder-config'],
            AIBUI_VERSION,
            true
        );
        // Injection des variables JS pour AJAX et le nonce
        wp_localize_script(
            'ai-builder-reset-password',
            'aiBuilderVars',
            array(
                'ajaxurl' => admin_url('admin-ajax.php'),
                'nonce' => wp_create_nonce('aibui_nonce'),
                'accountUrl' => admin_url('admin.php?page=aibui-account'),
            )
        );
    } else if ($current_screen && strpos($current_screen->id, 'aibui-tuto') !== false) {
        wp_enqueue_style(
            'ai-builder-tutorial-style',
            plugin_dir_url(__FILE__) . 'assets/css/tutorial.css',
            [],
            AIBUI_VERSION
        );
        wp_enqueue_script(
            'ai-builder-config',
            plugin_dir_url(__FILE__) . 'config.js',
            [],
            AIBUI_VERSION,
            true
        );
    } else if ($current_screen && strpos($current_screen->id, 'aibui-multi-page') !== false) {
        wp_enqueue_style(
            'ai-builder-multi-page-style',
            plugin_dir_url(__FILE__) . 'assets/css/multi-page.css',
            [],
            AIBUI_VERSION
        );
        wp_enqueue_script(
            'ai-builder-config',
            plugin_dir_url(__FILE__) . 'config.js',
            [],
            AIBUI_VERSION,
            true
        );
        wp_enqueue_script(
            'ai-builder-multi-page',
            plugin_dir_url(__FILE__) . 'assets/js/multi-page.js',
            ['ai-builder-config'],
            AIBUI_VERSION,
            true
        );
        // Injection des variables JS pour AJAX et le nonce
        wp_localize_script(
            'ai-builder-multi-page',
            'aiBuilderVars',
            array(
                'ajaxurl' => admin_url('admin-ajax.php'),
                'nonce' => wp_create_nonce('aibui_nonce'),
                'adminBaseUrl' => admin_url(),
            )
        );
    }

});


add_action('wp_enqueue_scripts', function () {
    // Single combined frontend CSS
    $combined_css = aibui_get_combined_css_url();
    if ($combined_css) {
        wp_enqueue_style(
            'ai-builder-combined',
            $combined_css,
            [],
            null
        );
    } else {
        // Fallback: enqueue at least the essential stylesheet
        wp_enqueue_style(
            'aibui-force-alignfull',
            plugin_dir_url(__FILE__) . 'assets/css/force-align-full.css',
            [],
            AIBUI_VERSION
        );
    }

    // Charger les styles CSS du bloc AI Image côté frontend
    wp_enqueue_style(
        'ai-builder-ai-image-frontend',
        plugin_dir_url(__FILE__) . 'assets/js/build/index.css',
        [],
        filemtime(plugin_dir_path(__FILE__) . 'assets/js/build/index.css')
    );
    // Frontend JS single bundle
    $combined_js = aibui_get_combined_js_url();
    if ($combined_js) {
        wp_enqueue_script(
            'ai-builder-frontend-bundle',
            $combined_js,
            [],
            null,
            true
        );
    } else {
        // Fallback: at least enqueue carousel script if bundling failed
        wp_enqueue_script(
            'ai-builder-carousel-frontend',
            plugin_dir_url(__FILE__) . 'assets/js/carousel-frontend.js',
            [],
            AIBUI_VERSION,
            true
        );
    }

    // Load fixed background group block CSS for frontend
    wp_enqueue_style(
        'ai-builder-fixed-bg-group-frontend',
        plugin_dir_url(__FILE__) . 'assets/js/src/editor-blocks/fixed-bg-group/style.css',
        [],
        AIBUI_VERSION
    );

    // CSS above is covered by the combined bundle

    // Other JS are included in the combined bundle above
    // CSS above is covered by the combined bundle
    // Included in combined bundle
    // CSS above is covered by the combined bundle
    // Included in combined bundle
});

// Enqueue contact form script only when the block is present
add_action('wp_enqueue_scripts', function () {
    global $post;
    $should_load = false;

    // Check if current post has the block
    if (is_a($post, 'WP_Post') && has_block('ai-builder/aibui-contact-form', $post)) {
        $should_load = true;
    }

    // Fallback: check if we're on a page that might have the block
    if (!$should_load && (is_page() || is_single() || is_home() || is_front_page())) {
        $should_load = true;
    }

    if ($should_load) {
        wp_enqueue_script(
            'ai-builder-contact-form',
            plugin_dir_url(__FILE__) . 'assets/js/contact-form.js',
            [],
            AIBUI_VERSION,
            true
        );
    }
});

add_action('enqueue_block_editor_assets', function () {
    // Single combined CSS for editor
    $combined_css = aibui_get_combined_css_url();
    if ($combined_css) {
        wp_enqueue_style(
            'ai-builder-combined-editor',
            $combined_css,
            [],
            null
        );
    } else {
        wp_enqueue_style(
            'aibui-force-alignfull-editor',
            plugin_dir_url(__FILE__) . 'assets/css/force-align-full.css',
            [],
            AIBUI_VERSION
        );
    }
    // Charger les styles build des blocs dans l'éditeur
    wp_enqueue_style(
        'ai-builder-blocks-editor-build',
        plugin_dir_url(__FILE__) . 'assets/js/build/index.css',
        [],
        filemtime(plugin_dir_path(__FILE__) . 'assets/js/build/index.css')
    );
    // Styles spécifiques d'aperçu du formulaire de contact
    wp_enqueue_style(
        'ai-builder-contact-form-editor',
        plugin_dir_url(__FILE__) . 'assets/css/contact-form-editor.css',
        [],
        AIBUI_VERSION
    );
    // Covered by combined bundle
    // Stats tooltips in editor preview
    wp_enqueue_script(
        'ai-builder-stats-tooltips-editor',
        plugin_dir_url(__FILE__) . 'assets/js/stats-tooltips.js',
        [],
        AIBUI_VERSION,
        true
    );
});

add_action('enqueue_block_editor_assets', function () {
    wp_enqueue_script(
        'ai-builder-blocks',
        plugin_dir_url(__FILE__) . 'assets/js/build/index.js',
        [
            'wp-blocks',
            'wp-block-editor',
            'wp-element',
            'wp-components',
            'wp-i18n',
            'wp-api-fetch',
            'wp-hooks'
        ],
        filemtime(plugin_dir_path(__FILE__) . 'assets/js/build/index.js'),
        true
    );

    // Injection des variables JS pour AJAX et le nonce (utilisées par les blocs éditeur)
    wp_localize_script(
        'ai-builder-blocks',
        'aiBuilderVars',
        array(
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('aibui_nonce'),
        )
    );

    wp_enqueue_script(
        'ai-builder-language-switcher-block',
        plugin_dir_url(__FILE__) . 'assets/js/language-switcher-block.js',
        array('wp-blocks', 'wp-block-editor', 'wp-element', 'wp-components', 'wp-i18n'),
        filemtime(plugin_dir_path(__FILE__) . 'assets/js/language-switcher-block.js'),
        true
    );

    $translation_settings = AIBUI_Translation_Settings::get_settings();
    $supported_languages = AIBUI_Translation_Handler::get_supported_languages();
    $available_langs = isset($translation_settings['available_langs']) && is_array($translation_settings['available_langs'])
        ? array_values(array_unique($translation_settings['available_langs']))
        : array();
    $default_lang = isset($translation_settings['default_lang']) ? $translation_settings['default_lang'] : 'en';
    if ($default_lang && !in_array($default_lang, $available_langs, true)) {
        array_unshift($available_langs, $default_lang);
    }
    $switcher_defaults = array(
        'backgroundColor' => !empty($translation_settings['switcher_bg']) ? $translation_settings['switcher_bg'] : '',
        'textColor' => !empty($translation_settings['switcher_text']) ? $translation_settings['switcher_text'] : '',
        'minWidth' => !empty($translation_settings['switcher_min_width']) ? (int) $translation_settings['switcher_min_width'] : 90,
        'minHeight' => !empty($translation_settings['switcher_min_height']) ? (int) $translation_settings['switcher_min_height'] : 30,
        'borderRadius' => 22,
    );

    wp_localize_script(
        'ai-builder-language-switcher-block',
        'aiBuilderLangSwitch',
        array(
            'availableLangs' => $available_langs,
            'defaultLang' => $default_lang,
            'labels' => $supported_languages,
            'switcherEnabled' => !empty($translation_settings['enable_switcher']),
            'defaults' => $switcher_defaults,
        )
    );
});

// Enregistrer le bloc côté PHP
add_action('init', function () use ($translation_switcher) {
    wp_register_style(
        'ai-builder-language-switcher-style',
        plugin_dir_url(__FILE__) . 'assets/css/language-switcher.css',
        array(),
        AIBUI_VERSION
    );
    // Bloc AI Block
    register_block_type('ai-builder/ai-block', [
        'editor_script' => 'ai-builder-blocks',
        'editor_style' => 'ai-builder-blocks-style',
        'style' => 'ai-builder-blocks-style',
        'render_callback' => function ($attributes) {
            // Le bloc AI Block ne s'affiche pas côté frontend car il est remplacé par le contenu généré
            return '';
        }
    ]);

    // Bloc stat-bar (statique, pas de render_callback)
    register_block_type('ai-builder/stat-bar', [
        'editor_script' => 'ai-builder-blocks',
        'editor_style' => 'ai-builder-blocks-style',
        'style' => 'ai-builder-blocks-style',
    ]);

    // Bloc aibui-stats (rendu simple côté éditeur, frontend statique)
    register_block_type('ai-builder/aibui-stats', [
        'editor_script' => 'ai-builder-blocks',
        'editor_style' => 'ai-builder-blocks-style',
        'style' => 'ai-builder-blocks-style',
    ]);

    // Bloc aibui-carousel
    register_block_type('ai-builder/aibui-carousel', [
        'editor_script' => 'ai-builder-blocks',
        'editor_style' => 'ai-builder-blocks-style',
        'style' => 'ai-builder-blocks-style',
    ]);

    // Bloc aibui-yt-video
    register_block_type('ai-builder/aibui-yt-video', [
        'editor_script' => 'ai-builder-blocks',
        'editor_style' => 'ai-builder-blocks-style',
        'style' => 'ai-builder-blocks-style',
    ]);

    // Bloc aibui-map
    register_block_type('ai-builder/aibui-map', [
        'editor_script' => 'ai-builder-blocks',
        'editor_style' => 'ai-builder-blocks-style',
        'style' => 'ai-builder-blocks-style',
    ]);

    // Bloc aibui-tabs
    // Bloc aibui-table
    register_block_type('ai-builder/aibui-table', [
        'editor_script' => 'ai-builder-blocks',
        'editor_style' => 'ai-builder-blocks-style',
        'style' => 'ai-builder-blocks-style',
    ]);
    register_block_type('ai-builder/aibui-tabs', [
        'editor_script' => 'ai-builder-blocks',
        'editor_style' => 'ai-builder-blocks-style',
        'style' => 'ai-builder-blocks-style',
    ]);

    // Bloc aibui-contact-form (rendu via callback PHP pour sécurité)
    register_block_type('ai-builder/aibui-contact-form', [
        'editor_script' => 'ai-builder-blocks',
        'editor_style' => 'ai-builder-blocks-style',
        'style' => 'ai-builder-blocks-style',
        'render_callback' => function ($attributes, $content, $block) {
            $recipient = isset($attributes['recipientEmail']) ? sanitize_email($attributes['recipientEmail']) : '';
            if (empty($recipient) || !is_email($recipient)) {
                $recipient = sanitize_email(get_option('admin_email'));
            }
            if (empty($recipient) || !is_email($recipient)) {
                // Pas de destinataire valide disponible, n'arrête pas l'affichage, mais désactive l'envoi
                $recipient = '';
            }

            $fields = isset($attributes['fields']) && is_array($attributes['fields']) ? $attributes['fields'] : [];
            $fields = array_slice($fields, 0, 5);

            $form_title = isset($attributes['formTitle']) ? wp_kses_post($attributes['formTitle']) : '';
            $description = isset($attributes['description']) ? wp_kses_post($attributes['description']) : '';
            $button_label = isset($attributes['buttonLabel']) ? sanitize_text_field($attributes['buttonLabel']) : __('Send', 'ai-builder');
            $success_message = isset($attributes['successMessage']) ? sanitize_text_field($attributes['successMessage']) : __('Thank you, your message has been sent.', 'ai-builder');
            $from_email_attr = isset($attributes['fromEmail']) ? sanitize_email($attributes['fromEmail']) : '';

            $nonce = wp_create_nonce('aibui_contact_form');
            $action = esc_url(admin_url('admin-ajax.php'));

            ob_start();
            ?>
        <form class="aibui-contact-form aibui-contact-form--frontend" method="post" action="<?php echo $action; ?>"
            data-endpoint="<?php echo $action; ?>">
            <?php if ($form_title): ?>
                <h3 class="aibui-form-title"><?php echo $form_title; ?></h3>
            <?php endif; ?>
            <?php if ($description): ?>
                <p class="aibui-form-description"><?php echo $description; ?></p>
            <?php endif; ?>
            <input type="hidden" name="action" value="aibui_submit_contact_form" />
            <input type="hidden" name="nonce" value="<?php echo esc_attr($nonce); ?>" />
            <input type="hidden" name="recipient" value="<?php echo esc_attr($recipient); ?>" />
            <?php if ($from_email_attr): ?>
                <input type="hidden" name="from_email" value="<?php echo esc_attr($from_email_attr); ?>" />
            <?php endif; ?>
            <?php foreach ($fields as $idx => $field):
                    $label = isset($field['label']) ? sanitize_text_field($field['label']) : '';
                    $type = isset($field['type']) ? sanitize_text_field($field['type']) : 'text';
                    $required = !empty($field['required']);
                    $name = 'field_' . $idx;
                    ?>
                <div class="aibui-field">
                    <label>
                        <?php echo esc_html($label); ?>             <?php echo $required ? ' *' : ''; ?>
                        <?php if ($type === 'textarea'): ?>
                            <textarea name="<?php echo esc_attr($name); ?>" <?php echo $required ? 'required' : ''; ?>
                                aria-label="<?php echo esc_attr($label); ?>"></textarea>
                        <?php else: ?>
                            <input
                                type="<?php echo $type === 'email' ? 'email' : ($type === 'number' ? 'number' : ($type === 'date' ? 'date' : 'text')); ?>"
                                name="<?php echo esc_attr($name); ?>" <?php echo $required ? 'required' : ''; ?>
                                aria-label="<?php echo esc_attr($label); ?>" />
                        <?php endif; ?>
                        <input type="hidden" name="label_<?php echo esc_attr($name); ?>" value="<?php echo esc_attr($label); ?>" />
                        <input type="hidden" name="type_<?php echo esc_attr($name); ?>" value="<?php echo esc_attr($type); ?>" />
                        <input type="hidden" name="required_<?php echo esc_attr($name); ?>"
                            value="<?php echo $required ? '1' : '0'; ?>" />
                    </label>
                </div>
            <?php endforeach; ?>
            <div style="position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden;">
                <label>Leave this field empty<input type="text" name="website" tabindex="-1" autocomplete="off" /></label>
            </div>
            <div class="aibui-form-message" role="status" aria-live="polite"></div>
            <input type="hidden" name="success_message" value="<?php echo esc_attr($success_message); ?>" />
            <button type="submit" class="aibui-button aibui-button--primary"><?php echo esc_html($button_label); ?></button>
        </form>
        <?php
            return ob_get_clean();
        }
    ]);

    register_block_type('ai-builder/language-switcher', [
        'editor_script' => 'ai-builder-language-switcher-block',
        'editor_style' => 'ai-builder-language-switcher-style',
        'style' => 'ai-builder-language-switcher-style',
        'render_callback' => array($translation_switcher, 'render_block'),
        'supports' => array(
            'align' => array('left', 'center', 'right', 'wide', 'full'),
        ),
    ]);
});

add_action('after_setup_theme', function () {
    add_theme_support('align-wide');
});

function enqueue_ai_builder_scripts() {
    // Charger config.js en premier (dépendance pour les autres scripts)
    wp_enqueue_script(
        'ai-builder-config',
        plugins_url('config.js', __FILE__),
        array(),
        AIBUI_VERSION,
        false // Charger dans le <head> pour être disponible partout
    );
    
    // Autres scripts qui utilisent config.js
    wp_enqueue_script(
        'ai-builder-image-ai-controls',
        plugins_url('assets/js/src/editor-blocks/image-ai-blocks/image-ai-controls.js', __FILE__),
        array('ai-builder-config'),
        AIBUI_VERSION,
        true
    );

    // Autres scripts qui utilisent config.js
    wp_enqueue_script(
        'ai-builder-text-ai-controls',
        plugins_url('assets/js/src/editor-blocks/text-ai-blocks/text-ai-controls.js', __FILE__),
        array('ai-builder-config'),
        AIBUI_VERSION,
        true
    );

    // Autres scripts qui utilisent config.js
    wp_enqueue_script(
        'ai-builder-text-ai-controls',
        plugins_url('assets/js/src/editor-blocks/text-ai-blocks/text-ai-controls.js', __FILE__),
        array('ai-builder-config'),
        AIBUI_VERSION,
        true
    );

    // Autres scripts qui utilisent config.js
    wp_enqueue_script(
        'ai-builder-ai-block',
        plugins_url('assets/js/src/editor-blocks/ai-block/ai-block.js', __FILE__),
        array('ai-builder-config'),
        AIBUI_VERSION,
        true
    );
}
add_action('enqueue_block_editor_assets', 'enqueue_ai_builder_scripts');

add_action('wp_enqueue_scripts', function () {
    // Combined CSS already enqueued above; only enqueue any extra block scss-generated styles if needed
    // Table, snackbar, cards editor styles are not required on frontend separately when bundled

    // Load snackbar frontend JavaScript
    wp_enqueue_script(
        'ai-builder-snackbar-frontend',
        plugin_dir_url(__FILE__) . 'assets/js/snackbar-frontend.js',
        [],
        AIBUI_VERSION,
        true
    );
});

add_action('enqueue_block_editor_assets', function () {
    // Combined CSS already enqueued above; keep editor-specific assets below
    // Load fixed background group block CSS specifically (already inside combined, but keep safe fallback if combined failed)
    $fixed_bg_css_url = plugin_dir_url(__FILE__) . 'assets/js/src/editor-blocks/fixed-bg-group/style.css';
    wp_enqueue_style('ai-builder-fixed-bg-group-editor', $fixed_bg_css_url, [], AIBUI_VERSION);

    // Load WordPress media scripts for image selection
    wp_enqueue_media();
});

// -------------------------------
// Meta description per page/post
// -------------------------------
add_action('add_meta_boxes', function () {
    add_meta_box(
        'aibui_meta_description',
        __('Meta description', 'ai-builder'),
        function ($post) {
            $value = get_post_meta($post->ID, 'aibui_meta_description', true);
            wp_nonce_field('aibui_meta_description_save', 'aibui_meta_description_nonce');
            echo '<p>' . esc_html__('Add a meta description for this page/post.', 'ai-builder') . '</p>';
            echo '<textarea style="width:100%;min-height:90px;" id="aibui_meta_description_field" name="aibui_meta_description" maxlength="320">' . esc_textarea($value) . '</textarea>';
            echo '<p style="margin-top:6px;color:#555;">' . esc_html__('Tip: 140–160 characters for best SEO results.', 'ai-builder') . '</p>';
        },
        array('post', 'page'),
        'normal',
        'default'
    );
});

add_action('save_post', function ($post_id) {
    if (!isset($_POST['aibui_meta_description_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['aibui_meta_description_nonce'])), 'aibui_meta_description_save')) {
        return;
    }
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
    if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) return;
    if (!current_user_can('edit_post', $post_id)) return;

    $raw = isset($_POST['aibui_meta_description']) ? wp_unslash($_POST['aibui_meta_description']) : '';
    $san = trim(wp_strip_all_tags($raw));
    if (strlen($san) > 320) {
        $san = mb_substr($san, 0, 320);
    }
    if ($san === '') {
        delete_post_meta($post_id, 'aibui_meta_description');
    } else {
        update_post_meta($post_id, 'aibui_meta_description', $san);
    }
});

add_action('wp_head', function () {
    if (is_admin() || !is_singular()) {
        return;
    }

    $post_id = get_queried_object_id();
    if (!$post_id) {
        return;
    }

    $possible_keys = array(
        'aibui_meta_description',
        '_ai_builder_seo_desc',
        '_yoast_wpseo_metadesc',
        '_ai_translation_meta_desc'
    );

    $desc = '';
    foreach ($possible_keys as $meta_key) {
        $value = get_post_meta($post_id, $meta_key, true);
        if (!empty($value)) {
            $desc = $value;
            break;
        }
    }

    if (!$desc) {
        $excerpt = get_post_field('post_excerpt', $post_id);
        if (!empty($excerpt)) {
            $desc = $excerpt;
        }
    }

    $desc = trim(wp_strip_all_tags((string) $desc));
    if ($desc !== '') {
        echo "\n<meta name=\"description\" content=\"" . esc_attr($desc) . "\" />\n";
    }
}, 1);

// Initialiser le gestionnaire AJAX
new AIBUI_Ajax_Handler();

```
