$token)); } public function save_post_css() { // Vérifier que les données POST existent if (!isset($_POST['nonce']) || !isset($_POST['post_id']) || !isset($_POST['css_content'])) { wp_send_json_error('Missing required data'); } // Déséchapper et assainir les données $nonce = sanitize_text_field(wp_unslash($_POST['nonce'])); $post_id = intval($_POST['post_id']); $css_content = wp_unslash($_POST['css_content']); $css_type = isset($_POST['css_type']) ? sanitize_text_field(wp_unslash($_POST['css_type'])) : 'page'; $replace = isset($_POST['replace']) ? filter_var(wp_unslash($_POST['replace']), FILTER_VALIDATE_BOOLEAN) : false; // Vérifier le nonce if (!wp_verify_nonce($nonce, 'aibui_nonce')) { wp_die('Security check failed'); } // Vérifier que l'utilisateur peut éditer ce post if (!current_user_can('edit_post', $post_id)) { wp_send_json_error('Insufficient permissions'); } if ($css_type === 'page') { // Pour les pages, remplacer complètement le CSS de page update_post_meta($post_id, 'ai_builder_page_css_content', $css_content); // Récupérer le CSS de blocs existant $block_css = get_post_meta($post_id, 'ai_builder_block_css_content', true); // Combiner page CSS + block CSS pour le CSS final $final_css = $css_content; if (!empty($block_css)) { $final_css .= "\n" . $block_css; } update_post_meta($post_id, 'ai_builder_css_content', $final_css); } else if ($css_type === 'block') { $page_css = get_post_meta($post_id, 'ai_builder_page_css_content', true); $block_css = get_post_meta($post_id, 'ai_builder_block_css_content', true); if (empty($page_css)) { $page_css = ''; } if (empty($block_css)) { $block_css = ''; } if ($replace) { // Si c'est une édition manuelle, remplacer complètement le CSS de blocs $block_css = $css_content; } else { // Si c'est une génération IA, ajouter au CSS existant $block_css .= "\n/* Block CSS - " . date('Y-m-d H:i:s') . " */\n" . $css_content . "\n"; } // Sauvegarder le CSS de bloc update_post_meta($post_id, 'ai_builder_block_css_content', $block_css); // Combiner page CSS + block CSS pour le CSS final $final_css = $page_css; if (!empty($block_css)) { $final_css .= "\n" . $block_css; } update_post_meta($post_id, 'ai_builder_css_content', $final_css); } wp_send_json_success('CSS saved successfully'); } public function get_post_css() { // Vérifier que les données POST existent if (!isset($_POST['nonce']) || !isset($_POST['post_id'])) { wp_send_json_error('Missing required data'); } // Déséchapper et assainir les données $nonce = sanitize_text_field(wp_unslash($_POST['nonce'])); $post_id = intval($_POST['post_id']); // Vérifier le nonce if (!wp_verify_nonce($nonce, 'aibui_nonce')) { wp_die('Security check failed'); } // Vérifier que l'utilisateur peut lire ce post if (!current_user_can('read_post', $post_id)) { wp_send_json_error('Insufficient permissions'); } // Récupérer les CSS depuis les meta du post $page_css = get_post_meta($post_id, 'ai_builder_page_css_content', true); $block_css = get_post_meta($post_id, 'ai_builder_block_css_content', true); $combined_css = get_post_meta($post_id, 'ai_builder_css_content', true); wp_send_json_success(array( 'pageCss' => $page_css, 'blockCss' => $block_css, 'combinedCss' => $combined_css )); } public function save_post_js() { // Vérifier que les données POST existent if (!isset($_POST['nonce']) || !isset($_POST['post_id']) || !isset($_POST['js_content'])) { wp_send_json_error('Missing required data'); } // Déséchapper et assainir les données $nonce = sanitize_text_field(wp_unslash($_POST['nonce'])); $post_id = intval($_POST['post_id']); $js_content = wp_unslash($_POST['js_content']); $js_type = isset($_POST['js_type']) ? sanitize_text_field(wp_unslash($_POST['js_type'])) : 'page'; $replace = isset($_POST['replace']) ? filter_var(wp_unslash($_POST['replace']), FILTER_VALIDATE_BOOLEAN) : false; // Vérifier le nonce if (!wp_verify_nonce($nonce, 'aibui_nonce')) { wp_die('Security check failed'); } // Vérifier que l'utilisateur peut éditer ce post if (!current_user_can('edit_post', $post_id)) { wp_send_json_error('Insufficient permissions'); } if ($js_type === 'page') { // Pour les pages, remplacer complètement le JS de page update_post_meta($post_id, 'ai_builder_page_js_content', $js_content); // Récupérer le JS de blocs existant $block_js = get_post_meta($post_id, 'ai_builder_block_js_content', true); // Combiner page JS + block JS pour le JS final $final_js = $js_content; if (!empty($block_js)) { $final_js .= "\n" . $block_js; } update_post_meta($post_id, 'ai_builder_js_content', $final_js); } else if ($js_type === 'block') { $page_js = get_post_meta($post_id, 'ai_builder_page_js_content', true); $block_js = get_post_meta($post_id, 'ai_builder_block_js_content', true); if (empty($page_js)) { $page_js = ''; } if (empty($block_js)) { $block_js = ''; } if ($replace) { // Si c'est une édition manuelle, remplacer complètement le JS de blocs $block_js = $js_content; } else { // Si c'est une génération IA, ajouter au JS existant $block_js .= "\n/* Block JS - " . date('Y-m-d H:i:s') . " */\n" . $js_content . "\n"; } // Sauvegarder le JS de bloc update_post_meta($post_id, 'ai_builder_block_js_content', $block_js); // Combiner page JS + block JS pour le JS final $final_js = $page_js; if (!empty($block_js)) { $final_js .= "\n" . $block_js; } update_post_meta($post_id, 'ai_builder_js_content', $final_js); } wp_send_json_success('JS saved successfully'); } public function get_post_js() { // Vérifier que les données POST existent if (!isset($_POST['nonce']) || !isset($_POST['post_id'])) { wp_send_json_error('Missing required data'); } // Déséchapper et assainir les données $nonce = sanitize_text_field(wp_unslash($_POST['nonce'])); $post_id = intval($_POST['post_id']); // Vérifier le nonce if (!wp_verify_nonce($nonce, 'aibui_nonce')) { wp_die('Security check failed'); } // Vérifier que l'utilisateur peut lire ce post if (!current_user_can('read_post', $post_id)) { wp_send_json_error('Insufficient permissions'); } // Récupérer les JS depuis les meta du post $page_js = get_post_meta($post_id, 'ai_builder_page_js_content', true); $block_js = get_post_meta($post_id, 'ai_builder_block_js_content', true); $combined_js = get_post_meta($post_id, 'ai_builder_js_content', true); wp_send_json_success(array( 'pageJS' => $page_js ?: '', 'blockJS' => $block_js ?: '', 'combinedJS' => $combined_js ?: '' )); } public function save_meta_description() { if (!isset($_POST['nonce']) || !isset($_POST['post_id'])) { wp_send_json_error('Missing required data'); } $nonce = sanitize_text_field(wp_unslash($_POST['nonce'])); if (!wp_verify_nonce($nonce, 'aibui_nonce')) { wp_die('Security check failed'); } $post_id = intval($_POST['post_id']); if (!current_user_can('edit_post', $post_id)) { wp_send_json_error('Insufficient permissions'); } $raw = isset($_POST['meta_desc']) ? wp_unslash($_POST['meta_desc']) : ''; $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); } wp_send_json_success('Meta description saved'); } // Capture wp_mail() errors and store briefly to surface via AJAX public function capture_mail_error($wp_error) { $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown'; $key = 'aibui_cf_mailerr_' . md5($ip); set_transient($key, $wp_error instanceof WP_Error ? $wp_error->get_error_message() : 'Unknown mail error', 120); } public function submit_contact_form() { if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'aibui_contact_form')) { wp_send_json_error('Invalid nonce'); } // Rate limiting per IP: 1 submission per 30 seconds $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown'; $key = 'aibui_cf_rl_' . md5($ip); $last = get_transient($key); if ($last) { wp_send_json_error('Too many requests. Please wait.'); } set_transient($key, time(), 30); $recipient = isset($_POST['recipient']) ? sanitize_email(wp_unslash($_POST['recipient'])) : ''; if (empty($recipient) || !is_email($recipient)) { $recipient = sanitize_email(get_option('admin_email')); } if (empty($recipient) || !is_email($recipient)) { wp_send_json_error('No valid recipient configured'); } $subject = sprintf('[%s] Nouveau message de contact', get_bloginfo('name')); $fields = []; $sender_email = ''; foreach ($_POST as $key => $value) { if (strpos($key, 'field_') === 0) { $label_key = 'label_' . $key; $type_key = 'type_' . $key; $req_key = 'required_' . $key; $label = isset($_POST[$label_key]) ? sanitize_text_field(wp_unslash($_POST[$label_key])) : 'Champ'; $type = isset($_POST[$type_key]) ? sanitize_text_field(wp_unslash($_POST[$type_key])) : 'text'; $is_required = isset($_POST[$req_key]) && wp_unslash($_POST[$req_key]) === '1'; $raw = wp_unslash($value); switch ($type) { case 'email': $san = sanitize_email($raw); if (!$sender_email && is_email($san)) { $sender_email = $san; } break; case 'number': $san = is_numeric($raw) ? $raw : ''; break; case 'date': $san = preg_match('/^\\d{4}-\\d{2}-\\d{2}$/', $raw) ? $raw : ''; break; case 'textarea': $san = sanitize_textarea_field($raw); break; default: $san = sanitize_text_field($raw); } if ($is_required && $san === '') { wp_send_json_error(sprintf('%s est requis', $label ? $label : 'Ce champ')); } $fields[] = ['label' => $label, 'type' => $type, 'value' => $san]; } } if (empty($fields)) { wp_send_json_error('No fields provided'); } // Build HTML email content $rows = ''; foreach ($fields as $f) { $val = $f['type'] === 'textarea' ? nl2br(esc_html($f['value'])) : esc_html($f['value']); $rows .= '