PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_TIMEOUT => 5, ] ); } catch (PDOException $e) { error_log('NewsletterWp: connessione fallita: ' . $e->getMessage()); throw new RuntimeException('Collegamento al database di WordPress non riuscito: controlla WP_DB_* nel file .env.'); } } return self::$pdo; } private static function unserializeOptions(?string $raw): array { if ($raw === null || $raw === '') return []; $o = @unserialize($raw, ['allowed_classes' => false]); return is_array($o) ? $o : []; } /** Ultime newsletter del plugin (per l'import e per lo stato). */ public static function listEmails(int $limit = 30): array { $st = self::db()->prepare("SELECT id, subject, status, created, sent, total FROM " . self::table() . " WHERE type = 'message' ORDER BY id DESC LIMIT " . max(1, min(100, $limit))); $st->execute(); return $st->fetchAll(); } /** Stato di più newsletter in una sola query: [id => status]. */ public static function statuses(array $ids): array { $ids = array_values(array_unique(array_filter(array_map('intval', $ids)))); if (!$ids) return []; $ph = implode(',', array_fill(0, count($ids), '?')); $st = self::db()->prepare("SELECT id, status FROM " . self::table() . " WHERE id IN ($ph)"); $st->execute($ids); $out = []; foreach ($st->fetchAll() as $r) $out[(int) $r['id']] = $r['status']; return $out; } /** Legge una newsletter del plugin e la converte in blocchi YogiBook. */ public static function import(int $id): array { $st = self::db()->prepare("SELECT id, subject, message, options, editor FROM " . self::table() . " WHERE id = ?"); $st->execute([$id]); $row = $st->fetch(); if (!$row) { throw new RuntimeException('Newsletter non trovata in WordPress.'); } $opts = self::unserializeOptions($row['options']); return [ 'subject' => (string) $row['subject'], 'preheader' => (string) ($opts['preheader'] ?? ''), 'blocks' => NewsletterRenderer::fromComposerHtml((string) $row['message']), 'settings' => NewsletterRenderer::settingsFromWpOptions($opts), ]; } /** * Crea o aggiorna la bozza in The Newsletter. * Aggiorna solo se è ancora "new" (mai partita). Restituisce [id, created(bool)]. */ public static function push(?int $wpId, string $subject, string $preheader, string $html, string $text, array $settings): array { $db = self::db(); $composerOpts = NewsletterRenderer::wpComposerOptions($settings); if ($wpId) { $st = $db->prepare("SELECT status, options FROM " . self::table() . " WHERE id = ?"); $st->execute([$wpId]); $row = $st->fetch(); if ($row) { if ($row['status'] !== 'new') { throw new RuntimeException('In WordPress questa newsletter è già "' . $row['status'] . '": non la modifico. Duplica la bozza per crearne una nuova.'); } // Mantiene tutto quello scelto in WordPress (liste, mittente, utm...) $opts = array_merge(self::unserializeOptions($row['options']), $composerOpts, ['preheader' => $preheader]); unset($opts['error_message']); $up = $db->prepare("UPDATE " . self::table() . " SET subject = ?, message = ?, message_text = ?, options = ?, editor = 2, updated = ? WHERE id = ? AND status = 'new'"); $up->execute([$subject, $html, $text, serialize($opts), time(), $wpId]); return [$wpId, false]; } // Cancellata in WordPress: la ricreiamo } // Nuova: il pubblico parte uguale all'ultima newsletter (si controlla in WordPress) $base = []; $last = $db->query("SELECT options FROM " . self::table() . " WHERE type = 'message' ORDER BY id DESC LIMIT 1")->fetchColumn(); if ($last) { $prev = self::unserializeOptions($last); foreach (['status', 'wp_users', 'lists', 'lists_operator', 'lists_exclude', 'countries', 'regions', 'cities', 'sender_email', 'sender_name', 'text_message_mode', 'utm_source', 'utm_campaign', 'utm_medium', 'utm_term', 'utm_content'] as $k) { if (array_key_exists($k, $prev)) $base[$k] = $prev[$k]; } } $opts = array_merge(['status' => 'C', 'wp_users' => '0', 'lists' => [], 'lists_operator' => 'or', 'lists_exclude' => []], $base, $composerOpts, ['preheader' => $preheader]); $ins = $db->prepare("INSERT INTO " . self::table() . " (language, subject, message, subject2, message2, name2, status, total, last_id, sent, track, list, type, query, editor, sex, theme, message_text, preferences, send_on, token, options, private, version, updated) VALUES ('', ?, ?, '', '', '', 'new', 0, 0, 0, 1, 0, 'message', '', 2, '', '', ?, '', ?, '', ?, 0, '', ?)"); $ins->execute([$subject, $html, $text, time(), serialize($opts), time()]); return [(int) $db->lastInsertId(), true]; } }