165 lines
7.1 KiB
PHP
165 lines
7.1 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Collegamento al database di WordPress per The Newsletter.
|
|
*
|
|
* Usa un utente MySQL dedicato che può leggere/scrivere SOLO la tabella delle newsletter.
|
|
* Variabili nel .env di YogiBook:
|
|
* WP_DB_HOST, WP_DB_NAME, WP_DB_USER, WP_DB_PASSWORD, WP_DB_PREFIX (default wp_),
|
|
* WP_ADMIN_URL (default https://yogasoul.it/wp-admin/)
|
|
*/
|
|
class NewsletterWp
|
|
{
|
|
private static ?PDO $pdo = null;
|
|
|
|
public static function isConfigured(): bool
|
|
{
|
|
return !empty($_ENV['WP_DB_NAME']) && !empty($_ENV['WP_DB_USER']);
|
|
}
|
|
|
|
public static function adminUrl(): string
|
|
{
|
|
return rtrim($_ENV['WP_ADMIN_URL'] ?? 'https://yogasoul.it/wp-admin/', '/') . '/admin.php?page=newsletter_emails_index';
|
|
}
|
|
|
|
private static function table(): string
|
|
{
|
|
$prefix = preg_replace('/[^a-zA-Z0-9_]/', '', $_ENV['WP_DB_PREFIX'] ?? 'wp_');
|
|
return '`' . $prefix . 'newsletter_emails`';
|
|
}
|
|
|
|
private static function db(): PDO
|
|
{
|
|
if (!self::isConfigured()) {
|
|
throw new RuntimeException('Collegamento a WordPress non configurato (manca WP_DB_* nel file .env).');
|
|
}
|
|
if (self::$pdo === null) {
|
|
$host = $_ENV['WP_DB_HOST'] ?? 'localhost';
|
|
$port = '3306';
|
|
if (strpos($host, ':') !== false) {
|
|
[$host, $port] = explode(':', $host, 2);
|
|
}
|
|
try {
|
|
self::$pdo = new PDO(
|
|
"mysql:host={$host};port={$port};dbname={$_ENV['WP_DB_NAME']};charset=utf8mb4",
|
|
$_ENV['WP_DB_USER'],
|
|
$_ENV['WP_DB_PASSWORD'] ?? '',
|
|
[
|
|
PDO::ATTR_ERRMODE => 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];
|
|
}
|
|
}
|