Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3dd9e63
New: init version of plugin feature with template parts
DanielHudson2 Aug 4, 2025
4362651
Fix: tried to use class as a trait
DanielHudson2 Aug 4, 2025
f8dab27
New: add styles as separate file
DanielHudson2 Aug 4, 2025
558fbc5
New: only apply template to non html emails, specific gf scenario
DanielHudson2 Aug 4, 2025
082551a
New: add logo to template
DanielHudson2 Aug 4, 2025
b7c2db0
Fix: code sniffer fixes
DanielHudson2 Aug 4, 2025
2407755
New: rename template functions and where they go in the theme
DanielHudson2 Aug 4, 2025
c658d3f
New: bring template inline with WooCommerce base
DanielHudson2 Aug 5, 2025
4efc8a3
New: inline all the styles from within <style> before passing email c…
DanielHudson2 Aug 7, 2025
63d34a6
New: use mozart to handle dependency loading
DanielHudson2 Aug 7, 2025
b7f3008
New: ignore dependencies folder in code sniffer
DanielHudson2 Aug 7, 2025
54dcc64
Fix: remove left margin from logo
DanielHudson2 Aug 7, 2025
3c23e8b
Fix: resolve setting values that aren't hexcodes
DanielHudson2 Aug 7, 2025
1fdf907
New: use woocommerce colours if they are set
DanielHudson2 Aug 7, 2025
09c14a2
New: gravity forms branding in emails
DanielHudson2 Aug 8, 2025
61cecf5
Add method comments for phpcs
brettsmason Aug 11, 2025
6c84e95
Correct class comment
brettsmason Aug 11, 2025
464a915
New: update colour resolver to work with direct variable declarations…
DanielHudson2 Aug 11, 2025
f857a8e
Merge branch 'feature/branded-emails' of github.com:eighteen73/orbit …
DanielHudson2 Aug 11, 2025
10609b6
Tidy: remove unused variable
DanielHudson2 Aug 11, 2025
e07a037
New: check if woocommerce is active before getting settings, hook for…
DanielHudson2 Aug 11, 2025
989c691
New: rename filter for disabling branded emails
DanielHudson2 Aug 11, 2025
a7ff01b
New: document branded emails feature
DanielHudson2 Aug 11, 2025
31ac628
New: additional documentation on branded emails
DanielHudson2 Aug 11, 2025
da7cb39
New: categorise filters documentation
DanielHudson2 Aug 11, 2025
fa00bf2
Fix typo
brettsmason Aug 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions includes/classes/BrandedEmails.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?php
/**
* Add branding email templates to site emails.
*
* @package Orbit
*/

namespace Eighteen73\Orbit;

/**
* This class is built upon BE Media from Production so all due credit to those authors.
* http://www.github.com/billerickson/be-media-from-production
*/
class BrandedEmails {

use Environment;
use Singleton;

/**
* Primary constructor
*
* @return void
*/
public function setup() {
if ( apply_filters( 'orbit_branded_emails_disable', false ) ) {
return;
}

add_filter( 'wp_mail', [ $this, 'apply_branded_email_template' ] );
add_filter( 'gform_html_message_template_pre_send_email', [ $this, 'apply_branded_email_template_to_gf_notifications' ] );
}

/**
* Wraps the original email message in a branded HTML email template.
*
* @param array $args Array of arguments passed to wp_mail().
* @return array Modified $args array with the email message wrapped in branded HTML.
*/
public function apply_branded_email_template( $args ) {
$headers = [];

// Convert headers to an array if they aren't already
if ( empty( $args['headers'] ) ) {
$headers = [];
} elseif ( is_string( $args['headers'] ) ) {
$headers = explode( "\n", str_replace( "\r\n", "\n", $args['headers'] ) );
} elseif ( is_array( $args['headers'] ) ) {
$headers = $args['headers'];
}

// Check if Content-Type is already set to HTML
$content_type_is_html = false;
foreach ( $headers as $header ) {
if ( stripos( $header, 'Content-Type:' ) !== false && stripos( $header, 'text/html' ) !== false ) {
$content_type_is_html = true;
break;
}
}

// If email is already HTML return original $args
if ( $content_type_is_html ) {
return $args;
}

ob_start();

Templates::include_template_part(
'branded-emails/email-template.php',
[
'email_content' => $args['message'],
'email_subject' => isset( $args['subject'] ) ? $args['subject'] : '',
]
);

$styled_message = ob_get_clean();

// Remove existing Content-Type headers (at this point we've already established it's not HTML)
$headers = array_filter(
$headers,
function ( $header ) {
return stripos( $header, 'Content-Type:' ) === false;
}
);

// Add HTML Content-Type
$headers[] = 'Content-Type: text/html; charset=UTF-8';

// Set updated headers and message
$args['headers'] = $headers;
$args['message'] = $styled_message;

return $args;
}

/**
* Provides a branded HTML template for Gravity Forms email notifications.
*
* `{message}` and `{subject}` placeholders will be replaced by
* Gravity Forms with the actual notification content.
*
* @param string $template The original email template string (usually empty).
* @return string The modified email template with placeholders for message and subject.
*/
public function apply_branded_email_template_to_gf_notifications( $template ) {
ob_start();

Templates::include_template_part(
'branded-emails/email-template.php',
[
'email_content' => '{message}',
'email_subject' => '{subject}',
]
);

$template = ob_get_clean();

return $template;
}
}
49 changes: 49 additions & 0 deletions includes/classes/Templates.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php
/**
* Template functions for Orbit.
*
* @package Orbit
*/

