diff --git a/CLAUDE.md b/CLAUDE.md index eb13b68..205f402 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -36,6 +36,12 @@ This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase w _No known bugs at this time._ +### Version 0.0.9 + + + +**Note for AI Assistants:** Cleanup the versions in this section after implementation, but keep this notice! + ## Technical Stack - **Language:** PHP 8.3.x @@ -432,20 +438,15 @@ Full API documentation available in `openapi.json` (OpenAPI 3.1 specification). - Removed "Current Version" field from product license settings - Current version now automatically derived from latest product version in database -- Refactored email system to use WooCommerce email notification classes -- License Expiration Warning email is now configurable via WooCommerce > Settings > Emails -- Email templates can be overridden in themes (woocommerce/emails/license-expiration.php) +- Refactored email system to use WooCommerce transactional email system +- License Expiration Warning email configurable via WooCommerce > Settings > Emails +- Uses WooCommerce's email header/footer templates for consistent styling - Configurable warning days for expiration notifications (first and second warning) **New classes:** - `LicenseExpirationEmail` - WooCommerce WC_Email subclass for license expiration warnings -**New files:** - -- `templates/emails/license-expiration.php` - HTML email template -- `templates/emails/plain/license-expiration.php` - Plain text email template - **Modified classes:** - `LicensedProduct` - `get_current_version()` and `get_major_version()` now query VersionManager @@ -456,7 +457,8 @@ Full API documentation available in `openapi.json` (OpenAPI 3.1 specification). **Technical notes:** -- WooCommerce email system allows admins to customize subject, heading, content, and enable/disable -- Email templates follow WooCommerce conventions and can be overridden in themes +- Email uses WooCommerce's `emails/email-header.php` and `emails/email-footer.php` templates +- Email content is rendered inline, inheriting WooCommerce's styling and customizations +- Admins can customize subject, heading, additional content, and enable/disable via WC settings - Expiration warning schedule (days before) remains in plugin settings - Email enable/disable is controlled through WooCommerce email settings diff --git a/src/Email/LicenseEmailController.php b/src/Email/LicenseEmailController.php index 930d39c..d28f9ee 100644 --- a/src/Email/LicenseEmailController.php +++ b/src/Email/LicenseEmailController.php @@ -44,9 +44,6 @@ final class LicenseEmailController // Cron action for checking expiring licenses add_action('wclp_check_expiring_licenses', [$this, 'sendExpirationWarnings']); - - // Add email templates location for theme overrides - add_filter('woocommerce_locate_template', [$this, 'locateTemplate'], 10, 3); } /** @@ -61,30 +58,6 @@ final class LicenseEmailController return $email_classes; } - /** - * Locate templates in plugin directory - * - * @param string $template Template path - * @param string $template_name Template name - * @param string $template_path Template path prefix - * @return string Modified template path - */ - public function locateTemplate(string $template, string $template_name, string $template_path): string - { - // Only handle our email templates - if (strpos($template_name, 'emails/license-') !== 0) { - return $template; - } - - $plugin_template = WC_LICENSED_PRODUCT_PLUGIN_DIR . 'templates/' . $template_name; - - if (file_exists($plugin_template)) { - return $plugin_template; - } - - return $template; - } - /** * Schedule the expiration check cron job */ diff --git a/src/Email/LicenseExpirationEmail.php b/src/Email/LicenseExpirationEmail.php index d695c4b..c9b5d39 100644 --- a/src/Email/LicenseExpirationEmail.php +++ b/src/Email/LicenseExpirationEmail.php @@ -16,6 +16,7 @@ use WC_Email; * License Expiration Warning Email class * * Sends email notifications to customers when their licenses are about to expire. + * Uses WooCommerce's transactional email system for consistent styling and customization. */ class LicenseExpirationEmail extends WC_Email { @@ -39,6 +40,11 @@ class LicenseExpirationEmail extends WC_Email */ public string $expiration_date = ''; + /** + * Customer display name + */ + public string $customer_name = ''; + /** * Constructor */ @@ -49,10 +55,6 @@ class LicenseExpirationEmail extends WC_Email $this->title = __('License Expiration Warning', 'wc-licensed-product'); $this->description = __('License expiration warning emails are sent to customers when their licenses are about to expire.', 'wc-licensed-product'); - $this->template_html = 'emails/license-expiration.php'; - $this->template_plain = 'emails/plain/license-expiration.php'; - $this->template_base = WC_LICENSED_PRODUCT_PLUGIN_DIR . 'templates/'; - $this->placeholders = [ '{site_title}' => $this->get_blogname(), '{product_name}' => '', @@ -99,6 +101,7 @@ class LicenseExpirationEmail extends WC_Email $this->license = $license; $this->days_remaining = $days_remaining; $this->recipient = $customer->user_email; + $this->customer_name = $customer->display_name ?: __('Customer', 'wc-licensed-product'); $product = wc_get_product($license->getProductId()); $this->product_name = $product ? $product->get_name() : __('Unknown Product', 'wc-licensed-product'); @@ -134,22 +137,17 @@ class LicenseExpirationEmail extends WC_Email */ public function get_content_html(): string { - return wc_get_template_html( - $this->template_html, - [ - 'license' => $this->license, - 'days_remaining' => $this->days_remaining, - 'product_name' => $this->product_name, - 'expiration_date' => $this->expiration_date, - 'email_heading' => $this->get_heading(), - 'additional_content' => $this->get_additional_content(), - 'sent_to_admin' => false, - 'plain_text' => false, - 'email' => $this, - ], - '', - $this->template_base - ); + ob_start(); + + // Use WooCommerce's email header + wc_get_template('emails/email-header.php', ['email_heading' => $this->get_heading()]); + + $this->render_email_body_html(); + + // Use WooCommerce's email footer + wc_get_template('emails/email-footer.php', ['email' => $this]); + + return ob_get_clean(); } /** @@ -157,22 +155,132 @@ class LicenseExpirationEmail extends WC_Email */ public function get_content_plain(): string { - return wc_get_template_html( - $this->template_plain, - [ - 'license' => $this->license, - 'days_remaining' => $this->days_remaining, - 'product_name' => $this->product_name, - 'expiration_date' => $this->expiration_date, - 'email_heading' => $this->get_heading(), - 'additional_content' => $this->get_additional_content(), - 'sent_to_admin' => false, - 'plain_text' => true, - 'email' => $this, - ], - '', - $this->template_base - ); + ob_start(); + + echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"; + echo esc_html(wp_strip_all_tags($this->get_heading())); + echo "\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n"; + + $this->render_email_body_plain(); + + return ob_get_clean(); + } + + /** + * Render HTML email body content + */ + private function render_email_body_html(): void + { + $account_url = wc_get_account_endpoint_url('licenses'); + ?> +
customer_name)); ?>
+ + days_remaining === 1) : ?> ++ ' . esc_html($this->product_name) . '', + esc_html($this->expiration_date) + ); ?> +
+ ++ ' . esc_html($this->product_name) . '', + $this->days_remaining, + esc_html($this->expiration_date) + ); ?> +
+ + + + +| + | product_name); ?> | +
|---|---|
| + |
+
+ license->getLicenseKey()); ?>
+
+ |
+
| + | license->getDomain()); ?> | +
| + | expiration_date); ?> | +
+ + + +
+ customer_name)); + echo "\n\n"; + + if ($this->days_remaining === 1) { + printf( + esc_html__('Your license for %s will expire tomorrow (%s).', 'wc-licensed-product'), + esc_html($this->product_name), + esc_html($this->expiration_date) + ); + } else { + printf( + esc_html__('Your license for %1$s will expire in %2$d days (%3$s).', 'wc-licensed-product'), + esc_html($this->product_name), + $this->days_remaining, + esc_html($this->expiration_date) + ); + } + echo "\n\n"; + + echo "----------\n"; + echo esc_html__('License Details', 'wc-licensed-product') . "\n"; + echo "----------\n\n"; + + echo esc_html__('Product:', 'wc-licensed-product') . ' ' . esc_html($this->product_name) . "\n"; + echo esc_html__('License Key:', 'wc-licensed-product') . ' ' . esc_html($this->license->getLicenseKey()) . "\n"; + echo esc_html__('Domain:', 'wc-licensed-product') . ' ' . esc_html($this->license->getDomain()) . "\n"; + echo esc_html__('Expires:', 'wc-licensed-product') . ' ' . esc_html($this->expiration_date) . "\n\n"; + + $additional_content = $this->get_additional_content(); + if ($additional_content) { + echo "----------\n\n"; + echo esc_html(wp_strip_all_tags(wptexturize($additional_content))); + echo "\n\n"; + } + + echo esc_html__('View My Licenses', 'wc-licensed-product') . ': ' . esc_url(wc_get_account_endpoint_url('licenses')) . "\n\n"; + + echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"; } /** diff --git a/templates/emails/license-expiration.php b/templates/emails/license-expiration.php deleted file mode 100644 index 461ca7b..0000000 --- a/templates/emails/license-expiration.php +++ /dev/null @@ -1,97 +0,0 @@ -getCustomerId()); -$customer_name = $customer ? $customer->display_name : __('Customer', 'wc-licensed-product'); -$account_url = wc_get_account_endpoint_url('licenses'); -?> - - - - -- -
- -- -
- - - - -| - | - |
|---|---|
| - |
-
- getLicenseKey()); ?>
-
- |
-
| - | getDomain()); ?> | -
| - | - |
- - - -
- -getCustomerId()); -$customer_name = $customer ? $customer->display_name : __('Customer', 'wc-licensed-product'); - -echo sprintf(esc_html__('Hello %s,', 'wc-licensed-product'), esc_html($customer_name)) . "\n\n"; - -if ($days_remaining === 1) { - echo sprintf( - esc_html__('Your license for %s will expire tomorrow (%s).', 'wc-licensed-product'), - esc_html($product_name), - esc_html($expiration_date) - ) . "\n\n"; -} else { - echo sprintf( - esc_html__('Your license for %1$s will expire in %2$d days (%3$s).', 'wc-licensed-product'), - esc_html($product_name), - $days_remaining, - esc_html($expiration_date) - ) . "\n\n"; -} - -echo "----------\n"; -echo esc_html__('License Details', 'wc-licensed-product') . "\n"; -echo "----------\n\n"; - -echo esc_html__('Product:', 'wc-licensed-product') . ' ' . esc_html($product_name) . "\n"; -echo esc_html__('License Key:', 'wc-licensed-product') . ' ' . esc_html($license->getLicenseKey()) . "\n"; -echo esc_html__('Domain:', 'wc-licensed-product') . ' ' . esc_html($license->getDomain()) . "\n"; -echo esc_html__('Expires:', 'wc-licensed-product') . ' ' . esc_html($expiration_date) . "\n\n"; - -if ($additional_content) { - echo "----------\n\n"; - echo esc_html(wp_strip_all_tags(wptexturize($additional_content))); - echo "\n\n"; -} - -echo esc_html__('View My Licenses', 'wc-licensed-product') . ': ' . esc_url(wc_get_account_endpoint_url('licenses')) . "\n\n"; - -echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n";