Newsletter */ if (!defined('ABSPATH')) { exit; } class Thalim_NL_Admin_Page { // ------------------------------------------------------------------------- // Main render // ------------------------------------------------------------------------- public function render() { if (!current_user_can('edit_others_posts')) { wp_die('Unauthorized'); } // Determine active month $year_month = sanitize_text_field($_GET['nl_month'] ?? ''); if (!preg_match('/^\d{4}-\d{2}$/', $year_month)) { $year_month = date('Y-m'); } // Handle synchronous save $save_message = null; if (isset($_POST['thalim_nl_save']) && wp_verify_nonce($_POST['_wpnonce'] ?? '', 'thalim_nl_save')) { $save_message = $this->handle_save_newsletter(); // Re-read month after save (may have been changed in form) $posted_month = sanitize_text_field($_POST['nl_month'] ?? ''); if (preg_match('/^\d{4}-\d{2}$/', $posted_month)) { $year_month = $posted_month; } } // Load existing newsletter for this month (if any) $existing = $this->get_newsletter_post_for_month($year_month); $existing_sections = []; $intro_content = ''; $conclusion_content = ''; $subscribe_url = ''; $unsubscribe_url = ''; if ($existing) { $existing_sections = json_decode(get_post_meta($existing->ID, '_newsletter_sections', true), true) ?: []; $intro_content = get_post_meta($existing->ID, '_newsletter_intro', true) ?: ''; $conclusion_content = get_post_meta($existing->ID, '_newsletter_conclusion', true) ?: ''; $subscribe_url = get_post_meta($existing->ID, '_newsletter_subscribe_url', true) ?: ''; $unsubscribe_url = get_post_meta($existing->ID, '_newsletter_unsubscribe_url', true) ?: ''; } // Query posts for current month $query = new Thalim_NL_Post_Query(); $month_data = $query->get_posts_for_month($year_month); // Past newsletters $past_newsletters = get_posts([ 'post_type' => 'post', 'post_status' => ['draft', 'publish', 'pending'], 'posts_per_page' => -1, 'meta_key' => '_newsletter_month', 'orderby' => 'meta_value', 'order' => 'DESC', 'lang' => '', ]); $past_newsletters = array_filter($past_newsletters, function ($p) { return !empty(get_post_meta($p->ID, '_newsletter_month', true)); }); ?>

Newsletter THALIM

Composer

'nl_intro', 'media_buttons' => false, 'tinymce' => [ 'toolbar1' => 'bold,italic,bullist,numlist,blockquote,link,unlink', 'toolbar2' => '', ], 'quicktags' => ['buttons' => 'strong,em,ul,ol,li,link,close'], 'editor_height' => 200, ]); ?>
render_sections_html($month_data, $existing_sections); ?>
'nl_conclusion', 'media_buttons' => false, 'tinymce' => [ 'toolbar1' => 'bold,italic,bullist,numlist,blockquote,link,unlink', 'toolbar2' => '', ], 'quicktags' => ['buttons' => 'strong,em,ul,ol,li,link,close'], 'editor_height' => 200, ]); ?>

Newsletters enregistrées

Aucune newsletter enregistrée.

ID, '_newsletter_month', true); $label = $this->format_month_label($nl_month); $edit_url = get_edit_post_link($nl->ID); ?>
Mois Actions
Modifier
$group) { // Collect all cat IDs in this group: parent + children $cats_in_group = [$parent_id => $group['name']]; foreach ($group['children'] as $cid => $cname) { $cats_in_group[$cid] = $cname; } // Check if any cat in this group has posts $group_has_posts = false; foreach ($cats_in_group as $cid => $cname) { if (!empty($month_data[$cid])) { $group_has_posts = true; break; } } if (!$group_has_posts) { continue; } $has_content = true; ?>

$label): $posts = $month_data[$cat_id] ?? []; if (empty($posts)) { continue; } $count = count($posts); $checked_in_section = (array) ($checked_ids[$cat_id] ?? $checked_ids[(string) $cat_id] ?? []); $has_checked = !empty($checked_in_section); ?>
> ()
Aucun contenu trouvé pour ce mois.

