Construct a DSL sentence from sources and constraints.
';
if (is_array($result) && isset($result['rows']) && is_array($result['rows'])) {
$rows = $result['rows'];
- echo '
';
- echo '
Preview (first ' . count($rows) . ' rows)
';
+ echo '
';
+ echo '
Preview (first ' . count($rows) . ' rows)
';
if ($rows === []) {
echo '
No rows returned.
';
} else {
@@ -253,6 +251,7 @@ final class DataSourcesAdminPage
}
echo '
Existing Data Sources
';
+ echo '
';
echo '';
echo '
';
@@ -139,54 +141,12 @@ final class DownloadPdfAdminPage
$format = 'merged';
}
- $this->downloadDebugLog('handleDownloadUi.start', [
- 'mailshot_id' => $mailshotId,
- 'format' => $format,
- 'memory_usage' => memory_get_usage(true),
- 'memory_peak' => memory_get_peak_usage(true),
- ]);
$this->maybeRaiseMemoryLimit($this->resolveDownloadMemoryLimitTarget());
- register_shutdown_function(function () use ($mailshotId, $format): void {
- $err = error_get_last();
- if (!is_array($err)) {
- return;
- }
- $type = (int) ($err['type'] ?? 0);
- $fatalTypes = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR];
- if (!in_array($type, $fatalTypes, true)) {
- return;
- }
- $this->downloadDebugLog('handleDownloadUi.shutdown_fatal', [
- 'mailshot_id' => $mailshotId,
- 'format' => $format,
- 'error_type' => $type,
- 'error_message' => (string) ($err['message'] ?? ''),
- 'error_file' => (string) ($err['file'] ?? ''),
- 'error_line' => (int) ($err['line'] ?? 0),
- 'memory_usage' => memory_get_usage(true),
- 'memory_peak' => memory_get_peak_usage(true),
- ]);
- });
-
if ($format === 'zip') {
try {
- $this->downloadDebugLog('handleDownloadUi.zip.before_generate', ['mailshot_id' => $mailshotId]);
$result = $this->runService()->generatePdfZipToTemp($mailshotId);
- $this->downloadDebugLog('handleDownloadUi.zip.after_generate', [
- 'mailshot_id' => $mailshotId,
- 'ok' => !empty($result['ok']),
- 'generated_count' => (int) ($result['generated_count'] ?? 0),
- 'recipient_count' => (int) ($result['recipient_count'] ?? 0),
- 'zip_path' => (string) ($result['zip_path'] ?? ''),
- 'memory_usage' => memory_get_usage(true),
- 'memory_peak' => memory_get_peak_usage(true),
- ]);
} catch (\Throwable $e) {
- $this->downloadDebugLog('handleDownloadUi.zip.exception', [
- 'mailshot_id' => $mailshotId,
- 'error' => $e->getMessage(),
- ]);
$this->wp->updateOption(self::RESULT_OPTION_KEY, ['ok' => false, 'errors' => ['ZIP generation failed: ' . $e->getMessage()]]);
$this->redirectTo($this->wp->adminUrl('admin.php?page=' . self::PAGE_SLUG . '&mailshot_id=' . $mailshotId));
return;
@@ -205,14 +165,9 @@ final class DownloadPdfAdminPage
}
try {
- $this->downloadDebugLog('handleDownloadUi.zip.before_send', ['mailshot_id' => $mailshotId, 'zip_path' => $zipPath]);
$this->sendFileDownload('mailshot_' . $mailshotId . '_pdfs.zip', 'application/zip', $zipPath);
} catch (\Throwable $e) {
@unlink($zipPath);
- $this->downloadDebugLog('handleDownloadUi.zip.send_exception', [
- 'mailshot_id' => $mailshotId,
- 'error' => $e->getMessage(),
- ]);
$this->wp->updateOption(self::RESULT_OPTION_KEY, ['ok' => false, 'errors' => ['ZIP download failed: ' . $e->getMessage()]]);
$this->redirectTo($this->wp->adminUrl('admin.php?page=' . self::PAGE_SLUG . '&mailshot_id=' . $mailshotId));
}
@@ -220,21 +175,8 @@ final class DownloadPdfAdminPage
}
try {
- $this->downloadDebugLog('handleDownloadUi.merged.before_generate', ['mailshot_id' => $mailshotId]);
$result = $this->runService()->generatePdfBatch($mailshotId, true, false);
- $this->downloadDebugLog('handleDownloadUi.merged.after_generate', [
- 'mailshot_id' => $mailshotId,
- 'ok' => !empty($result['ok']),
- 'generated_count' => (int) ($result['generated_count'] ?? 0),
- 'recipient_count' => (int) ($result['recipient_count'] ?? 0),
- 'memory_usage' => memory_get_usage(true),
- 'memory_peak' => memory_get_peak_usage(true),
- ]);
} catch (\Throwable $e) {
- $this->downloadDebugLog('handleDownloadUi.merged.exception', [
- 'mailshot_id' => $mailshotId,
- 'error' => $e->getMessage(),
- ]);
$this->wp->updateOption(self::RESULT_OPTION_KEY, ['ok' => false, 'errors' => ['Merged PDF generation failed: ' . $e->getMessage()]]);
$this->redirectTo($this->wp->adminUrl('admin.php?page=' . self::PAGE_SLUG . '&mailshot_id=' . $mailshotId));
return;
@@ -252,13 +194,8 @@ final class DownloadPdfAdminPage
return;
}
try {
- $this->downloadDebugLog('handleDownloadUi.merged.before_send', ['mailshot_id' => $mailshotId, 'bytes_len' => strlen($bytes)]);
$this->sendBinaryDownload('mailshot_' . $mailshotId . '_merged.pdf', 'application/pdf', $bytes);
} catch (\Throwable $e) {
- $this->downloadDebugLog('handleDownloadUi.merged.send_exception', [
- 'mailshot_id' => $mailshotId,
- 'error' => $e->getMessage(),
- ]);
$this->wp->updateOption(self::RESULT_OPTION_KEY, ['ok' => false, 'errors' => ['Merged PDF download failed: ' . $e->getMessage()]]);
$this->redirectTo($this->wp->adminUrl('admin.php?page=' . self::PAGE_SLUG . '&mailshot_id=' . $mailshotId));
return;
@@ -320,33 +257,6 @@ final class DownloadPdfAdminPage
return ($this->mailshotServiceFactory)();
}
- /** @param array
$context */
- private function downloadDebugLog(string $event, array $context = []): void
- {
- $line = '[feca-mailshots/download-pdf][' . gmdate('Y-m-d H:i:s') . ' UTC] ' . $event;
- if ($context !== []) {
- $json = json_encode($context);
- if (is_string($json) && $json !== '') {
- $line .= ' ' . $json;
- }
- }
-
- error_log($line);
-
- if (!defined('ABSPATH')) {
- return;
- }
-
- $path = ABSPATH . 'wp-content/uploads/feca_mailshots_download_debug.log';
- $dir = dirname($path);
- if (!is_dir($dir)) {
- @mkdir($dir, 0755, true);
- }
- if (is_dir($dir) && is_writable($dir)) {
- @error_log($line . PHP_EOL, 3, $path);
- }
- }
-
private function maybeRaiseMemoryLimit(string $target): void
{
if (!function_exists('ini_get') || !function_exists('ini_set')) {
@@ -367,11 +277,9 @@ final class DownloadPdfAdminPage
$old = $current;
@ini_set('memory_limit', $target);
$new = (string) ini_get('memory_limit');
- $this->downloadDebugLog('handleDownloadUi.memory_limit_adjust', [
- 'old' => $old,
- 'new' => $new,
- 'target' => $target,
- ]);
+ if ($new === $old) {
+ return;
+ }
}
private function resolveDownloadMemoryLimitTarget(): string
diff --git a/feca_mailshots_plugin/src/Admin/MailshotTestAdminPage.php b/feca_mailshots_plugin/src/Admin/MailshotTestAdminPage.php
index 04b0afa..188af8e 100644
--- a/feca_mailshots_plugin/src/Admin/MailshotTestAdminPage.php
+++ b/feca_mailshots_plugin/src/Admin/MailshotTestAdminPage.php
@@ -62,47 +62,49 @@ final class MailshotTestAdminPage
$rows = is_array($preview['rows'] ?? null) ? $preview['rows'] : [];
$selectedRecipientIndex = (int) ($this->wp->requestParam('recipient_index', '0') ?? '0');
+ if ($selectedRecipientIndex < -1) {
+ $selectedRecipientIndex = 0;
+ }
$defaultEmail = $this->runService()->defaultTestEmail()['default_test_email'] ?? '';
$testEmail = (string) ($this->wp->requestParam('test_email', (string) $defaultEmail) ?? $defaultEmail);
$result = $this->result();
$action = htmlspecialchars($this->wp->adminUrl('admin-post.php'));
- echo 'Mailshot Test
';
+ echo '
Mailshot Test
';
+ echo $this->renderAdminUiStyles();
echo '
Render with a selected recipient context, then optionally send one test email.
';
if ($result !== null) {
$ok = !empty($result['ok']);
- $bg = $ok ? '#f1f8e9' : '#ffebee';
- $border = $ok ? '#8bc34a' : '#ef9a9a';
- echo '
';
+ $bannerClass = $ok ? 'feca-banner-success' : 'feca-banner-error';
+ echo '
';
echo '
' . ($ok ? 'Test action succeeded.' : 'Test action failed.') . '';
if (!empty($result['errors']) && is_array($result['errors'])) {
- echo '
' . htmlspecialchars(implode('; ', $result['errors'])) . '
';
+ echo '
' . htmlspecialchars(implode('; ', $result['errors'])) . '
';
}
if (!empty($result['warnings']) && is_array($result['warnings'])) {
- echo '
Warnings: ' . htmlspecialchars(implode('; ', $result['warnings'])) . '
';
+ echo '
Warnings: ' . htmlspecialchars(implode('; ', $result['warnings'])) . '
';
}
if (!empty($result['sent_to'])) {
- echo '
Sent to: ' . htmlspecialchars((string) $result['sent_to']) . '
';
+ echo '
Sent to: ' . htmlspecialchars((string) $result['sent_to']) . '
';
}
if (!empty($result['sent_at'])) {
- echo '
Sent at: ' . htmlspecialchars((string) $result['sent_at']) . '
';
+ echo '
Sent at: ' . htmlspecialchars((string) $result['sent_at']) . '
';
}
if (($result['ui_action'] ?? '') === 'render' && !empty($result['ok']) && is_array($result['rendered'] ?? null)) {
- echo '
';
+ echo '
';
}
- echo '
Show technical details
' . htmlspecialchars($this->debugJson($result), ENT_QUOTES) . '
';
echo '
';
}
- echo '
';
- echo '
1. Select Mailshot
';
- echo '