Compare commits

..

29 Commits

Author SHA1 Message Date
a25ea3ddf6 Bump up release version to 0.0.23 2016-04-09 02:08:05 +03:00
021349caee Merge pull request #415 from mailpoet/public_api_update
Updates query parameters for public API
2016-04-09 02:01:20 +03:00
89f2958d23 - Updates cron to use new public API query parameters 2016-04-08 18:53:57 -04:00
8c8435766e - Updates query parameters for public API 2016-04-08 18:40:45 -04:00
40dd1bbb3b Merge pull request #413 from mailpoet/rendering_engine_update
Rendering engine update
2016-04-08 22:27:48 +03:00
ba40437eb9 - Enables dynamic line-height based on font-size 2016-04-08 15:19:14 -04:00
813db1ae33 - Sets LI bottom margin to 10px 2016-04-08 08:45:09 -04:00
9588397e4e - Moves all styles logic to the StylesHelper class
- Sets margin-bottom on h1-4 to be 0.3*font-size
2016-04-07 19:39:09 -04:00
ecf83ca419 - Disables color compression when tidying CSS 2016-04-07 19:39:09 -04:00
9cc494f0fa - Removes image height HTML attribute and sets "height:auto" style 2016-04-07 19:39:09 -04:00
dd4b7e4d1c - Adds lines heights to LIs 2016-04-07 19:39:09 -04:00
738b2f6c17 - Adds dynamic line breaks to paragraphs when the elment is followed by
list
2016-04-07 19:39:09 -04:00
33289342d3 - Implements dynamic margins on headings 2016-04-07 19:39:09 -04:00
a00f1efcfe - Updates unit test due to button style change 2016-04-07 19:38:15 -04:00
b89897e6d4 - Adds line breaks after headings IF they are followed by paragraph
- Adds line breaks after blocksquotes
- Updates margin on lists
- Adds line breaks after paragraphs IF they are not the last element
2016-04-07 19:38:15 -04:00
c539837896 - Makes button's stroke width = border width 2016-04-07 19:38:15 -04:00
27edf5f71d - Updates list styles 2016-04-07 19:38:15 -04:00
32cc5644f9 - Removes height:auto from images 2016-04-07 19:38:15 -04:00
8a664aa7f1 - Set left text alignment on all elements when alignment is otherwise
absent
2016-04-07 19:38:15 -04:00
7e5e8a4282 - Updates button padding 2016-04-07 19:38:15 -04:00
70d5d609e2 Merge pull request #412 from mailpoet/scheduled_sending
Fixes an issue with welcome emails not being sent to confirmed subscribers
2016-04-07 12:09:30 +03:00
19160c99e1 Merge pull request #411 from mailpoet/send_with_review
Send with review
2016-04-06 18:23:50 +03:00
99b2a7457e Merge pull request #410 from mailpoet/newsletter_send_preview_fix
Fixes an issue with shortcodes not rendering when sending newsletter
2016-04-06 18:05:39 +03:00
945d7edc70 Send with review
- updated MailPoet logo
- added SPF
- hide Dkim for beta
- added warning in case the number of emails/sec is too high
2016-04-06 16:57:10 +02:00
6a97badfed - Fixes an issue with welcome emails not being seint to confirmed
subscribers
2016-04-05 14:34:22 -04:00
5ec8e4ed52 - Fixes an issue with shortcodes not rendering when sending newsletter
preview
2016-04-05 09:54:04 -04:00
1569b5f80a Merge pull request #409 from mailpoet/scheduled_sending
Fixed an issue with newsletter schedule not being saved
2016-04-05 12:10:34 +03:00
e62ecc5036 - Fixes duplicate detection check 2016-04-04 21:09:15 -04:00
b0150e184b - Fixed an issue with newsletter schedule not being saved 2016-04-04 19:41:18 -04:00
24 changed files with 232 additions and 186 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -34,13 +34,16 @@ define(
// show sending methods // show sending methods
jQuery('.mailpoet_sending_methods').fadeIn(); jQuery('.mailpoet_sending_methods').fadeIn();
} else { } else {
// hide DKIM option when using MailPoet's API // toggle SPF/DKIM (hidden if the sending method is MailPoet)
jQuery('#mailpoet_mta_dkim')[ jQuery('#mailpoet_mta_spf')[
(group === 'mailpoet') (group === 'mailpoet')
? 'hide' ? 'hide'
: 'show' : 'show'
](); ]();
// (HIDDEN FOR BETA)
jQuery('#mailpoet_mta_dkim').hide();
// hide sending methods // hide sending methods
jQuery('.mailpoet_sending_methods').hide(); jQuery('.mailpoet_sending_methods').hide();

View File

@ -8,38 +8,38 @@ if(!defined('ABSPATH')) exit;
class PublicAPI { class PublicAPI {
public $api; public $api;
public $section; public $endpoint;
public $action; public $action;
public $request_payload; public $data;
function __construct() { function __construct() {
# http://example.com/?mailpoet-api&section=&action=&request_payload= # http://example.com/?mailpoet&endpoint=&action=&data=
$this->api = isset($_GET['mailpoet-api']) ? true : false; $this->api = isset($_GET['mailpoet']) ? true : false;
$this->section = isset($_GET['section']) ? $_GET['section'] : false; $this->endpoint = isset($_GET['endpoint']) ?
Helpers::underscoreToCamelCase($_GET['endpoint']) :
false;
$this->action = isset($_GET['action']) ? $this->action = isset($_GET['action']) ?
Helpers::underscoreToCamelCase($_GET['action']) : Helpers::underscoreToCamelCase($_GET['action']) :
false; false;
$this->request_payload = isset($_GET['request_payload']) ? $this->data = isset($_GET['data']) ? $_GET['data'] : false;
unserialize(base64_decode($_GET['request_payload'])) :
false;
} }
function init() { function init() {
if(!$this->api && !$this->section) return; if(!$this->api && !$this->endpoint) return;
$this->_checkAndCallMethod($this, $this->section, $terminate = true); $this->_checkAndCallMethod($this, $this->endpoint, $terminate_request = true);
} }
function queue() { function queue() {
try { try {
$queue = new Daemon($this->request_payload); $queue = new Daemon($this->data);
$this->_checkAndCallMethod($queue, $this->action); $this->_checkAndCallMethod($queue, $this->action);
} catch(\Exception $e) { } catch(\Exception $e) {
} }
} }
private function _checkAndCallMethod($class, $method, $terminate = false) { private function _checkAndCallMethod($class, $method, $terminate_request = false) {
if(!method_exists($class, $method)) { if(!method_exists($class, $method)) {
if(!$terminate) return; if(!$terminate_request) return;
header('HTTP/1.0 404 Not Found'); header('HTTP/1.0 404 Not Found');
exit; exit;
} }

View File

@ -38,9 +38,9 @@ class CronHelper {
} }
static function accessDaemon($token, $timeout = self::daemon_request_timeout) { static function accessDaemon($token, $timeout = self::daemon_request_timeout) {
$payload = serialize(array('token' => $token)); $data = serialize(array('token' => $token));
$url = '/?mailpoet-api&section=queue&action=run&request_payload=' . $url = '/?mailpoet&endpoint=queue&action=run&data=' .
base64_encode($payload); base64_encode($data);
$args = array( $args = array(
'timeout' => $timeout, 'timeout' => $timeout,
'user-agent' => 'MailPoet (www.mailpoet.com) Cron' 'user-agent' => 'MailPoet (www.mailpoet.com) Cron'

View File

@ -10,17 +10,18 @@ if(!defined('ABSPATH')) exit;
class Daemon { class Daemon {
public $daemon; public $daemon;
public $request_payload; public $data;
public $refreshed_token; public $refreshed_token;
const daemon_request_timeout = 5; const daemon_request_timeout = 5;
private $timer; private $timer;
function __construct($request_payload = array()) { function __construct($data) {
if (!$data) $this->abortWithError(__('Invalid or missing cron data.'));
set_time_limit(0); set_time_limit(0);
ignore_user_abort(); ignore_user_abort();
$this->daemon = CronHelper::getDaemon(); $this->daemon = CronHelper::getDaemon();
$this->token = CronHelper::createToken(); $this->token = CronHelper::createToken();
$this->request_payload = $request_payload; $this->data = unserialize(base64_decode($data));
$this->timer = microtime(true); $this->timer = microtime(true);
} }
@ -29,8 +30,8 @@ class Daemon {
if(!$daemon) { if(!$daemon) {
$this->abortWithError(__('Daemon does not exist.')); $this->abortWithError(__('Daemon does not exist.'));
} }
if(!isset($this->request_payload['token']) || if(!isset($this->data['token']) ||
$this->request_payload['token'] !== $daemon['token'] $this->data['token'] !== $daemon['token']
) { ) {
$this->abortWithError(__('Invalid or missing token.')); $this->abortWithError(__('Invalid or missing token.'));
} }
@ -49,7 +50,7 @@ class Daemon {
// after each execution, re-read daemon data in case it was deleted or // after each execution, re-read daemon data in case it was deleted or
// its status has changed // its status has changed
$daemon = CronHelper::getDaemon(); $daemon = CronHelper::getDaemon();
if(!$daemon || $daemon['token'] !== $this->request_payload['token']) { if(!$daemon || $daemon['token'] !== $this->data['token']) {
exit; exit;
} }
$daemon['counter']++; $daemon['counter']++;

View File

@ -69,11 +69,7 @@ class Scheduler {
->findArray(); ->findArray();
$subscribers = Helpers::arrayColumn($subscribers, 'subscriber_id'); $subscribers = Helpers::arrayColumn($subscribers, 'subscriber_id');
$subscribers = array_unique($subscribers); $subscribers = array_unique($subscribers);
if(!count($subscribers)) { if(!count($subscribers) || !$this->checkIfNewsletterChanged($newsletter)) {
$queue->delete();
return;
}
if(!$this->checkIfNewsletterChanged($newsletter)) {
$queue->scheduled_at = $next_run_date; $queue->scheduled_at = $next_run_date;
$queue->save(); $queue->save();
return; return;
@ -141,7 +137,7 @@ class Scheduler {
$rendered_newsletter = $renderer->render(); $rendered_newsletter = $renderer->render();
$new_hash = md5($rendered_newsletter['html']); $new_hash = md5($rendered_newsletter['html']);
$old_hash = $last_run_queue->newsletter_rendered_body_hash; $old_hash = $last_run_queue->newsletter_rendered_body_hash;
return $new_hash !== $old_hash; return $new_hash === $old_hash;
} }
private function getQueueNextRunDate($schedule) { private function getQueueNextRunDate($schedule) {

View File

@ -11,7 +11,7 @@ class Setting extends Model {
const DEFAULT_SENDING_METHOD_GROUP = 'website'; const DEFAULT_SENDING_METHOD_GROUP = 'website';
const DEFAULT_SENDING_METHOD = 'PHPMail'; const DEFAULT_SENDING_METHOD = 'PHPMail';
const DEFAULT_SENDING_FREQUENCY_EMAILS = 25; const DEFAULT_SENDING_FREQUENCY_EMAILS = 25;
const DEFAULT_SENDING_FREQUENCY_INTERVAL = 15; // in minutes const DEFAULT_SENDING_FREQUENCY_INTERVAL = 5; // in minutes
function __construct() { function __construct() {
parent::__construct(); parent::__construct();

View File

@ -13,7 +13,7 @@ class SubscriberSegment extends Model {
} }
function subscriber() { function subscriber() {
return $this->has_one(__NAMESPACE__.'\Subscriber', 'id'); return $this->has_one(__NAMESPACE__.'\Subscriber', 'id', 'subscriber_id');
} }
static function setSubscriptions($subscriber, $segment_ids = array()) { static function setSubscriptions($subscriber, $segment_ids = array()) {

View File

@ -13,14 +13,14 @@ class Button {
<div> <div>
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0;"> <table width="100%" cellpadding="0" cellspacing="0" border="0" style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0;">
<tr> <tr>
<td class="mailpoet_button-container" style="padding:8px 20px;text-align:' . $element['styles']['block']['textAlign'] . ';"><!--[if mso]> <td class="mailpoet_button-container" style="text-align:' . $element['styles']['block']['textAlign'] . ';"><!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" <v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"
href="' . $element['url'] . '" href="' . $element['url'] . '"
style="height:' . $element['styles']['block']['lineHeight'] . '; style="height:' . $element['styles']['block']['lineHeight'] . ';
width:' . $element['styles']['block']['width'] . '; width:' . $element['styles']['block']['width'] . ';
v-text-anchor:middle;" v-text-anchor:middle;"
arcsize="' . round($element['styles']['block']['borderRadius'] / $element['styles']['block']['lineHeight'] * 100) . '%" arcsize="' . round($element['styles']['block']['borderRadius'] / $element['styles']['block']['lineHeight'] * 100) . '%"
strokeweight="1px" strokeweight="' . $element['styles']['block']['borderWidth'] . '"
strokecolor="' . $element['styles']['block']['borderColor'] . '" strokecolor="' . $element['styles']['block']['borderColor'] . '"
fillcolor="' . $element['styles']['block']['backgroundColor'] . '"> fillcolor="' . $element['styles']['block']['backgroundColor'] . '">
<w:anchorlock/> <w:anchorlock/>

View File

@ -7,6 +7,9 @@ class Footer {
static function render($element) { static function render($element) {
$element['text'] = preg_replace('/\n/', '<br /><br />', $element['text']); $element['text'] = preg_replace('/\n/', '<br /><br />', $element['text']);
$element['text'] = preg_replace('/(<\/?p.*?>)/i', '', $element['text']); $element['text'] = preg_replace('/(<\/?p.*?>)/i', '', $element['text']);
$line_height = sprintf(
'%spx', StylesHelper::$line_height_multiplier * (int) $element['styles']['text']['fontSize']
);
$DOM_parser = new \pQuery(); $DOM_parser = new \pQuery();
$DOM = $DOM_parser->parseStr($element['text']); $DOM = $DOM_parser->parseStr($element['text']);
if(isset($element['styles']['link'])) { if(isset($element['styles']['link'])) {
@ -25,7 +28,7 @@ class Footer {
$template = ' $template = '
<tr> <tr>
<td class="mailpoet_header_footer_padded mailpoet_footer" ' . $background_color . ' <td class="mailpoet_header_footer_padded mailpoet_footer" ' . $background_color . '
style="line-height: ' . StylesHelper::$line_height . ';' . StylesHelper::getBlockStyles($element) . StylesHelper::getStyles($element['styles'], 'text') . '"> style="line-height: ' . $line_height . ';' . StylesHelper::getBlockStyles($element) . StylesHelper::getStyles($element['styles'], 'text') . '">
' . $DOM->html() . ' ' . $DOM->html() . '
</td> </td>
</tr>'; </tr>';

View File

@ -6,7 +6,10 @@ use MailPoet\Newsletter\Renderer\StylesHelper;
class Header { class Header {
static function render($element) { static function render($element) {
$element['text'] = preg_replace('/\n/', '<br /><br />', $element['text']); $element['text'] = preg_replace('/\n/', '<br /><br />', $element['text']);
$element['text'] = preg_replace('/(<\/?p.*?>)/', '', $element['text']); $element['text'] = preg_replace('/(<\/?p.*?>)/i', '', $element['text']);
$line_height = sprintf(
'%spx', StylesHelper::$line_height_multiplier * (int) $element['styles']['text']['fontSize']
);
$DOM_parser = new \pQuery(); $DOM_parser = new \pQuery();
$DOM = $DOM_parser->parseStr($element['text']); $DOM = $DOM_parser->parseStr($element['text']);
if(isset($element['styles']['link'])) { if(isset($element['styles']['link'])) {
@ -25,7 +28,7 @@ class Header {
$template = ' $template = '
<tr> <tr>
<td class="mailpoet_header_footer_padded mailpoet_header" ' . $background_color . ' <td class="mailpoet_header_footer_padded mailpoet_header" ' . $background_color . '
style="' . StylesHelper::getBlockStyles($element) . StylesHelper::getStyles($element['styles'], 'text') . '"> style="line-height: ' . $line_height . ';' . StylesHelper::getBlockStyles($element) . StylesHelper::getStyles($element['styles'], 'text') . '">
' . $DOM->html() . ' ' . $DOM->html() . '
</td> </td>
</tr>'; </tr>';

View File

@ -11,7 +11,7 @@ class Image {
$element = self::adjustImageDimensions($element, $column_count); $element = self::adjustImageDimensions($element, $column_count);
$image_template = ' $image_template = '
<img style="max-width:' . $element['width'] . 'px;" src="' . $element['src'] . '" <img style="max-width:' . $element['width'] . 'px;" src="' . $element['src'] . '"
width="' . $element['width'] . '" height="' . $element['height'] . '" alt="' . $element['alt'] . '"/> width="' . $element['width'] . '" alt="' . $element['alt'] . '"/>
'; ';
if(!empty($element['link'])) { if(!empty($element['link'])) {
$image_template = '<a href="' . $element['link'] . '">' . $image_template . '</a>'; $image_template = '<a href="' . $element['link'] . '">' . $image_template . '</a>';

View File

@ -10,7 +10,7 @@ class Text {
$html = self::convertParagraphsToTables($html); $html = self::convertParagraphsToTables($html);
$html = self::styleLists($html); $html = self::styleLists($html);
$html = self::styleHeadings($html); $html = self::styleHeadings($html);
$html = self::addLineBreakAfterTags($html); $html = self::removeLastLineBreak($html);
$template = ' $template = '
<tr> <tr>
<td class="mailpoet_text mailpoet_padded_bottom mailpoet_padded_side" valign="top" style="word-break:break-word;word-wrap:break-word;"> <td class="mailpoet_text mailpoet_padded_bottom mailpoet_padded_side" valign="top" style="word-break:break-word;word-wrap:break-word;">
@ -56,6 +56,14 @@ class Text {
</tr> </tr>
</tbody>' </tbody>'
); );
$blockquote->parent->insertChild(
array(
'tag_name' => 'br',
'self_close' => true,
'attributes' => array()
),
$blockquote->index() + 1
);
} }
return $DOM->__toString(); return $DOM->__toString();
} }
@ -72,16 +80,23 @@ class Text {
continue; continue;
} }
$style = $paragraph->style; $style = $paragraph->style;
if(!preg_match('/text-align/i', $style)) {
$style = 'text-align: left;' . $style;
}
$contents = $paragraph->html(); $contents = $paragraph->html();
$paragraph->setTag('table'); $paragraph->setTag('table');
$paragraph->style = 'border-spacing:0;mso-table-lspace:0;mso-table-rspace:0;'; $paragraph->style = 'border-spacing:0;mso-table-lspace:0;mso-table-rspace:0;';
$paragraph->width = '100%'; $paragraph->width = '100%';
$paragraph->cellpadding = 0; $paragraph->cellpadding = 0;
$next_element = $paragraph->getNextSibling();
// unless this is the last element in column, add double line breaks
$line_breaks = ($next_element && !empty($next_element->getInnerText())) ? '<br /><br />' : '';
// if this element is followed by a list, add single line break
$line_breaks = ($next_element && preg_match('/<li>/i', $next_element->getInnerText())) ? '<br />' : $line_breaks;
$paragraph->html(' $paragraph->html('
<tr> <tr>
<td class="mailpoet_paragraph" style="line-height:' . StylesHelper::$line_height . ';word-break:break-word;word-wrap:break-word;' . $style . '"> <td class="mailpoet_paragraph" style="word-break:break-word;word-wrap:break-word;' . $style . '">
' . $contents . ' ' . $contents . $line_breaks . '
<br />
</td> </td>
</tr>' </tr>'
); );
@ -96,11 +111,13 @@ class Text {
if(!$lists->count()) return $html; if(!$lists->count()) return $html;
foreach($lists as $list) { foreach($lists as $list) {
if($list->tag === 'li') { if($list->tag === 'li') {
$list->setInnertext($list->text());
$list->class = 'mailpoet_paragraph'; $list->class = 'mailpoet_paragraph';
} else { } else {
$list->class = 'mailpoet_paragraph'; $list->class = 'mailpoet_paragraph';
$list->style .= 'line-height:' . StylesHelper::$line_height . ';padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;'; $list->style .= 'padding-top:0;padding-bottom:0;margin-top:10px;';
} }
$list->style .= 'margin-bottom:10px;';
} }
return $DOM->__toString(); return $DOM->__toString();
} }
@ -111,27 +128,12 @@ class Text {
$headings = $DOM->query('h1, h2, h3, h4'); $headings = $DOM->query('h1, h2, h3, h4');
if(!$headings->count()) return $html; if(!$headings->count()) return $html;
foreach($headings as $heading) { foreach($headings as $heading) {
$heading->style .= 'line-height:' . StylesHelper::$line_height . ';margin:0;font-style:normal;font-weight:normal;'; $heading->style .= 'padding:0;font-style:normal;font-weight:normal;';
} }
return $DOM->__toString(); return $DOM->__toString();
} }
static function addLineBreakAfterTags($html) { static function removeLastLineBreak($html) {
$DOM_parser = new \pQuery(); return preg_replace('/(^)?(<br.*?\/?>)+$/i', '', $html);
$DOM = $DOM_parser->parseStr($html);
$tags = $DOM->query('ul, ol, h1, h2, h3, h4, table.mailpoet_blockquote');
if(!$tags->count()) return $html;
foreach($tags as $tag) {
$tag->parent->insertChild(
array(
'tag_name' => 'br',
'self_close' => true,
'attributes' => array()
),
$tag->index() + 1
);
}
// remove last line break
return preg_replace('/(^)?(<br.*?\/?>)+$/i', '', $DOM->__toString());
} }
} }

View File

@ -63,7 +63,7 @@ class Renderer {
foreach($styles as $selector => $style) { foreach($styles as $selector => $style) {
switch($selector) { switch($selector) {
case 'text': case 'text':
$selector = 'td.mailpoet_paragraph, td.mailpoet_blockquote'; $selector = 'td.mailpoet_paragraph, td.mailpoet_blockquote, li.mailpoet_paragraph';
break; break;
case 'body': case 'body':
$selector = 'body, .mailpoet-wrapper'; $selector = 'body, .mailpoet-wrapper';
@ -75,13 +75,6 @@ class Renderer {
$selector = '.mailpoet_content-wrapper'; $selector = '.mailpoet_content-wrapper';
break; break;
} }
if(isset($style['fontFamily'])) {
$css .= StylesHelper::setFontFamily(
$style['fontFamily'],
$selector
);
unset($style['fontFamily']);
}
$css .= StylesHelper::setStyle($style, $selector); $css .= StylesHelper::setStyle($style, $selector);
} }
return $css; return $css;

View File

@ -27,7 +27,8 @@ class StylesHelper {
'Trebuchet MS' => "'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif", 'Trebuchet MS' => "'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif",
'Verdana' => 'Verdana, Geneva, sans-serif' 'Verdana' => 'Verdana, Geneva, sans-serif'
); );
static $line_height = 1.61803398875; static $line_height_multiplier = 1.6;
static $heading_margin_multiplier = 0.3;
static $padding_width = 20; static $padding_width = 20;
static function getBlockStyles($element, $ignore_specific_styles = false) { static function getBlockStyles($element, $ignore_specific_styles = false) {
@ -52,19 +53,12 @@ class StylesHelper {
$attribute; $attribute;
} }
static function setFontFamily($font_family, $selector) {
$font_family = (isset(self::$font[$font_family])) ?
self::$font[$font_family] :
self::$font['Arial'];
$css = $selector . '{' . PHP_EOL;
$css .= 'font-family:' . $font_family . ';' . PHP_EOL;
$css .= '}' . PHP_EOL;
return $css;
}
static function setStyle($style, $selector) { static function setStyle($style, $selector) {
$css = $selector . '{' . PHP_EOL; $css = $selector . '{' . PHP_EOL;
$style = self::applyHeadingMargin($style, $selector);
$style = self::applyLineHeight($style, $selector);
foreach($style as $attribute => $individual_style) { foreach($style as $attribute => $individual_style) {
$individual_style = self::applyFontFamily($attribute, $individual_style);
$css .= self::translateCSSAttribute($attribute) . ':' . $individual_style . ';' . PHP_EOL; $css .= self::translateCSSAttribute($attribute) . ':' . $individual_style . ';' . PHP_EOL;
} }
$css .= '}' . PHP_EOL; $css .= '}' . PHP_EOL;
@ -80,10 +74,31 @@ class StylesHelper {
$text_alignment = isset($block['styles']['block']['textAlign']) ? $text_alignment = isset($block['styles']['block']['textAlign']) ?
strtolower($block['styles']['block']['textAlign']) : strtolower($block['styles']['block']['textAlign']) :
false; false;
if(!$text_alignment || !in_array($text_alignment, $alignments)) { if(in_array($text_alignment, $alignments)) {
return $block; return $block;
} }
$block['styles']['block']['textAlign'] = 'left'; $block['styles']['block']['textAlign'] = 'left';
return $block; return $block;
} }
static function applyFontFamily($attribute, $style) {
if($attribute !== 'fontFamily') return $style;
return (isset(self::$font[$style])) ?
self::$font[$style] :
self::$font['Arial'];
}
static function applyHeadingMargin($style, $selector) {
if (!preg_match('/h[1-4]/i', $selector)) return $style;
$font_size = (int) $style['fontSize'];
$style['margin'] = sprintf('0 0 %spx 0', self::$heading_margin_multiplier * $font_size);
return $style;
}
static function applyLineHeight($style, $selector) {
if (!preg_match('/mailpoet_paragraph|h[1-4]/i', $selector)) return $style;
$font_size = (int) $style['fontSize'];
$style['lineHeight'] = sprintf('%spx', self::$line_height_multiplier * $font_size);
return $style;
}
} }

View File

@ -54,8 +54,8 @@
} }
.mailpoet_button { .mailpoet_button {
width: 100% !important; width: 100% !important;
max-width: 100% !important;
padding: 5px 0 !important; padding: 5px 0 !important;
box-sizing:border-box !important;
} }
div, .mailpoet_cols-two, .mailpoet_cols-three { div, .mailpoet_cols-two, .mailpoet_cols-three {
max-width: 100% !important; max-width: 100% !important;

View File

@ -43,7 +43,8 @@ class Scheduler {
$option_field = NewsletterOptionField::where('name', 'schedule') $option_field = NewsletterOptionField::where('name', 'schedule')
->findOne() ->findOne()
->asArray(); ->asArray();
$relation = NewsletterOption::where('option_field_id', $option_field['id']) $relation = NewsletterOption::where('newsletter_id', $newsletter_id)
->where('option_field_id', $option_field['id'])
->findOne(); ->findOne();
if(!$relation) { if(!$relation) {
$relation = NewsletterOption::create(); $relation = NewsletterOption::create();

View File

@ -157,7 +157,7 @@ class Newsletters {
if(empty($data['subscriber'])) { if(empty($data['subscriber'])) {
return array( return array(
'result' => false, 'result' => false,
'errors' => array(__('Please specify receiver information')) 'errors' => array(__('Please specify receiver information.'))
); );
} }
@ -165,20 +165,17 @@ class Newsletters {
$renderer = new Renderer($newsletter); $renderer = new Renderer($newsletter);
$rendered_newsletter = $renderer->render(); $rendered_newsletter = $renderer->render();
$divider = '***MailPoet***';
$data_for_shortcodes =
array_merge(array($newsletter['subject']), $rendered_newsletter);
$body = implode($divider, $data_for_shortcodes);
$shortcodes = new \MailPoet\Newsletter\Shortcodes\Shortcodes( $shortcodes = new \MailPoet\Newsletter\Shortcodes\Shortcodes(
$rendered_newsletter['html'],
$newsletter $newsletter
); );
$processed_newsletter['html'] = $shortcodes->replace(); list($newsletter['subject'],
$shortcodes = new \MailPoet\Newsletter\Shortcodes\Shortcodes( $newsletter['body']['html'],
$rendered_newsletter['text'], $newsletter['body']['text']
$newsletter ) = explode($divider, $shortcodes->replace($body));
);
$processed_newsletter['text'] = $shortcodes->replace();
$newsletter['body'] = array(
'html' => $processed_newsletter['html'],
'text' => $processed_newsletter['text'],
);
try { try {
$mailer = new \MailPoet\Mailer\Mailer( $mailer = new \MailPoet\Mailer\Mailer(

View File

@ -18,23 +18,6 @@ class Hosts {
'EU (Ireland)' => 'eu-west-1' 'EU (Ireland)' => 'eu-west-1'
) )
), ),
'ElasticEmail' => array(
'name' => 'ElasticEmail',
'emails' => 100,
'interval' => 5,
'fields' => array(
'api_key'
)
),
'MailGun' => array(
'name' => 'MailGun',
'emails' => 100,
'interval' => 5,
'fields' => array(
'domain',
'api_key'
)
),
'SendGrid' => array( 'SendGrid' => array(
'name' => 'SendGrid', 'name' => 'SendGrid',
'emails' => 100, 'emails' => 100,

View File

@ -116,6 +116,7 @@ class CSS {
public function parseCSS($text) public function parseCSS($text)
{ {
$css = new csstidy(); $css = new csstidy();
$css->settings['compress_colors'] = false;
$css->parse($text); $css->parse($text);
$rules = array(); $rules = array();

View File

@ -4,7 +4,7 @@ if(!defined('ABSPATH')) exit;
use \MailPoet\Config\Initializer; use \MailPoet\Config\Initializer;
/* /*
* Plugin Name: MailPoet * Plugin Name: MailPoet
* Version: 0.0.22 * Version: 0.0.23
* Plugin URI: http://www.mailpoet.com * Plugin URI: http://www.mailpoet.com
* Description: MailPoet Newsletters. * Description: MailPoet Newsletters.
* Author: MailPoet * Author: MailPoet
@ -22,7 +22,7 @@ use \MailPoet\Config\Initializer;
require 'vendor/autoload.php'; require 'vendor/autoload.php';
define('MAILPOET_VERSION', '0.0.22'); define('MAILPOET_VERSION', '0.0.23');
$initializer = new Initializer(array( $initializer = new Initializer(array(
'file' => __FILE__, 'file' => __FILE__,

View File

@ -207,11 +207,10 @@ class NewsletterRendererTest extends MailPoetTest {
) )
)->true(); )->true();
expect($DOM('tr > td.mailpoet_text > ul.mailpoet_paragraph', 0)->attr('style')) expect($DOM('tr > td.mailpoet_text > ul.mailpoet_paragraph', 0)->attr('style'))
->contains('padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;'); ->contains('padding-top:0;padding-bottom:0;margin-top:10px;margin-bottom:10px;');
// headings should be styled // headings should be styled
expect($DOM('tr > td.mailpoet_text > h1', 0)->attr('style')) expect($DOM('tr > td.mailpoet_text > h1', 0)->attr('style'))
->contains('margin:0;font-style:normal;font-weight:normal;'); ->contains('padding:0;font-style:normal;font-weight:normal;');
} }
function testItRendersDivider() { function testItRendersDivider() {

View File

@ -1,8 +1,8 @@
<% set intervals = [1, 2, 5, 10, 15, 30, 60] %> <% set intervals = [1, 2, 5, 10, 15] %>
<% set default_frequency = { <% set default_frequency = {
'website': { 'website': {
'emails': 25, 'emails': 25,
'interval': 15 'interval': 5
}, },
'smtp': { 'smtp': {
'emails': 100, 'emails': 100,
@ -66,15 +66,21 @@
<img <img
src="<%= assets_url %>/img/mailpoet_logo.png" src="<%= assets_url %>/img/mailpoet_logo.png"
alt="MailPoet" alt="MailPoet"
width="222" width="137"
height="54" height="54"
/> />
</h3> </h3>
<p class="mailpoet_description"> <p class="mailpoet_description">
<%= __('Send to 500 subscribers per month for <strong>free</strong>. Enjoy great deliverability, and speed.') %> <strong><%= __('Currently in closed beta.') %></strong>
<br /><br /> <br />
<a href="#todo"><%= __('See pricing for more.') %></a> <%= __('[link]Sign up to our newsletter[/link] to get our latest news on this, and more.')
| replace({
'[link]': '<a href="http://www.mailpoet.com/subscribe/" target="_blank">',
'[/link]': '</a>'
})
| raw
%>
</p> </p>
<div class="mailpoet_status"> <div class="mailpoet_status">
@ -91,10 +97,12 @@
data-group="website" data-group="website"
<% if(settings.mta_group == 'website') %>class="mailpoet_active"<% endif %> <% if(settings.mta_group == 'website') %>class="mailpoet_active"<% endif %>
> >
<h3><%= __('Your own website') %></h3> <h3><%= __('Your web host/server') %></h3>
<p class="mailpoet_description"> <p class="mailpoet_description">
<%= __('The simplest solution for small lists. Your web host sets a daily email limit.') %> <strong><%= __('Free, but not recommended.') %></strong>
<br />
<%= __('Web hosts generally have a bad reputation as senders. Your newsletter might be considered spam.') %>
</p> </p>
<div class="mailpoet_status"> <div class="mailpoet_status">
@ -114,6 +122,8 @@
<h3><%= __('Third party') %></h3> <h3><%= __('Third party') %></h3>
<p class="mailpoet_description"> <p class="mailpoet_description">
<strong><%= __('Currently the best solution.') %></strong>
<br />
<%= __('Send with an alternate email provider. Usually not free.') %> <%= __('Send with an alternate email provider. Usually not free.') %>
</p> </p>
@ -136,29 +146,6 @@
data-group="mailpoet" data-group="mailpoet"
style="display:none;" style="display:none;"
> >
<h3><%= __('Open a free account with MailPoet, and get:') %></h3>
<ol>
<li>
<%=
__('Send up to 4000 emails with good deliverability for free. %1$sNeed more?%2$s')
| format('<a href="#todo">', '</a>')
| raw
%>
</li>
<li>
<%= __("Test your campaign's spam score") %>
</li>
<li>
<%= __('Send on time, without delay, without setting up your own "cron"') %>
</li>
</ol>
<a class="button-secondary">
<%=- __('Create a free account to get a key') -%>
</a>
<hr />
<h3><%= __('Already have a key?') %></h3> <h3><%= __('Already have a key?') %></h3>
<table class="form-table"> <table class="form-table">
<tbody> <tbody>
@ -243,10 +230,11 @@
type="number" type="number"
min="1" min="1"
max="1000" max="1000"
value="<%= <% if(settings.mta_group == 'website') %>
settings.mta.frequency.emails value="<%= settings.mta.frequency.emails %>"
| default(default_frequency.website.emails) <% else %>
%>" value="<%= default_frequency.website.emails %>"
<% endif %>
/> />
<%= __('emails') %> <%= __('emails') %>
<select id="website_frequency_interval"> <select id="website_frequency_interval">
@ -264,7 +252,7 @@
<% endif %> <% endif %>
> >
<%= sending_frequency(interval) %> <%= sending_frequency(interval) %>
<% if(interval == 15) %> <% if(interval == default_frequency.website.interval) %>
(<%= __('recommended') %>) (<%= __('recommended') %>)
<% endif %> <% endif %>
</option> </option>
@ -274,7 +262,7 @@
</p> </p>
<br /> <br />
<p> <p>
<%= __('<strong>Warning!</strong> Sending more than the recommended amount of emails might break the terms of your host or provider.') %> <%= __('<strong>Warning!</strong> Sending more than the recommended amount of emails might break the terms of your host or provider.') %>'
<br /> <br />
<%= __('Double check with them what maximum number of emails you can send daily.') %> <%= __('Double check with them what maximum number of emails you can send daily.') %>
</p> </p>
@ -335,10 +323,11 @@
type="number" type="number"
min="1" min="1"
max="1000" max="1000"
value="<%= <% if(settings.mta_group == 'smtp') %>
settings.mta.frequency.emails value="<%= settings.mta.frequency.emails %>"
| default(default_frequency.smtp.emails) <% else %>
%>" value="<%= default_frequency.smtp.emails %>"
<% endif %>
/> />
<%= __('emails') %> <%= __('emails') %>
<select id="smtp_frequency_interval"> <select id="smtp_frequency_interval">
@ -356,7 +345,7 @@
<% endif %> <% endif %>
> >
<%= sending_frequency(interval) %> <%= sending_frequency(interval) %>
<% if(interval == 15) %> <% if(interval == default_frequency.smtp.interval) %>
(<%= __('recommended') %>) (<%= __('recommended') %>)
<% endif %> <% endif %>
</option> </option>
@ -364,12 +353,6 @@
</select> </select>
<span id="mailpoet_smtp_daily_emails"></span> <span id="mailpoet_smtp_daily_emails"></span>
</p> </p>
<br />
<p>
<%= __('<strong>Warning!</strong> Sending more than the recommended amount of emails might break the terms of your host or provider.') %>
<br />
<%= __('Double check with them what maximum number of emails you can send daily.') %>
</p>
</td> </td>
</tr> </tr>
<!-- smtp: host --> <!-- smtp: host -->
@ -617,13 +600,29 @@
<table class="form-table"> <table class="form-table">
<tbody> <tbody>
<!-- SPF -->
<tr id="mailpoet_mta_spf">
<th scope="row">
<label>
<%= __('SPF signature (recommended)') %>
<p class="description">
<%= __('Improves your spam score by allowing the recipient to verify that your website is allowed to send emails from your domain.') %>
</p>
</label>
</th>
<td>
<p>
<%= __('SPF is set in your DNS. Check the support documents of your host to set it up.') %>
</p>
</td>
</tr>
<!-- dkim --> <!-- dkim -->
<tr id="mailpoet_mta_dkim"> <tr id="mailpoet_mta_dkim" style="display:none;">
<th scope="row"> <th scope="row">
<label for="settings[dkim_enabled]"> <label for="settings[dkim_enabled]">
<%= __('DKIM signature') %> <%= __('DKIM signature (recommended)') %>
<p class="description"> <p class="description">
<%= __('Improve your spam score. Mailpoet can sign all your emails with DKIM.') %> <%= __('Improve your spam score. MailPoet can sign all your emails with DKIM.') %>
<a <a
href="#todo/guide-to-dkim-in-wysija/" href="#todo/guide-to-dkim-in-wysija/"
target="_blank" target="_blank"
@ -693,6 +692,7 @@
<input <input
id="mailpoet_mta_test_email" id="mailpoet_mta_test_email"
type="text" type="text"
class="regular-text"
value="<%= current_user.user_email %>" value="<%= current_user.user_email %>"
/> />
<a <a
@ -745,6 +745,16 @@
: $('#mta_group').val() : $('#mta_group').val()
); );
// check that we have a from address
if(settings.sender.address.length === 0) {
// validation
return MailPoet.Notice.error(
'The email could not be sent. Make sure the option "Email notifications" has a FROM email address in the Basics tab.',
{ scroll: true, static: true }
);
}
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({ MailPoet.Ajax.post({
endpoint: 'mailer', endpoint: 'mailer',
action: 'send', action: 'send',
@ -763,16 +773,35 @@
} }
} }
}).done(function(response) { }).done(function(response) {
MailPoet.Modal.loading(false);
if(response.result === true) { if(response.result === true) {
MailPoet.Notice.success("The email has been sent! Check your inbox."); MailPoet.Notice.success(
"<%= __('The email has been sent! Check your inbox.') %>",
{ scroll: true }
);
} else { } else {
if (response.errors) { if (response.errors) {
MailPoet.Notice.error("The email could not be sent. " + response.errors); MailPoet.Notice.error(
"<%= __('The email could not be sent.') %> " + response.errors,
{ scroll: true }
);
} }
else { else {
MailPoet.Notice.error("The email could not be sent. Please check your settings."); if(mailer.method === 'PHPMail') {
MailPoet.Notice.error(
"<%= __('The email could not be sent. Contact your host to help you fix any sending issues with your server.') %>",
{ scroll: true, static: true }
);
} else {
MailPoet.Notice.error(
"<%= __('The email could not be sent. Please check your settings.') %>",
{ scroll: true }
);
} }
} }
}
}).error(function(response) {
MailPoet.Modal.loading(false);
}); });
}); });
@ -965,7 +994,16 @@
interval: $('#'+method+'_frequency_interval').val() interval: $('#'+method+'_frequency_interval').val()
}; };
options.daily_emails = ~~((1440 / options.interval) * options.emails); var MINUTES_PER_DAY = 1440;
var SECONDS_PER_DAY = 86400;
options.daily_emails = ~~(
(MINUTES_PER_DAY / options.interval) * options.emails
);
options.emails_per_second = (~~(
((options.daily_emails) / 86400) * 10)
) / 10;
$('#mailpoet_'+method+'_daily_emails').html( $('#mailpoet_'+method+'_daily_emails').html(
sending_frequency_template(options) sending_frequency_template(options)

View File

@ -12,3 +12,14 @@
| format('{{ daily_emails }}') | format('{{ daily_emails }}')
| raw | raw
%> %>
{{#ifCond emails_per_second ">" "1"}}
<br /><br />
<span style="color: #d54e21;">
<%=
__("That's %1$s emails per second. <strong>We highly recommend to send 1 email per second at most.</strong> This is the time MailPoet needs to process and send a single email from most hosts. <strong>Alternatively, send with MailPoet which can be 50 times faster.</strong>")
| format('{{ emails_per_second }}')
| raw
%>
</span>
{{/ifCond}}