runServiceFactory = $runServiceFactory; $this->mailshotServiceFactory = $mailshotServiceFactory; $this->wp = $wp; } public function register(): void { $this->wp->addAction('admin_menu', [$this, 'registerMenu']); $this->wp->addAction('admin_post_feca_mailshots_run_api', [$this, 'handleApi']); $this->wp->addAction('admin_post_feca_mailshots_run_execute_ui', [$this, 'handleRunUi']); $this->wp->addAction('admin_post_feca_mailshots_retry_failed_ui', [$this, 'handleRetryFailedUi']); $this->wp->addAction('admin_post_feca_mailshots_retry_recipient_ui', [$this, 'handleRetryRecipientUi']); } public function registerMenu(): void { $this->wp->addSubmenuPage('feca-mailshot', 'Run Mailshot', 'Run Mailshot', self::CAPABILITY, 'feca-mailshots-run', [$this, 'render']); } public function render(): void { if (!$this->wp->currentUserCan(self::CAPABILITY)) { echo 'Permission denied'; return; } $mailshots = $this->mailshotService()->list(); $selectedMailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0'); if ($selectedMailshotId <= 0 && $mailshots !== []) { $selectedMailshotId = (int) ($mailshots[0]['id'] ?? 0); } $result = $this->result(); $lastRunRows = $selectedMailshotId > 0 ? $this->mailshotService()->lastRun($selectedMailshotId) : []; $action = htmlspecialchars($this->wp->adminUrl('admin-post.php')); echo '

Run Mailshot

'; echo '

Execute full sends and retry failures from the current mailshot last-run rows.

'; if ($result !== null) { $ok = !empty($result['ok']); $bg = $ok ? '#f1f8e9' : '#ffebee'; $border = $ok ? '#8bc34a' : '#ef9a9a'; echo '
'; echo '' . ($ok ? 'Run action completed.' : 'Run action failed.') . ''; if ($ok) { echo '

attempted=' . (int) ($result['attempted'] ?? 0) . ', sent=' . (int) ($result['sent'] ?? 0) . ', failed=' . (int) ($result['failed'] ?? 0) . ', warnings=' . (int) ($result['warnings'] ?? 0) . ', skipped=' . (int) ($result['skipped'] ?? 0) . '

'; } if (!empty($result['errors']) && is_array($result['errors'])) { echo '

' . htmlspecialchars(implode('; ', $result['errors'])) . '

'; } echo '
Show technical details
' . htmlspecialchars(json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) . '
'; echo '
'; } echo '
'; echo '

1. Select Mailshot

'; echo '
'; echo ''; echo ' '; echo '
'; echo '
'; echo '
'; echo '

2. Run Actions

'; echo ''; echo ' '; echo ''; echo '
'; echo '
'; echo '

3. Last Run Rows

'; if ($lastRunRows === []) { echo '

No rows in mailshot_last_run for this mailshot.

'; } else { echo ''; foreach ($lastRunRows as $row) { $recipientKey = (string) ($row['recipient_key'] ?? ''); $status = (string) ($row['status'] ?? ''); $msg = (string) (($row['error_message'] ?? '') ?: ($row['warning_message'] ?? '')); echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; } echo '
Recipient KeyEmailStatusAttemptsError/WarningRetry
' . htmlspecialchars($recipientKey) . '' . htmlspecialchars((string) ($row['recipient_email_last'] ?? '')) . '' . htmlspecialchars($status) . '' . (int) ($row['attempt_count'] ?? 0) . '' . htmlspecialchars($msg) . ''; if ($status === 'failed') { echo '
'; echo ''; echo ''; echo ''; echo ''; echo '
'; } echo '
'; } echo '
'; echo '
'; } public function handleApi(): void { if (!$this->wp->currentUserCan(self::CAPABILITY)) { $this->wp->sendJson(['ok' => false, 'error' => 'Permission denied'], 403); return; } $op = (string) ($this->wp->requestParam('op', '') ?? ''); $service = $this->runService(); try { if ($op === 'run_mailshot') { $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0'); $this->wp->sendJson($service->runMailshot($mailshotId)); return; } if ($op === 'retry_failed') { $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0'); $this->wp->sendJson($service->retryFailed($mailshotId)); return; } if ($op === 'retry_recipient') { $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0'); $recipientKey = (string) ($this->wp->requestParam('recipient_key', '') ?? ''); $this->wp->sendJson($service->retryRecipient($mailshotId, $recipientKey)); return; } $this->wp->sendJson(['ok' => false, 'error' => 'Unknown op'], 400); } catch (\Throwable $e) { $this->wp->sendJson(['ok' => false, 'error' => $e->getMessage()], 500); } } public function handleRunUi(): void { if (!$this->wp->currentUserCan(self::CAPABILITY)) { $this->wp->sendJson(['ok' => false, 'error' => 'Permission denied'], 403); return; } $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0'); $result = $this->runService()->runMailshot($mailshotId); $this->wp->updateOption(self::RESULT_OPTION_KEY, $result); $this->redirect($mailshotId); } public function handleRetryFailedUi(): void { if (!$this->wp->currentUserCan(self::CAPABILITY)) { $this->wp->sendJson(['ok' => false, 'error' => 'Permission denied'], 403); return; } $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0'); $result = $this->runService()->retryFailed($mailshotId); $this->wp->updateOption(self::RESULT_OPTION_KEY, $result); $this->redirect($mailshotId); } public function handleRetryRecipientUi(): void { if (!$this->wp->currentUserCan(self::CAPABILITY)) { $this->wp->sendJson(['ok' => false, 'error' => 'Permission denied'], 403); return; } $mailshotId = (int) ($this->wp->requestParam('mailshot_id', '0') ?? '0'); $recipientKey = (string) ($this->wp->requestParam('recipient_key', '') ?? ''); $result = $this->runService()->retryRecipient($mailshotId, $recipientKey); $this->wp->updateOption(self::RESULT_OPTION_KEY, $result); $this->redirect($mailshotId); } private function redirect(int $mailshotId): void { $url = $this->wp->adminUrl('admin.php?page=feca-mailshots-run&mailshot_id=' . $mailshotId); if (!headers_sent()) { header('Location: ' . $url, true, 302); exit; } } /** @return array|null */ private function result(): ?array { $raw = $this->wp->getOption(self::RESULT_OPTION_KEY, null); return is_array($raw) ? $raw : null; } private function runService(): MailshotRunService { return ($this->runServiceFactory)(); } private function mailshotService(): MailshotService { return ($this->mailshotServiceFactory)(); } }