From b609aca2cc365b644f505b52794094870ba60a69 Mon Sep 17 00:00:00 2001 From: Yasen Pramatarov Date: Tue, 23 Dec 2025 14:34:11 +0200 Subject: [PATCH] Loads email templates from "emails" views, available to plugins too. --- app/helpers/email_helper.php | 45 ++++++++++++++++--- app/templates/{ => emails}/password_reset.txt | 0 2 files changed, 39 insertions(+), 6 deletions(-) rename app/templates/{ => emails}/password_reset.txt (100%) diff --git a/app/helpers/email_helper.php b/app/helpers/email_helper.php index 002ffd9..2364306 100644 --- a/app/helpers/email_helper.php +++ b/app/helpers/email_helper.php @@ -11,13 +11,45 @@ * * @param string $templateName Template filename (without extension) * @param array $variables Variables to substitute + * @param array $options Additional options * @return string Rendered template content */ -function renderEmailTemplate($templateName, $variables = []) { - $templateFile = __DIR__ . '/../templates/' . $templateName . '.txt'; +function renderEmailTemplate($templateName, $variables = [], array $options = []) { + $searchPaths = []; - if (!file_exists($templateFile)) { - throw new RuntimeException("Email template '$templateName' not found"); + // Explicit plugin template path takes priority + if (!empty($options['plugin_template'])) { + $searchPaths[] = rtrim((string)$options['plugin_template'], DIRECTORY_SEPARATOR); + } + + // Plugin name maps to its templates directory (if registered) + if (!empty($options['plugin'])) { + $pluginKey = (string)$options['plugin']; + $pluginInfo = $GLOBALS['enabled_plugins'][$pluginKey] ?? null; + if (!empty($pluginInfo['path'])) { + $pluginBase = rtrim($pluginInfo['path'], DIRECTORY_SEPARATOR); + + // We search for email templates in the following locations: + // we can add more locations if needed, but "views/emails" is the standard location + $searchPaths[] = $pluginBase . '/views/emails'; + $searchPaths[] = $pluginBase . '/views/email'; + } + } + + // Fallback to core app templates + $searchPaths[] = __DIR__ . '/../templates/emails'; + + $templateFile = null; + foreach ($searchPaths as $basePath) { + $candidate = rtrim($basePath, DIRECTORY_SEPARATOR) . '/' . $templateName . '.txt'; + if (is_file($candidate)) { + $templateFile = $candidate; + break; + } + } + + if ($templateFile === null) { + throw new RuntimeException("Email template '$templateName' not found in any configured template paths"); } $content = file_get_contents($templateFile); @@ -39,11 +71,12 @@ function renderEmailTemplate($templateName, $variables = []) { * @param array $variables Template variables * @param array $config Application config * @param array $additionalHeaders Additional email headers + * @param array $options Additional options * @return bool Success status */ -function sendTemplateEmail($to, $subject, $templateName, $variables, $config, $additionalHeaders = []) { +function sendTemplateEmail($to, $subject, $templateName, $variables, $config, $additionalHeaders = [], array $options = []) { try { - $message = renderEmailTemplate($templateName, $variables); + $message = renderEmailTemplate($templateName, $variables, $options); $fromDomain = $config['domain'] ?? ($_SERVER['HTTP_HOST'] ?? 'totalmeet.local'); $headers = array_merge([ diff --git a/app/templates/password_reset.txt b/app/templates/emails/password_reset.txt similarity index 100% rename from app/templates/password_reset.txt rename to app/templates/emails/password_reset.txt