Skip to content
Snippets Groups Projects
Commit 310a2804 authored by Piotr Potrebka's avatar Piotr Potrebka
Browse files

feat: email abstract

parent 867d3d33
Branches
Tags
1 merge request!2Devel
Pipeline #152602 passed
......@@ -6,7 +6,6 @@ use WPDesk\View\Renderer\Renderer;
interface ConditionInterface {
public function is_valid(): bool;
}
<?php
namespace WPDesk\Library\WPEmail\Parser;
namespace WPDesk\Library\WPEmail\Helpers;
use Pelago\Emogrifier\CssInliner;
use Pelago\Emogrifier\HtmlProcessor\CssToAttributeConverter;
use Pelago\Emogrifier\HtmlProcessor\HtmlPruner;
class HTMLDecorator {
class HTML {
public static function style_inline( $content, $styles = '' ) {
if ( class_exists( 'DOMDocument' ) ) {
......
<?php
namespace WPDesk\Library\WPEmail\Helpers;
class Template {
/**
* Determine whether a hex color is light.
*
* @param mixed $color Color.
*
* @return bool True if a light color.
*/
public static function is_hex_light( $color ) {
$hex = str_replace( '#', '', $color );
$c_r = hexdec( substr( $hex, 0, 2 ) );
$c_g = hexdec( substr( $hex, 2, 2 ) );
$c_b = hexdec( substr( $hex, 4, 2 ) );
$brightness = ( ( $c_r * 299 ) + ( $c_g * 587 ) + ( $c_b * 114 ) ) / 1000;
return $brightness > 155;
}
public static function light_or_dark( $color, $dark = '#000000', $light = '#FFFFFF' ) {
return self::is_hex_light( $color ) ? $dark : $light;
}
/**
* Convert RGB to HEX.
*
* @param mixed $color Color.
*
* @return array
*/
public static function rgb_from_hex( $color ) {
$color = str_replace( '#', '', $color );
// Convert shorthand colors to full format, e.g. "FFF" -> "FFFFFF".
$color = preg_replace( '~^(.)(.)(.)$~', '$1$1$2$2$3$3', $color );
$rgb = [];
$rgb['R'] = hexdec( $color[0] . $color[1] );
$rgb['G'] = hexdec( $color[2] . $color[3] );
$rgb['B'] = hexdec( $color[4] . $color[5] );
return $rgb;
}
/**
* Make HEX color darker.
*
* @param mixed $color Color.
* @param int $factor Darker factor.
* Defaults to 30.
*
* @return string
*/
public static function hex_darker( $color, $factor = 30 ) {
$base = self::rgb_from_hex( $color );
$color = '#';
foreach ( $base as $k => $v ) {
$amount = $v / 100;
$amount = self::round( $amount * $factor );
$new_decimal = $v - $amount;
$new_hex_component = dechex( $new_decimal );
if ( strlen( $new_hex_component ) < 2 ) {
$new_hex_component = '0' . $new_hex_component;
}
$color .= $new_hex_component;
}
return $color;
}
/**
* Make HEX color lighter.
*
* @param mixed $color Color.
* @param int $factor Lighter factor.
* Defaults to 30.
*
* @return string
*/
public static function hex_lighter( $color, $factor = 30 ) {
$base = self::rgb_from_hex( $color );
$color = '#';
foreach ( $base as $k => $v ) {
$amount = 255 - $v;
$amount = $amount / 100;
$amount = self::round( $amount * $factor );
$new_decimal = $v + $amount;
$new_hex_component = dechex( $new_decimal );
if ( strlen( $new_hex_component ) < 2 ) {
$new_hex_component = '0' . $new_hex_component;
}
$color .= $new_hex_component;
}
return $color;
}
/**
* @param $val
* @param int $precision
* @param int $mode
*
* @return float
*/
public static function round( $val, int $precision = 0, int $mode = PHP_ROUND_HALF_UP ): float {
if ( ! is_numeric( $val ) ) {
$val = floatval( $val );
}
return round( $val, $precision, $mode );
}
}
......@@ -3,14 +3,14 @@
namespace WPDesk\Library\WPEmail;
use WPDesk\Library\WPEmail\Abstracts\EmailInterface;
use WPDesk\Library\WPEmail\Parser\HTMLDecorator;
use WPDesk\Library\WPEmail\Helpers\HTML;
use WPDesk\View\Renderer\Renderer;
use WPDesk\View\Renderer\SimplePhpRenderer;
use WPDesk\View\Resolver\ChainResolver;
use WPDesk\View\Resolver\DirResolver;
use WPDesk\View\Resolver\WPThemeResolver;
use WPDesk\View\Resolver\Resolver;
class EmailSender {
class Mailer {
/**
* @var EmailInterface[]
......@@ -20,12 +20,12 @@ class EmailSender {
/**
* @var string
*/
private $from = 'wordpress@wordpress.org';
private $from;
/**
* @var string
*/
private $from_name = 'WordPress';
private $from_name;
/**
* @var Renderer
......@@ -33,36 +33,89 @@ class EmailSender {
private $renderer;
/**
* @param $from
* @param $from_name
* @var array
*/
public function __construct() {
$this->init_renderer();
protected $placeholders = [];
/**
* @param string $from
* @param string $from_name
* @param Resolver[] $dir_resolvers
*/
public function __construct(
string $from = 'wordpress@wordpress.org',
string $from_name = 'WordPress',
array $dir_resolvers = []
) {
$this->from = $from;
$this->from_name = $from_name;
$this->set_renderer( $this->init_renderer( $dir_resolvers ) );
}
public function init_renderer() {
/**
* @param array $dir_resolvers
*
* @return Renderer
*/
private function init_renderer( array $dir_resolvers ): Renderer {
$resolver = new ChainResolver();
foreach ( $dir_resolvers as $dir_resolver ) {
if ( $dir_resolver instanceof Resolver ) {
$resolver->appendResolver( $dir_resolver );
}
}
$resolver->appendResolver( new DirResolver( __DIR__ ) );
$this->renderer = new SimplePhpRenderer( $resolver );
return new SimplePhpRenderer( $resolver );
}
/**
* @param Renderer $renderer
*
* @return void
*/
public function set_renderer( Renderer $renderer ) {
$this->renderer = $renderer;
}
/**
* @param EmailInterface $email
*
* @return void
*/
public function add_email( EmailInterface $email ) {
$this->emails[ $email->get_id() ] = $email;
}
/**
* @return EmailInterface[]
*/
public function get_emails(): array {
return $this->emails;
}
public function set_from( string $from ) {
$this->from = $from;
/**
* Set placeholders.
*
* @param array $placeholders
*
* @return self
*/
public function set_placeholders( array $placeholders = [] ): self {
$this->placeholders = array_merge( $this->placeholders, $placeholders );
return $this;
}
/**
* Get defined placeholders.
*
* @return string[]
*/
public function get_placeholders(): array {
return $this->placeholders;
}
/**
* WordPress callback for setting the from email
......@@ -71,7 +124,7 @@ class EmailSender {
*
* @return string
*/
public function from( $email ): string {
public function from_filter( string $email ): string {
if ( ! empty( $this->from ) && is_email( $this->from ) ) {
$email = $this->from;
}
......@@ -80,11 +133,6 @@ class EmailSender {
}
public function set_from_name( string $from_name ) {
$this->from_name = $from_name;
}
/**
* WordPress callback for setting the from name
*
......@@ -92,7 +140,7 @@ class EmailSender {
*
* @return string
*/
public function from_name( $name ) {
public function from_name_filter( string $name ): string {
if ( ! empty( $this->from_name ) ) {
$name = html_entity_decode( sanitize_text_field( $this->from_name ) );
}
......@@ -105,41 +153,40 @@ class EmailSender {
*
* @return void
*/
private function before_wp_mail() {
add_filter( 'wp_mail_from', array( $this, 'from' ) );
add_filter( 'wp_mail_from_name', array( $this, 'from_name' ) );
protected function before_wp_mail() {
add_filter( 'wp_mail_from', array( $this, 'from_filter' ) );
add_filter( 'wp_mail_from_name', array( $this, 'from_name_filter' ) );
}
public function send( array $placeholders = [] ) {
public function send() {
$this->before_wp_mail();
foreach ( $this->get_emails() as $email ) {
$template = $this->get_template( $email, $placeholders );
$subject = $this->replace_placeholders( $email->get_subject() );
if ( $email->get_is_enable() ) {
$this->before_wp_mail();
wp_mail(
$email->get_recipients(), $email->get_subject(), $this->css_inline( $template ), $email->get_headers(), $email->get_attachments()
$email->get_recipients(), $subject, $this->get_body( $email ), $email->get_headers(), $email->get_attachments()
);
$this->after_wp_mail();
}
}
$this->after_wp_mail();
}
public function get_template( EmailInterface $email, $placeholders = [] ): string {
$content = $this->replace_placeholders( $email->get_content(), $placeholders );
protected function get_body( EmailInterface $email ): string {
$content = $this->replace_placeholders( $email->get_content() );
$output = $this->renderer->render( 'html/email-header', [ 'heading' => $email->get_heading(), 'logo' => '' ] );
$output .= $this->renderer->render( 'html/' . $email->get_id(), [ 'content' => $content ] );
$output .= $this->renderer->render( 'html/email-footer', [] );
$output .= $this->renderer->render( 'html/email-footer', [ 'footer' => '' ] );
return $output;
return $this->css_inline( $output );
}
/**
* @param string $content
* @param array $placeholders
* @param string $string
*
* @return array|string|string[]
*/
private function replace_placeholders( string $content, array $placeholders = [] ): string {
return str_replace( array_keys( $placeholders ), array_values( $placeholders ), $content );
protected function replace_placeholders( string $string ): string {
return (string) str_replace( array_keys( $this->placeholders ), array_values( $this->placeholders ), $string );
}
/**
......@@ -147,10 +194,10 @@ class EmailSender {
*
* @return mixed|string
*/
private function css_inline( string $content ): string {
protected function css_inline( string $content ): string {
$styles = $this->renderer->render( 'html/email-styles', [] );
return HTMLDecorator::style_inline( $content, $styles );
return HTML::style_inline( $content, $styles );
}
/**
......@@ -158,9 +205,9 @@ class EmailSender {
*
* @return void
*/
private function after_wp_mail() {
remove_filter( 'wp_mail_from', array( $this, 'from' ) );
remove_filter( 'wp_mail_from_name', array( $this, 'from_name' ) );
protected function after_wp_mail() {
remove_filter( 'wp_mail_from', array( $this, 'from_filter' ) );
remove_filter( 'wp_mail_from_name', array( $this, 'from_name_filter' ) );
}
}
<?php
declare( strict_types=1 );
namespace WPDesk\Library\WPEmail;
class MailerException extends \RuntimeException {
public static function with_wp_error( \WP_Error $error ): self {
$errors = $error->get_error_messages( 'wp_mail_failed' );
$message = implode( "\n", $errors );
return new self( sprintf( 'wp_mail() failure. Message [%s]', $message ) );
}
}
......@@ -40,7 +40,7 @@ defined( 'ABSPATH' ) || exit;
<table border="0" cellpadding="10" cellspacing="0" width="100%">
<tr>
<td colspan="2" valign="middle" id="credit">
<?php echo wp_kses_post( wpautop( wptexturize( apply_filters( 'wpdesk/wp_mail/template/footer', '' ) ) ) ); ?>
<?php echo $params['footer'] ?? ''; ?>
</td>
</tr>
</table>
......
......@@ -47,7 +47,7 @@ $params = isset( $params ) ? $params : [];
<table border="0" cellpadding="0" cellspacing="0" width="100%" id="template_header">
<tr>
<td id="header_wrapper">
<h1><?php echo $params['heading']; ?></h1>
<h1><?php echo $params['heading'] ?? 'Header'; ?></h1>
</td>
</tr>
</table>
......
<?php
/**
* Email Styles
*
* This template can be overridden by copying it to yourtheme/woocommerce/emails/email-styles.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* @see https://docs.woocommerce.com/document/template-structure/
* @package WooCommerce\Templates\Emails
* @version 4.0.0
*/
use WPDesk\Library\WPEmail\Helpers\Template;
$params = isset( $params ) ? $params : [];
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Load colors.
$bg = get_option( 'woocommerce_email_background_color' );
$body = get_option( 'woocommerce_email_body_background_color' );
$base = get_option( 'woocommerce_email_base_color' );
$base_text = wc_light_or_dark( $base, '#202020', '#ffffff' );
$text = get_option( 'woocommerce_email_text_color' );
$bg = $params['bg'] ?? '#f9f9f9';
$body = $params['body'] ?? '#ffffff';
$base = $params['base'] ?? '#d15291';
$base_text = Template::light_or_dark( $base, '#171717', '#ffffff' );
$text = $params['text'] ?? '#303030';
// Pick a contrasting color for links.
$link_color = wc_hex_is_light( $base ) ? $base : $base_text;
$link_color = Template::is_hex_light( $base ) ? $base : $base_text;
if ( wc_hex_is_light( $body ) ) {
$link_color = wc_hex_is_light( $base ) ? $base_text : $base;
if ( Template::is_hex_light( $body ) ) {
$link_color = Template::is_hex_light( $base ) ? $base_text : $base;
}
$bg_darker_10 = wc_hex_darker( $bg, 10 );
$body_darker_10 = wc_hex_darker( $body, 10 );
$base_lighter_20 = wc_hex_lighter( $base, 20 );
$base_lighter_40 = wc_hex_lighter( $base, 40 );
$text_lighter_20 = wc_hex_lighter( $text, 20 );
$text_lighter_40 = wc_hex_lighter( $text, 40 );
$bg_darker_10 = Template::hex_darker( $bg, 10 );
$body_darker_10 = Template::hex_darker( $body, 10 );
$base_lighter_20 = Template::hex_lighter( $base, 20 );
$base_lighter_40 = Template::hex_lighter( $base, 40 );
$text_lighter_20 = Template::hex_lighter( $text, 20 );
$text_lighter_40 = Template::hex_lighter( $text, 40 );
// !important; is a gmail hack to prevent styles being stripped if it doesn't like something.
// body{padding: 0;} ensures proper scale/positioning of the email in the iOS native email app.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment