self::COLOR_LABORATOIRE, 3 => self::COLOR_MANIFESTATIONS, 4 => self::COLOR_PUBLICATIONS, 5 => self::COLOR_MEDIATIONS, 6 => self::COLOR_RESSOURCES, ]; // ── Public entry point ──────────────────────────────────────────────────── /** * Generate a complete email-ready HTML document from a saved newsletter post. */ /** Month window timestamps — set by generate(), used by format_seminar_line() */ private int $month_start = 0; private int $month_end = 0; public function generate(WP_Post $post): string { $sections_json = get_post_meta($post->ID, '_newsletter_sections', true); $sections = json_decode($sections_json, true) ?: []; $intro = get_post_meta($post->ID, '_newsletter_intro', true) ?: ''; $conclusion = get_post_meta($post->ID, '_newsletter_conclusion', true) ?: ''; $subscribe_url = get_post_meta($post->ID, '_newsletter_subscribe_url', true) ?: ''; $unsubscribe_url = get_post_meta($post->ID, '_newsletter_unsubscribe_url', true) ?: ''; // Compute month window from stored newsletter month $year_month = get_post_meta($post->ID, '_newsletter_month', true) ?: ''; if ($year_month) { $this->month_start = strtotime($year_month . '-01 00:00:00') ?: 0; $this->month_end = strtotime('last day of ' . $year_month . ' 23:59:59') ?: 0; } // Build ordered section blocks following the category hierarchy $groups = Thalim_NL_Post_Query::get_eligible_categories(); $section_blocks = []; foreach ($groups as $parent_id => $group) { $color = self::PARENT_COLORS[$parent_id] ?? self::COLOR_DARK; // 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; } foreach ($cats_in_group as $cat_id => $label) { $post_ids = $sections[$cat_id] ?? $sections[(string) $cat_id] ?? []; if (empty($post_ids)) { continue; } $items = []; foreach ($post_ids as $pid) { $line = $this->format_post_line((int) $pid, $cat_id); if ($line) { $items[] = $line; } } if (!empty($items)) { $section_blocks[] = [ 'label' => $label, 'color' => $color, 'items' => $items, ]; } } } return $this->render_email_document($intro, $section_blocks, $conclusion, $subscribe_url, $unsubscribe_url); } // ── Email document builder ───────────────────────────────────────────────── private function render_email_document(string $intro, array $section_blocks, string $conclusion, string $subscribe_url = '', string $unsubscribe_url = ''): string { $logo_url = get_theme_file_uri('assets/images/thalim-logo.png'); $site_url = get_bloginfo('url'); $site_name = get_bloginfo('name'); // Font stacks (Gelasio via Google Fonts for clients that support it) $font_serif = "Gelasio, Georgia, 'Times New Roman', serif"; $font_sans = "Arial, Helvetica, sans-serif"; // Shared cell style $cell_padding = 'padding:32px 40px;'; $body_style = "font-family:{$font_sans};font-size:15px;line-height:1.6;color:" . self::COLOR_DARK . ";"; ob_start(); ?> <?php echo esc_html($site_name); ?> — Newsletter
— Newsletter  ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌
format_seminar_line($post_id); } $post = get_post($post_id); if (!$post) { return ''; } $font_serif = "Gelasio, Georgia, 'Times New Roman', serif"; $font_sans = "Arial, Helvetica, sans-serif"; $url = get_permalink($post_id); $title = get_the_title($post_id); // Date $date_str = $this->format_date_for_category($post_id, $cat_id); // Authors $author_parts = []; foreach (get_post_meta($post_id, 'membres', false) as $uid) { $user = get_userdata((int) $uid); if ($user) { $author_parts[] = $user->display_name; } } $autrepersonnes = get_post_meta($post_id, 'autrepersonnes', true) ?: ''; if ($autrepersonnes) { $author_parts[] = $autrepersonnes; } $authors_str = implode(', ', $author_parts); // Image (first image from documents_joints) $image_url = ''; $doc_ids = get_post_meta($post_id, 'documents_joints', false); foreach ($doc_ids as $doc_id) { $mime = get_post_mime_type($doc_id); if ($mime && str_starts_with($mime, 'image/')) { $src_data = wp_get_attachment_image_src($doc_id, 'thumbnail'); if ($src_data) { $image_url = $src_data[0]; break; } } } // Meta line: date — authors $meta_parts = []; if ($date_str) { $meta_parts[] = esc_html($date_str); } if ($authors_str) { $meta_parts[] = esc_html($authors_str); } $meta_html = implode(' — ', $meta_parts); // Build the post block as a table row ob_start(); ?>
post_status !== 'publish') continue; $raw_debut = get_post_meta($sid, 'date_de_debut', true) ?: ''; $ts = $raw_debut ? strtotime($raw_debut) : false; // Filter: only séances within the month window if ($this->month_start && $this->month_end) { if (!$ts || $ts < $this->month_start || $ts > $this->month_end) { continue; } } $seances[] = [ 'id' => $sid, 'title' => get_the_title($sid), 'date_debut' => $raw_debut, 'date_fin' => get_post_meta($sid, 'date_de_fin', true) ?: '', 'heure_de_debut' => substr(get_post_meta($sid, 'heure_de_debut', true) ?: '', 0, 5), 'heure_de_fin' => substr(get_post_meta($sid, 'heure_de_fin', true) ?: '', 0, 5), 'lieu' => get_post_meta($sid, 'lieu', true) ?: '', ]; } usort($seances, fn($a, $b) => strcmp($a['date_debut'], $b['date_debut'])); ob_start(); ?>

format_raw_date($raw_debut); $fin_str = $this->format_raw_date($raw_fin); if ($debut_str && $fin_str && $debut_str !== $fin_str) { return $debut_str . '–' . $fin_str; } return $debut_str ?: $fin_str; } $raw_dt = get_post_meta($post_id, 'datetime', true) ?: ''; if ($raw_dt && !str_starts_with($raw_dt, '0000-00-00')) { return $this->format_raw_date($raw_dt); } $post = get_post($post_id); return $post ? $this->format_raw_date($post->post_date) : ''; } private function format_raw_date(string $raw): string { if (!$raw || str_starts_with($raw, '0000-00-00')) { return ''; } $ts = strtotime($raw); return $ts ? date_i18n('j F Y', $ts) : ''; } // ── Rich-text processor (intro / conclusion) ────────────────────────────── /** * Convert stored WYSIWYG content to email-safe inline-styled HTML. * Applies wpautop then inlines font/colour styles on common tags. */ private function process_rich_text(string $content): string { $font_serif = "Gelasio, Georgia, 'Times New Roman', serif"; $font_sans = "Arial, Helvetica, sans-serif"; $color_dark = self::COLOR_DARK; $color_mid = self::COLOR_MID; $color_rule = self::COLOR_RULE; $html = wpautop($content); // Style

$html = preg_replace( '/])/', '

$html = preg_replace( '/])/', ' $html = preg_replace( '/])/', '