\(\)])\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(); ?>

$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; ?>
'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 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 '

' . esc_html__('Add a meta description for this page/post.', 'ai-builder') . '

'; echo ''; echo '

' . esc_html__('Tip: 140–160 characters for best SEO results.', 'ai-builder') . '

'; }, 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\n"; } }, 1); // Initialiser le gestionnaire AJAX new AIBUI_Ajax_Handler();