'; } return $html; } /** * Small date hint shown next to each post title in the checklist. */ private function format_post_date_hint(array $post): string { $candidates = [$post['date_debut'], $post['datetime'], $post['post_date']]; foreach ($candidates as $raw) { if ($raw && !str_starts_with($raw, '0000-00-00')) { $ts = strtotime($raw); if ($ts) { return date_i18n('j M Y', $ts); } } } return ''; } // ------------------------------------------------------------------------- // Save // ------------------------------------------------------------------------- private function handle_save_newsletter(): array { $year_month = sanitize_text_field($_POST['nl_month'] ?? ''); if (!preg_match('/^\d{4}-\d{2}$/', $year_month)) { return ['error', 'Mois invalide.']; } $intro = wp_kses_post(wp_unslash($_POST['nl_intro'] ?? '')); $conclusion = wp_kses_post(wp_unslash($_POST['nl_conclusion'] ?? '')); $subscribe_url = esc_url_raw(wp_unslash($_POST['nl_subscribe_url'] ?? '')); $unsubscribe_url = esc_url_raw(wp_unslash($_POST['nl_unsubscribe_url'] ?? '')); // Build sections: cat_id => [post_id, ...] $raw_sections = $_POST['nl_sections'] ?? []; $sections = []; foreach ($raw_sections as $cat_id => $post_ids) { $cat_id = (int) $cat_id; $clean_ids = array_map('intval', (array) $post_ids); $clean_ids = array_filter($clean_ids); if (!empty($clean_ids)) { $sections[$cat_id] = array_values($clean_ids); } } $post_id = $this->save_newsletter_post($year_month, $intro, $conclusion, $sections, $subscribe_url, $unsubscribe_url); if (is_wp_error($post_id)) { return ['error', $post_id->get_error_message()]; } $label = $this->format_month_label($year_month); return ['success', "Newsletter «\u{00A0}{$label}\u{00A0}» enregistrée et publiée (ID\u{00A0}: {$post_id})."]; } private function save_newsletter_post(string $year_month, string $intro, string $conclusion, array $sections, string $subscribe_url = '', string $unsubscribe_url = ''): int|WP_Error { global $wpdb; $label = 'Newsletter — ' . $this->format_month_label($year_month); $existing = $this->get_newsletter_post_for_month($year_month); // First pass: insert/update with placeholder content (meta must exist before exporter runs) $post_args = [ 'post_title' => $label, 'post_content' => '', 'post_status' => 'publish', 'post_type' => 'post', ]; if ($existing) { $post_args['ID'] = $existing->ID; $post_id = wp_update_post($post_args, true); } else { $post_id = wp_insert_post($post_args, true); } if (is_wp_error($post_id)) { return $post_id; } // Save all meta so the exporter can read them update_post_meta($post_id, '_newsletter_month', $year_month); update_post_meta($post_id, '_newsletter_intro', $intro); update_post_meta($post_id, '_newsletter_conclusion', $conclusion); update_post_meta($post_id, '_newsletter_sections', wp_json_encode($sections)); update_post_meta($post_id, '_newsletter_subscribe_url', $subscribe_url); update_post_meta($post_id, '_newsletter_unsubscribe_url', $unsubscribe_url); // Generate full rendered HTML and store as post_content $exporter = new Thalim_NL_HTML_Exporter(); $full_html = $exporter->generate(get_post($post_id)); wp_update_post(['ID' => $post_id, 'post_content' => $full_html]); $this->do_triple_storage_category($post_id, THALIM_NL_CAT_NEWSLETTER); if (function_exists('pll_set_post_language')) { pll_set_post_language($post_id, 'fr'); } return $post_id; } /** * Assign a category using the Pods triple-storage pattern (same as HAL importer). */ private function do_triple_storage_category(int $post_id, int $cat_id): void { global $wpdb; // 1. Native WP category assignment wp_set_post_categories($post_id, [$cat_id]); // 2. Pods postmeta: single integer update_post_meta($post_id, 'categorie', $cat_id); // 3. Pods _pods_ meta: serialized array update_post_meta($post_id, '_pods_categorie', [$cat_id]); // 4. wp_podsrel row $wpdb->delete( $wpdb->prefix . 'podsrel', [ 'pod_id' => THALIM_NL_POD_ID_POST, 'field_id' => THALIM_NL_FIELD_ID_CAT, 'item_id' => $post_id, ], ['%d', '%d', '%d'] ); $wpdb->insert( $wpdb->prefix . 'podsrel', [ 'pod_id' => THALIM_NL_POD_ID_POST, 'field_id' => THALIM_NL_FIELD_ID_CAT, 'item_id' => $post_id, 'related_pod_id' => 0, 'related_field_id' => 0, 'related_item_id' => $cat_id, 'weight' => 0, ], ['%d', '%d', '%d', '%d', '%d', '%d', '%d'] ); } // ------------------------------------------------------------------------- // AJAX handlers // ------------------------------------------------------------------------- public function handle_ajax_load_month(): void { check_ajax_referer('thalim_newsletter_ajax', '_wpnonce'); if (!current_user_can('edit_others_posts')) { wp_send_json_error('Unauthorized', 403); } $year_month = sanitize_text_field($_POST['month'] ?? ''); if (!preg_match('/^\d{4}-\d{2}$/', $year_month)) { wp_send_json_error('Invalid month format'); } $query = new Thalim_NL_Post_Query(); $month_data = $query->get_posts_for_month($year_month); $existing = $this->get_newsletter_post_for_month($year_month); $existing_sections = []; $intro_content = ''; $conclusion_content = ''; $subscribe_url = ''; $unsubscribe_url = ''; $has_existing = false; if ($existing) { $has_existing = true; $existing_sections = json_decode(get_post_meta($existing->ID, '_newsletter_sections', true), true) ?: []; $intro_content = get_post_meta($existing->ID, '_newsletter_intro', true) ?: ''; $conclusion_content = get_post_meta($existing->ID, '_newsletter_conclusion', true) ?: ''; $subscribe_url = get_post_meta($existing->ID, '_newsletter_subscribe_url', true) ?: ''; $unsubscribe_url = get_post_meta($existing->ID, '_newsletter_unsubscribe_url', true) ?: ''; } $html = $this->render_sections_html($month_data, $existing_sections); wp_send_json_success([ 'html' => $html, 'intro' => $intro_content, 'conclusion' => $conclusion_content, 'subscribe_url' => $subscribe_url, 'unsubscribe_url' => $unsubscribe_url, 'has_existing' => $has_existing, ]); } public function handle_ajax_export_html(): void { check_ajax_referer('thalim_newsletter_ajax', '_wpnonce'); if (!current_user_can('edit_others_posts')) { wp_send_json_error('Unauthorized', 403); } $post_id = (int) ($_POST['post_id'] ?? 0); if (!$post_id) { wp_send_json_error('Missing post_id'); } $post = get_post($post_id); if (!$post) { wp_send_json_error('Post not found'); } // post_content already holds the full rendered HTML (set on save) wp_send_json_success(['html' => $post->post_content]); } // ------------------------------------------------------------------------- // Helpers // ------------------------------------------------------------------------- public function get_newsletter_post_for_month(string $year_month): ?WP_Post { $posts = get_posts([ 'post_type' => 'post', 'post_status' => ['draft', 'publish', 'pending'], 'posts_per_page' => 1, 'meta_key' => '_newsletter_month', 'meta_value' => $year_month, 'lang' => '', // Polylang: all languages ]); return $posts[0] ?? null; } private function format_month_label(string $year_month): string { $ts = strtotime($year_month . '-01'); if (!$ts) { return $year_month; } // e.g. "Mars 2026" return ucfirst(date_i18n('F Y', $ts)); } }