namespace Eighteen73\Orbit;

/**
* This class is built upon BE Media from Production so all due credit to those authors.
* http://www.github.com/billerickson/be-media-from-production
*/
class Templates {

use Environment;
use Singleton;

/**
* Function to get the template file from the theme if it exists, otherwise from the plugin.
*
* @param string $template_name The name of the template file.
* @return string The path to the template file.
*/
private static function get_template_part( $template_name ) {
$theme_template = get_stylesheet_directory() . '/template-parts/' . $template_name;

if ( file_exists( $theme_template ) ) :
return $theme_template;
endif;

return ORBIT_PATH . 'template-parts/' . $template_name;
}

/**
* Function to include the template file from the get_template_part function.
*
* @param string $template_name The name of the template file.
* @param array $args Optional. Associative array of variables to make available in the template.
*/
public static function include_template_part( string $template_name, array $args = [] ) {

$template_path = self::get_template_part( $template_name );

if ( file_exists( $template_path ) ) {
include $template_path;
}
}
}
1 change: 1 addition & 0 deletions orbit.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function () {
Security\HideAuthor::instance()->setup();
Security\HideVersion::instance()->setup();
Security\RemoveHeadLinks::instance()->setup();
BrandedEmails::instance()->setup();
OtherFilters::instance()->setup();
HealthCheck::instance()->setup();
RemoteFiles::instance()->setup();
Expand Down
54 changes: 54 additions & 0 deletions template-parts/branded-emails/email-styles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
/**
* Branded Email Styles
* This file can be overridden in your theme.
*
* @package Orbit
*/

if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}

$background_color = apply_filters( 'orbit_branded_emails_background_color', '#f4f4f4' );
$body_background_color = apply_filters( 'orbit_branded_emails_body_background_color', '#ffffff' );
$body_border_color = apply_filters( 'orbit_branded_emails_body_border_color', '#ddd' );
$body_max_width = apply_filters( 'orbit_branded_emails_body_max_width', '800px' );
$body_text_color = apply_filters( 'orbit_branded_emails_body_text_color', '#000' );
$footer_text_color = apply_filters( 'orbit_branded_emails_footer_text_color', '#999' );
?>

<style>
body {
background: <?php echo esc_attr( $background_color ); ?>;
font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
padding: 20px;
}

.email-wrapper {
background: <?php echo esc_attr( $body_background_color ); ?>;
border: 1px solid <?php echo esc_attr( $body_border_color ); ?>;
border-radius: 6px;
color: <?php echo esc_attr( $body_text_color ); ?>;
max-width: <?php echo esc_attr( $body_max_width ); ?>;
margin: 0 auto;
padding: 20px;
}

.email-header img {
max-height: 100px;
width: auto;
}

.email-content {
margin-bottom: 40px;
margin-top: 40px;
}

.email-footer {
color: <?php echo esc_attr( $footer_text_color ); ?>;
font-size: 12px;
margin-top: 20px;
text-align: center;
}
</style>
51 changes: 51 additions & 0 deletions template-parts/branded-emails/email-template.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
/**
* Branded Email Template
* This file can be overridden in your theme.
*
* @package Orbit
*
* @var string $email_content
*/

namespace Eighteen73\Orbit;

if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}

$header_logo = apply_filters( 'orbit_branded_emails_header_logo', '' );
$email_content = $args['email_content'] ?? '';
$email_subject = $args['email_subject'] ?? get_bloginfo( 'name', 'display' );
?>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><?php echo esc_attr( $email_subject ); ?></title>
<?php Templates::include_template_part( 'branded-emails/email-styles.php' ); ?>
</head>

<body>
<div class="email-wrapper">
<div class="email-header">
<?php
if ( ! empty( $header_logo ) ) {
echo '<p style="margin-top:0;"><img src="' . esc_url( $header_logo ) . '" alt="' . esc_attr( get_bloginfo( 'name', 'display' ) ) . '" /></p>';
} else {
echo '<h1>' . esc_html( get_bloginfo( 'name' ) ) . '</h1>';
}
?>
</div>

<div class="email-content">
<?php echo wp_kses_post( wpautop( $email_content ) ); ?>
</div>

<div class="email-footer">
Sent from <?php echo esc_html( get_bloginfo( 'name', 'display' ) ); ?>
</div>
</div>
</body>
</html>