Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2f25dc6a20 | ||
|
fc38ee2f08 | ||
|
33bebc6629 | ||
|
14a8e02f99 | ||
|
0bf6c87ec7 | ||
|
422fba2835 | ||
|
f36dbb78e6 | ||
|
3213dd0d08 | ||
|
3f2199fd63 | ||
|
a4477a9bd6 | ||
|
52790d7bd6 | ||
|
0b9812210f | ||
|
756dbb4641 | ||
|
b38742ddc0 | ||
|
49e38549ec | ||
|
afcb0a0d7f | ||
|
d18f0e50b5 | ||
|
6868a07ead | ||
|
cca76d0d97 | ||
|
70fa77d333 | ||
|
412201d965 | ||
|
045a92c7d6 | ||
|
2ba2e3eca5 | ||
|
90c294f60e | ||
|
57b953dd14 | ||
|
0f81a8db60 | ||
|
2d6971f8df | ||
|
0abe8b5371 | ||
|
5bad682879 |
@@ -16,7 +16,7 @@ define([
|
||||
defaults: function() {
|
||||
return this._getDefaults({
|
||||
type: 'footer',
|
||||
text: '<a href="[subscription:unsubscribe_url]">Unsubscribe</a> | <a href="[subscription:manage_url]">Manage subscription</a><br /><b>Add your postal address here!</b>',
|
||||
text: '<a href="[link:subscription_unsubscribe_url]">Unsubscribe</a> | <a href="[link:subscription_manage_url]">Manage subscription</a><br /><b>Add your postal address here!</b>',
|
||||
styles: {
|
||||
block: {
|
||||
backgroundColor: 'transparent',
|
||||
|
@@ -16,7 +16,7 @@ define([
|
||||
defaults: function() {
|
||||
return this._getDefaults({
|
||||
type: 'header',
|
||||
text: 'Display problems? <a href="[newsletter:view_in_browser_url]">View it in your browser</a>',
|
||||
text: 'Display problems? <a href="[link:newsletter_view_in_browser_url]">View it in your browser</a>',
|
||||
styles: {
|
||||
block: {
|
||||
backgroundColor: 'transparent',
|
||||
|
@@ -284,7 +284,7 @@ define([
|
||||
}
|
||||
|
||||
if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') &&
|
||||
JSON.stringify(jsonObject).indexOf("[subscription:unsubscribe_url]") < 0) {
|
||||
JSON.stringify(jsonObject).indexOf("[link:subscription_unsubscribe_url]") < 0) {
|
||||
this.showValidationError(MailPoet.I18n.t('unsubscribeLinkMissing'));
|
||||
return;
|
||||
}
|
||||
|
@@ -245,14 +245,20 @@ define([
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
action: 'render',
|
||||
action: 'showPreview',
|
||||
data: json,
|
||||
}).done(function(response){
|
||||
MailPoet.Modal.loading(false);
|
||||
window.open('data:text/html;charset=utf-8,' + encodeURIComponent(response.rendered_body), '_blank');
|
||||
|
||||
if (response.result === true) {
|
||||
window.open(response.data.url, '_blank')
|
||||
}
|
||||
MailPoet.Notice.error(response.errors);
|
||||
}).fail(function(error) {
|
||||
MailPoet.Modal.loading(false);
|
||||
alert('Something went wrong, check console');
|
||||
MailPoet.Notice.error(
|
||||
MailPoet.I18n.t('newsletterPreviewFailed')
|
||||
);
|
||||
});
|
||||
},
|
||||
sendPreview: function() {
|
||||
|
@@ -39,6 +39,9 @@ class Env {
|
||||
self::$assets_url = plugins_url('/assets', $file);
|
||||
$wp_upload_dir = wp_upload_dir();
|
||||
self::$temp_path = $wp_upload_dir['basedir'].'/'.self::$plugin_name;
|
||||
if (!is_dir(self::$temp_path)) {
|
||||
mkdir(self::$temp_path);
|
||||
}
|
||||
self::$temp_url = $wp_upload_dir['baseurl'].'/'.self::$plugin_name;
|
||||
self::$languages_path = self::$path . '/lang';
|
||||
self::$lib_path = self::$path . '/lib';
|
||||
|
@@ -142,7 +142,7 @@ class BlankTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "footer",
|
||||
"text" => "<a href=\"[subscription:unsubscribe_url]\">Unsubscribe</a> | <a href=\"[subscription:manage_url]\">Manage subscription</a><br /><b>Add your postal address here!</b>",
|
||||
"text" => "<a href=\"[link:subscription_unsubscribe_url]\">Unsubscribe</a> | <a href=\"[link:subscription_manage_url]\">Manage subscription</a><br /><b>Add your postal address here!</b>",
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "transparent"
|
||||
|
@@ -46,7 +46,7 @@ class FranksRoastHouseTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "header",
|
||||
"text" => __("Display problems? <a href=\"[newsletter:view_in_browser_url]\">View it in your browser</a>"),
|
||||
"text" => __("Display problems? <a href=\"[link:newsletter_view_in_browser_url]\">View it in your browser</a>"),
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "#ccc6c6"
|
||||
@@ -280,7 +280,7 @@ class FranksRoastHouseTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "footer",
|
||||
"text" => __("<p><a href=\"[subscription:unsubscribe_url]\">Unsubscribe</a> | <a href=\"[subscription:manage_url]\">Manage subscription</a><br />12345 MailPoet Drive, EmailVille, 76543</p>"),
|
||||
"text" => __("<p><a href=\"[link:subscription_unsubscribe_url]\">Unsubscribe</a> | <a href=\"[link:subscription_manage_url]\">Manage subscription</a><br />12345 MailPoet Drive, EmailVille, 76543</p>"),
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "#a9a7a7"
|
||||
|
@@ -242,7 +242,7 @@ class PostNotificationsBlankTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "footer",
|
||||
"text" => __("<a href=\"[subscription:unsubscribe_url]\">Unsubscribe</a> | <a href=\"[subscription:manage_url]\">Manage subscription</a><br /><b>Add your postal address here!</b>"),
|
||||
"text" => __("<a href=\"[link:subscription_unsubscribe_url]\">Unsubscribe</a> | <a href=\"[link:subscription_manage_url]\">Manage subscription</a><br /><b>Add your postal address here!</b>"),
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "transparent"
|
||||
|
@@ -46,7 +46,7 @@ class WelcomeTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "header",
|
||||
"text" => __("Display problems? <a href=\"[newsletter:view_in_browser_url]\">View it in your browser</a>"),
|
||||
"text" => __("Display problems? <a href=\"[link:newsletter_view_in_browser_url]\">View it in your browser</a>"),
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "transparent"
|
||||
@@ -224,7 +224,7 @@ class WelcomeTemplate {
|
||||
"blocks" => array(
|
||||
array(
|
||||
"type" => "footer",
|
||||
"text" => __("<a href=\"[subscription:unsubscribe_url]\">Unsubscribe</a> | <a href=\"[subscription:manage_url]\">Manage subscription</a><br /><b>Add your postal address here!</b>"),
|
||||
"text" => __("<a href=\"[link:subscription_unsubscribe_url]\">Unsubscribe</a> | <a href=\"[link:subscription_manage_url]\">Manage subscription</a><br /><b>Add your postal address here!</b>"),
|
||||
"styles" => array(
|
||||
"block" => array(
|
||||
"backgroundColor" => "transparent"
|
||||
|
@@ -2,9 +2,10 @@
|
||||
namespace MailPoet\Config;
|
||||
|
||||
use MailPoet\Cron\Daemon;
|
||||
use MailPoet\Newsletter\Viewer\ViewInBrowser;
|
||||
use MailPoet\Statistics\Track\Clicks;
|
||||
use MailPoet\Statistics\Track\Opens;
|
||||
use MailPoet\Subscription;
|
||||
use MailPoet\Statistics\Track\Clicks;
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
@@ -25,7 +26,7 @@ class PublicAPI {
|
||||
Helpers::underscoreToCamelCase($_GET['action']) :
|
||||
false;
|
||||
$this->data = isset($_GET['data']) ?
|
||||
$_GET['data'] :
|
||||
unserialize(base64_decode($_GET['data'])) :
|
||||
false;
|
||||
}
|
||||
|
||||
@@ -35,33 +36,29 @@ class PublicAPI {
|
||||
}
|
||||
|
||||
function queue() {
|
||||
try {
|
||||
$queue = new Daemon($this->_decodeData());
|
||||
$this->_checkAndCallMethod($queue, $this->action);
|
||||
} catch(\Exception $e) {
|
||||
}
|
||||
$queue = new Daemon($this->data);
|
||||
$this->_checkAndCallMethod($queue, $this->action);
|
||||
}
|
||||
|
||||
function subscription() {
|
||||
try {
|
||||
$subscription = new Subscription\Pages($this->action, $this->_decodeData());
|
||||
$this->_checkAndCallMethod($subscription, $this->action);
|
||||
} catch(\Exception $e) {
|
||||
}
|
||||
$subscription = new Subscription\Pages($this->action, $this->data);
|
||||
$this->_checkAndCallMethod($subscription, $this->action);
|
||||
}
|
||||
|
||||
function track() {
|
||||
try {
|
||||
if($this->action === 'click') {
|
||||
$track_class = new Clicks($this->data);
|
||||
}
|
||||
if($this->action === 'open') {
|
||||
$track_class = new Opens($this->data);
|
||||
}
|
||||
if(!isset($track_class)) return;
|
||||
$track_class->track();
|
||||
} catch(\Exception $e) {
|
||||
if($this->action === 'click') {
|
||||
$track_class = new Clicks($this->data);
|
||||
}
|
||||
if($this->action === 'open') {
|
||||
$track_class = new Opens($this->data);
|
||||
}
|
||||
if(!isset($track_class)) return;
|
||||
$track_class->track();
|
||||
}
|
||||
|
||||
function viewInBrowser() {
|
||||
$viewer = new ViewInBrowser($this->data);
|
||||
$viewer->view();
|
||||
}
|
||||
|
||||
private function _checkAndCallMethod($class, $method, $terminate_request = false) {
|
||||
@@ -77,12 +74,4 @@ class PublicAPI {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function _decodeData() {
|
||||
if($this->data !== false) {
|
||||
return unserialize(base64_decode($this->data));
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,13 +7,13 @@ use MailPoet\Util\Security;
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class CronHelper {
|
||||
const daemon_execution_limit = 20;
|
||||
const daemon_execution_timeout = 35;
|
||||
const daemon_request_timeout = 2;
|
||||
const DAEMON_EXECUTION_LIMIT = 20;
|
||||
const DAEMON_EXECUTION_TIMEOUT = 35;
|
||||
const DAEMON_REQUEST_TIMEOUT = 2;
|
||||
|
||||
static function createDaemon($token) {
|
||||
$daemon = array(
|
||||
'status' => 'starting',
|
||||
'status' => Daemon::STATUS_STARTING,
|
||||
'counter' => 0,
|
||||
'token' => $token
|
||||
);
|
||||
@@ -37,7 +37,7 @@ class CronHelper {
|
||||
return Security::generateRandomString();
|
||||
}
|
||||
|
||||
static function accessDaemon($token, $timeout = self::daemon_request_timeout) {
|
||||
static function accessDaemon($token, $timeout = self::DAEMON_REQUEST_TIMEOUT) {
|
||||
$data = serialize(array('token' => $token));
|
||||
$url = '/?mailpoet&endpoint=queue&action=run&data=' .
|
||||
base64_encode($data);
|
||||
@@ -71,7 +71,7 @@ class CronHelper {
|
||||
|
||||
static function checkExecutionTimer($timer) {
|
||||
$elapsed_time = microtime(true) - $timer;
|
||||
if($elapsed_time >= self::daemon_execution_limit) {
|
||||
if($elapsed_time >= self::DAEMON_EXECUTION_LIMIT) {
|
||||
throw new \Exception(__('Maximum execution time reached.'));
|
||||
}
|
||||
}
|
||||
|
@@ -12,12 +12,15 @@ class Daemon {
|
||||
public $daemon;
|
||||
public $data;
|
||||
public $refreshed_token;
|
||||
const daemon_request_timeout = 5;
|
||||
const STATUS_STOPPED = 'stopped';
|
||||
const STATUS_STOPPING = 'stopping';
|
||||
const STATUS_STARTED = 'started';
|
||||
const STATUS_STARTING = 'starting';
|
||||
const REQUEST_TIMEOUT = 5;
|
||||
private $timer;
|
||||
|
||||
function __construct($data) {
|
||||
if(empty($data)) $this->abortWithError(__('Invalid or missing cron data.'));
|
||||
set_time_limit(0);
|
||||
ignore_user_abort();
|
||||
$this->daemon = CronHelper::getDaemon();
|
||||
$this->token = CronHelper::createToken();
|
||||
@@ -27,6 +30,7 @@ class Daemon {
|
||||
|
||||
function run() {
|
||||
$daemon = $this->daemon;
|
||||
set_time_limit(0);
|
||||
if(!$daemon) {
|
||||
$this->abortWithError(__('Daemon does not exist.'));
|
||||
}
|
||||
@@ -42,10 +46,11 @@ class Daemon {
|
||||
$queue = new SendingQueue();
|
||||
$queue->process($this->timer);
|
||||
} catch(\Exception $e) {
|
||||
// continue processing, no need to catch errors
|
||||
}
|
||||
$elapsed_time = microtime(true) - $this->timer;
|
||||
if($elapsed_time < CronHelper::daemon_execution_limit) {
|
||||
sleep(CronHelper::daemon_execution_limit - $elapsed_time);
|
||||
if($elapsed_time < CronHelper::DAEMON_EXECUTION_LIMIT) {
|
||||
sleep(CronHelper::DAEMON_EXECUTION_LIMIT - $elapsed_time);
|
||||
}
|
||||
// after each execution, re-read daemon data in case it was deleted or
|
||||
// its status has changed
|
||||
@@ -55,8 +60,8 @@ class Daemon {
|
||||
}
|
||||
$daemon['counter']++;
|
||||
$this->abortIfStopped($daemon);
|
||||
if($daemon['status'] === 'starting') {
|
||||
$daemon['status'] = 'started';
|
||||
if($daemon['status'] === self::STATUS_STARTING) {
|
||||
$daemon['status'] = self::STATUS_STARTED;
|
||||
}
|
||||
$daemon['token'] = $this->token;
|
||||
CronHelper::saveDaemon($daemon);
|
||||
@@ -64,9 +69,9 @@ class Daemon {
|
||||
}
|
||||
|
||||
function abortIfStopped($daemon) {
|
||||
if($daemon['status'] === 'stopped') exit;
|
||||
if($daemon['status'] === 'stopping') {
|
||||
$daemon['status'] = 'stopped';
|
||||
if($daemon['status'] === self::STATUS_STOPPED) exit;
|
||||
if($daemon['status'] === self::STATUS_STOPPING) {
|
||||
$daemon['status'] = self::STATUS_STOPPING;
|
||||
CronHelper::saveDaemon($daemon);
|
||||
exit;
|
||||
}
|
||||
@@ -77,7 +82,7 @@ class Daemon {
|
||||
}
|
||||
|
||||
function callSelf() {
|
||||
CronHelper::accessDaemon($this->token, self::daemon_request_timeout);
|
||||
CronHelper::accessDaemon($this->token, self::REQUEST_TIMEOUT);
|
||||
exit;
|
||||
}
|
||||
}
|
@@ -23,7 +23,7 @@ class Supervisor {
|
||||
// if the daemon is stopped, return its status and do nothing
|
||||
if(!$this->force_run &&
|
||||
isset($daemon['status']) &&
|
||||
$daemon['status'] === 'stopped'
|
||||
$daemon['status'] === Daemon::STATUS_STOPPED
|
||||
) {
|
||||
return $this->formatDaemonStatusMessage($daemon['status']);
|
||||
|
||||
@@ -31,17 +31,17 @@ class Supervisor {
|
||||
$elapsed_time = time() - (int) $daemon['updated_at'];
|
||||
// if it's been less than 40 seconds since last execution and we're not
|
||||
// force-running the daemon, return its status and do nothing
|
||||
if($elapsed_time < CronHelper::daemon_execution_timeout && !$this->force_run) {
|
||||
if($elapsed_time < CronHelper::DAEMON_EXECUTION_TIMEOUT && !$this->force_run) {
|
||||
return $this->formatDaemonStatusMessage($daemon['status']);
|
||||
}
|
||||
// if it's been less than 40 seconds since last execution, we are
|
||||
// force-running the daemon and it's either being started or stopped,
|
||||
// return its status and do nothing
|
||||
elseif($elapsed_time < CronHelper::daemon_execution_timeout &&
|
||||
elseif($elapsed_time < CronHelper::DAEMON_EXECUTION_TIMEOUT &&
|
||||
$this->force_run &&
|
||||
in_array($daemon['status'], array(
|
||||
'stopping',
|
||||
'starting'
|
||||
Daemon::STATUS_STOPPING,
|
||||
Daemon::STATUS_STARTING
|
||||
))
|
||||
) {
|
||||
return $this->formatDaemonStatusMessage($daemon['status']);
|
||||
|
@@ -4,7 +4,6 @@ namespace MailPoet\Cron\Workers;
|
||||
use MailPoet\Cron\CronHelper;
|
||||
use MailPoet\Mailer\Mailer;
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\NewsletterLink;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Models\StatisticsNewsletters;
|
||||
use MailPoet\Models\Subscriber;
|
||||
@@ -20,9 +19,9 @@ class SendingQueue {
|
||||
public $mta_config;
|
||||
public $mta_log;
|
||||
public $processing_method;
|
||||
public $divider = '***MailPoet***';
|
||||
private $timer;
|
||||
const batch_size = 50;
|
||||
const BATCH_SIZE = 50;
|
||||
const DIVIDER = '***MailPoet***';
|
||||
|
||||
function __construct($timer = false) {
|
||||
$this->mta_config = $this->getMailerConfig();
|
||||
@@ -51,7 +50,7 @@ class SendingQueue {
|
||||
$queue->subscribers->failed = array();
|
||||
}
|
||||
$mailer = $this->configureMailer($newsletter);
|
||||
foreach(array_chunk($queue->subscribers->to_process, self::batch_size) as
|
||||
foreach(array_chunk($queue->subscribers->to_process, self::BATCH_SIZE) as
|
||||
$subscribers_ids) {
|
||||
$subscribers = Subscriber::whereIn('id', $subscribers_ids)
|
||||
->findArray();
|
||||
@@ -94,8 +93,8 @@ class SendingQueue {
|
||||
// render newsletter
|
||||
list($rendered_newsletter, $queue->newsletter_rendered_body_hash) =
|
||||
$this->renderNewsletter($newsletter);
|
||||
// extract and replace links
|
||||
$processed_newsletter = $this->processLinks(
|
||||
// process link shortcodes, extract and save links in the database
|
||||
$processed_newsletter = $this->processLinksAndShortcodes(
|
||||
$this->joinObject($rendered_newsletter),
|
||||
$newsletter['id'],
|
||||
$queue->id
|
||||
@@ -119,7 +118,7 @@ class SendingQueue {
|
||||
function processBulkSubscribers($mailer, $newsletter, $subscribers, $queue) {
|
||||
foreach($subscribers as $subscriber) {
|
||||
$processed_newsletters[] =
|
||||
$this->processNewsletter($newsletter, $subscriber, $queue);
|
||||
$this->processNewsletterBeforeSending($newsletter, $subscriber, $queue);
|
||||
if(!$queue->newsletter_rendered_subject) {
|
||||
$queue->newsletter_rendered_subject = $processed_newsletters[0]['subject'];
|
||||
}
|
||||
@@ -163,7 +162,7 @@ class SendingQueue {
|
||||
function processIndividualSubscriber($mailer, $newsletter, $subscribers, $queue) {
|
||||
foreach($subscribers as $subscriber) {
|
||||
$this->checkSendingLimit();
|
||||
$processed_newsletter = $this->processNewsletter($newsletter, $subscriber, $queue);
|
||||
$processed_newsletter = $this->processNewsletterBeforeSending($newsletter, $subscriber, $queue);
|
||||
if(!$queue->newsletter_rendered_subject) {
|
||||
$queue->newsletter_rendered_subject = $processed_newsletter['subject'];
|
||||
}
|
||||
@@ -202,21 +201,26 @@ class SendingQueue {
|
||||
return array($rendered_newsletter, $rendered_newsletter_hash);
|
||||
}
|
||||
|
||||
function processLinks($text, $newsletter_id, $queue_id) {
|
||||
list($text, $processed_links) = Links::replace($text);
|
||||
foreach($processed_links as $link) {
|
||||
// save extracted and processed links
|
||||
$newsletter_link = NewsletterLink::create();
|
||||
$newsletter_link->newsletter_id = $newsletter_id;
|
||||
$newsletter_link->queue_id = $queue_id;
|
||||
$newsletter_link->hash = $link['hash'];
|
||||
$newsletter_link->url = $link['url'];
|
||||
$newsletter_link->save();
|
||||
}
|
||||
return $text;
|
||||
function processLinksAndShortcodes($content, $newsletter_id, $queue_id) {
|
||||
// process only link shortcodes
|
||||
$shortcodes = new Shortcodes($newsletter = false, $subscriber = false, $queue_id);
|
||||
$content = $shortcodes->replace(
|
||||
$content,
|
||||
$categories = array('link')
|
||||
);
|
||||
// extract and save links and link shortcodes
|
||||
list($content, $processed_links) =
|
||||
Links::process(
|
||||
$content,
|
||||
$links = false,
|
||||
$process_link_shortcodes = true,
|
||||
$queue_id
|
||||
);
|
||||
Links::save($processed_links, $newsletter_id, $queue_id);
|
||||
return $content;
|
||||
}
|
||||
|
||||
function processNewsletter($newsletter, $subscriber = false, $queue) {
|
||||
function processNewsletterBeforeSending($newsletter, $subscriber = false, $queue) {
|
||||
$data_for_shortcodes = array(
|
||||
$newsletter['subject'],
|
||||
$newsletter['body']['html'],
|
||||
@@ -225,10 +229,11 @@ class SendingQueue {
|
||||
$processed_newsletter = $this->replaceShortcodes(
|
||||
$newsletter,
|
||||
$subscriber,
|
||||
$queue,
|
||||
$this->joinObject($data_for_shortcodes)
|
||||
);
|
||||
if((boolean) Setting::getValue('tracking.enabled')) {
|
||||
$processed_newsletter = $this->replaceLinks(
|
||||
$processed_newsletter = Links::replaceSubscriberData(
|
||||
$newsletter['id'],
|
||||
$subscriber['id'],
|
||||
$queue->id,
|
||||
@@ -242,18 +247,11 @@ class SendingQueue {
|
||||
return $newsletter;
|
||||
}
|
||||
|
||||
function replaceLinks($newsletter_id, $subscriber_id, $queue_id, $body) {
|
||||
return str_replace(
|
||||
'[mailpoet_data]',
|
||||
sprintf('%s-%s-%s', $newsletter_id, $subscriber_id, $queue_id),
|
||||
$body
|
||||
);
|
||||
}
|
||||
|
||||
function replaceShortcodes($newsletter, $subscriber, $body) {
|
||||
function replaceShortcodes($newsletter, $subscriber, $queue, $body) {
|
||||
$shortcodes = new Shortcodes(
|
||||
$newsletter,
|
||||
$subscriber
|
||||
$subscriber,
|
||||
$queue
|
||||
);
|
||||
return $shortcodes->replace($body);
|
||||
}
|
||||
@@ -372,10 +370,10 @@ class SendingQueue {
|
||||
}
|
||||
|
||||
private function joinObject($object = array()) {
|
||||
return implode($this->divider, $object);
|
||||
return implode(self::DIVIDER, $object);
|
||||
}
|
||||
|
||||
private function splitObject($object = array()) {
|
||||
return explode($this->divider, $object);
|
||||
return explode(self::DIVIDER, $object);
|
||||
}
|
||||
}
|
@@ -124,6 +124,10 @@ class Subscriber extends Model {
|
||||
return false;
|
||||
}
|
||||
|
||||
static function verifyToken($email, $token) {
|
||||
return (self::generateToken($email) === $token);
|
||||
}
|
||||
|
||||
static function subscribe($subscriber_data = array(), $segment_ids = array()) {
|
||||
if(empty($subscriber_data) or empty($segment_ids)) {
|
||||
return false;
|
||||
|
@@ -1,13 +1,16 @@
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Links;
|
||||
|
||||
use MailPoet\Models\NewsletterLink;
|
||||
use MailPoet\Newsletter\Shortcodes\Shortcodes;
|
||||
use MailPoet\Util\Security;
|
||||
|
||||
class Links {
|
||||
static function extract($text) {
|
||||
const DATA_TAG = '[mailpoet_data]';
|
||||
|
||||
static function extract($content) {
|
||||
// adopted from WP's wp_extract_urls() function & modified to work on hrefs
|
||||
# match href=' or href="
|
||||
# match href=' or href="
|
||||
$regex = '#(?:href.*?=.*?)(["\']?)('
|
||||
# match http://
|
||||
. '(?:([\w-]+:)?//?)'
|
||||
@@ -18,22 +21,24 @@ class Links {
|
||||
. '(?:'
|
||||
. '\([\w\d]+\)|'
|
||||
. '(?:'
|
||||
. '[^`!()\[\]{};:\'".,<>«»“”‘’\s]|'
|
||||
. '[^`!()\[\]{}:;\'".,<>«»“”‘’\s]|'
|
||||
. '(?:[:]\d+)?/?'
|
||||
. ')+'
|
||||
. ')'
|
||||
. ')\\1#';
|
||||
preg_match_all($regex, $text, $links);
|
||||
$shortcodes = new Shortcodes();;
|
||||
$shortcodes = $shortcodes->extract($text, $limit = array('subscription'));
|
||||
// extract shortcodes with [link:*] format
|
||||
$shortcodes = new Shortcodes();
|
||||
$shortcodes = $shortcodes->extract($content, $categories = array('link'));
|
||||
// extract links
|
||||
preg_match_all($regex, $content, $links);
|
||||
return array_merge(
|
||||
array_unique($links[2]),
|
||||
$shortcodes
|
||||
);
|
||||
}
|
||||
|
||||
static function replace($text, $links = false) {
|
||||
$links = ($links) ? $links : self::extract($text);
|
||||
static function process($content) {
|
||||
$links = self::extract($content);
|
||||
$processed_links = array();
|
||||
foreach($links as $link) {
|
||||
$hash = Security::generateRandomString(5);
|
||||
@@ -42,13 +47,53 @@ class Links {
|
||||
'url' => $link
|
||||
);
|
||||
$encoded_link = sprintf(
|
||||
'%s/?mailpoet&endpoint=track&action=click&data=%s',
|
||||
'%s/?mailpoet&endpoint=track&action=click&data=%s-%s',
|
||||
home_url(),
|
||||
'[mailpoet_data]-'.$hash
|
||||
self::DATA_TAG,
|
||||
$hash
|
||||
);
|
||||
$link_regex = '/' . preg_quote($link, '/') . '/';
|
||||
$text = preg_replace($link_regex, $encoded_link, $text);
|
||||
$content = preg_replace($link_regex, $encoded_link, $content);
|
||||
}
|
||||
return array(
|
||||
$content,
|
||||
$processed_links
|
||||
);
|
||||
}
|
||||
|
||||
static function replaceSubscriberData(
|
||||
$newsletter_id,
|
||||
$subscriber_id,
|
||||
$queue_id,
|
||||
$content
|
||||
) {
|
||||
$regex = sprintf('/data=(%s(?:-\w+)?)/', preg_quote(self::DATA_TAG));
|
||||
preg_match_all($regex, $content, $links);
|
||||
foreach($links[1] as $link) {
|
||||
$hash = null;
|
||||
if(preg_match('/-/', $link)) {
|
||||
list(, $hash) = explode('-', $link);
|
||||
}
|
||||
$data = array(
|
||||
'newsletter' => $newsletter_id,
|
||||
'subscriber' => $subscriber_id,
|
||||
'queue' => $queue_id,
|
||||
'hash' => $hash
|
||||
);
|
||||
$data = rtrim(base64_encode(serialize($data)), '=');
|
||||
$content = str_replace($link, $data, $content);
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
static function save($links, $newsletter_id, $queue_id) {
|
||||
foreach($links as $link) {
|
||||
$newsletter_link = NewsletterLink::create();
|
||||
$newsletter_link->newsletter_id = $newsletter_id;
|
||||
$newsletter_link->queue_id = $queue_id;
|
||||
$newsletter_link->hash = $link['hash'];
|
||||
$newsletter_link->url = $link['url'];
|
||||
$newsletter_link->save();
|
||||
}
|
||||
return array($text, $processed_links);
|
||||
}
|
||||
}
|
@@ -57,14 +57,7 @@ class Text {
|
||||
</tr>
|
||||
</tbody>'
|
||||
);
|
||||
$blockquote->parent->insertChild(
|
||||
array(
|
||||
'tag_name' => 'br',
|
||||
'self_close' => true,
|
||||
'attributes' => array()
|
||||
),
|
||||
$blockquote->index() + 1
|
||||
);
|
||||
$blockquote = self::insertLineBreak($blockquote);
|
||||
}
|
||||
return $DOM->__toString();
|
||||
}
|
||||
@@ -75,8 +68,25 @@ class Text {
|
||||
$paragraphs = $DOM->query('p');
|
||||
if(!$paragraphs->count()) return $html;
|
||||
foreach($paragraphs as $paragraph) {
|
||||
// remove empty paragraphs
|
||||
// process empty paragraphs
|
||||
if(!trim($paragraph->html())) {
|
||||
$next_element = ($paragraph->getNextSibling()) ?
|
||||
trim($paragraph->getNextSibling()->text()) :
|
||||
false;
|
||||
$previous_element = ($paragraph->getPreviousSibling()) ?
|
||||
trim($paragraph->getPreviousSibling()->text()) :
|
||||
false;
|
||||
$previous_element_tag = ($previous_element) ?
|
||||
$paragraph->getPreviousSibling()->tag :
|
||||
false;
|
||||
// if previous or next paragraphs are empty OR previous paragraph
|
||||
// is a heading, insert a break line
|
||||
if (!$next_element ||
|
||||
!$previous_element ||
|
||||
(preg_match('/h\d+/', $previous_element_tag))
|
||||
) {
|
||||
$paragraph = self::insertLineBreak($paragraph);
|
||||
}
|
||||
$paragraph->remove();
|
||||
continue;
|
||||
}
|
||||
@@ -91,9 +101,13 @@ class Text {
|
||||
$paragraph->cellpadding = 0;
|
||||
$next_element = $paragraph->getNextSibling();
|
||||
// unless this is the last element in column, add double line breaks
|
||||
$line_breaks = ($next_element && !$next_element->getInnerText()) ? '<br /><br />' : '';
|
||||
$line_breaks = ($next_element && !trim($next_element->text())) ?
|
||||
'<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;
|
||||
$line_breaks = ($next_element && preg_match('/<li>/i', $next_element->text())) ?
|
||||
'<br />' :
|
||||
$line_breaks;
|
||||
$paragraph->html('
|
||||
<tr>
|
||||
<td class="mailpoet_paragraph" style="word-break:break-word;word-wrap:break-word;' . $style . '">
|
||||
@@ -139,4 +153,16 @@ class Text {
|
||||
static function removeLastLineBreak($html) {
|
||||
return preg_replace('/(^)?(<br.*?\/?>)+$/i', '', $html);
|
||||
}
|
||||
|
||||
static function insertLineBreak($element) {
|
||||
$element->parent->insertChild(
|
||||
array(
|
||||
'tag_name' => 'br',
|
||||
'self_close' => true,
|
||||
'attributes' => array()
|
||||
),
|
||||
$element->index() + 1
|
||||
);
|
||||
return $element;
|
||||
}
|
||||
}
|
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Renderer\PostProcess;
|
||||
|
||||
use MailPoet\Newsletter\Links\Links;
|
||||
|
||||
class OpenTracking {
|
||||
static function process($template) {
|
||||
$DOM = new \pQuery();
|
||||
@@ -9,7 +11,7 @@ class OpenTracking {
|
||||
$open_tracking_link = sprintf(
|
||||
'<img alt="" class="" src="%s/%s"/>',
|
||||
home_url(),
|
||||
htmlentities('?mailpoet&endpoint=track&action=open&data=[mailpoet_data]')
|
||||
esc_attr('?mailpoet&endpoint=track&action=open&data=' . Links::DATA_TAG)
|
||||
);
|
||||
$template->html($template->html() . $open_tracking_link);
|
||||
return $DOM->__toString();
|
||||
|
171
lib/Newsletter/Shortcodes/Categories/Link.php
Normal file
171
lib/Newsletter/Shortcodes/Categories/Link.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Shortcodes\Categories;
|
||||
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Statistics\Track\Unsubscribes;
|
||||
use MailPoet\Subscription\Url as SubscriptionUrl;
|
||||
|
||||
class Link {
|
||||
/*
|
||||
{
|
||||
text: '<%= __('Unsubscribe') %>',-
|
||||
shortcode: 'subscription:unsubscribe',
|
||||
},
|
||||
{
|
||||
text: '<%= __('Manage subscription') %>',
|
||||
shortcode: 'subscription:manage',
|
||||
},
|
||||
{
|
||||
text: '<%= __('View in browser link') %>',
|
||||
shortcode: 'newsletter:view_in_browser',
|
||||
}
|
||||
*/
|
||||
static function process($action,
|
||||
$default_value = false,
|
||||
$newsletter,
|
||||
$subscriber,
|
||||
$queue = false
|
||||
) {
|
||||
switch($action) {
|
||||
case 'subscription_unsubscribe':
|
||||
$action = 'subscription_unsubscribe_url';
|
||||
$url = self::processUrl(
|
||||
$action,
|
||||
esc_attr(SubscriptionUrl::getUnsubscribeUrl($subscriber)),
|
||||
$queue
|
||||
);
|
||||
return sprintf(
|
||||
'<a target="_blank" href="%s">%s</a>',
|
||||
$url,
|
||||
__('Unsubscribe')
|
||||
);
|
||||
break;
|
||||
|
||||
case 'subscription_unsubscribe_url':
|
||||
return self::processUrl(
|
||||
$action,
|
||||
SubscriptionUrl::getUnsubscribeUrl($subscriber),
|
||||
$queue
|
||||
);
|
||||
break;
|
||||
|
||||
case 'subscription_manage':
|
||||
$url = self::processUrl(
|
||||
$action = 'subscription_manage_url',
|
||||
esc_attr(SubscriptionUrl::getManageUrl($subscriber)),
|
||||
$queue
|
||||
);
|
||||
return sprintf(
|
||||
'<a target="_blank" href="%s">%s</a>',
|
||||
$url,
|
||||
__('Manage subscription')
|
||||
);
|
||||
break;
|
||||
|
||||
case 'subscription_manage_url':
|
||||
return self::processUrl(
|
||||
$action,
|
||||
SubscriptionUrl::getManageUrl($subscriber),
|
||||
$queue
|
||||
);
|
||||
break;
|
||||
|
||||
case 'newsletter_view_in_browser':
|
||||
$action = 'view_in_browser_url';
|
||||
$url = esc_attr(self::getViewInBrowserUrl($newsletter, $subscriber, $queue));
|
||||
$url = self::processUrl($action, $url, $queue);
|
||||
return sprintf(
|
||||
'<a target="_blank" href="%s">%s</a>',
|
||||
$url,
|
||||
__('View in your browser')
|
||||
);
|
||||
break;
|
||||
|
||||
case 'newsletter_view_in_browser_url':
|
||||
$url = self::getViewInBrowserUrl($newsletter, $subscriber, $queue);
|
||||
return self::processUrl($action, $url, $queue);
|
||||
break;
|
||||
|
||||
default:
|
||||
$shortcode = self::getShortcode($action);
|
||||
$url = apply_filters(
|
||||
'mailpoet_newsletter_shortcode_link',
|
||||
$shortcode,
|
||||
$newsletter,
|
||||
$subscriber,
|
||||
$queue
|
||||
);
|
||||
return ($url !== $shortcode) ?
|
||||
self::processUrl($action, $url, $queue) :
|
||||
false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static function getViewInBrowserUrl(
|
||||
$newsletter,
|
||||
$subscriber = false,
|
||||
$queue = false
|
||||
) {
|
||||
$data = array(
|
||||
'newsletter' => (isset($newsletter['id'])) ?
|
||||
$newsletter['id'] :
|
||||
$newsletter,
|
||||
'subscriber' => (isset($subscriber['id'])) ?
|
||||
$subscriber['id'] :
|
||||
$subscriber,
|
||||
'subscriber_token' => (isset($subscriber['id'])) ?
|
||||
Subscriber::generateToken($subscriber['email']) :
|
||||
false,
|
||||
'queue' => (isset($queue['id'])) ?
|
||||
$queue['id'] :
|
||||
$queue
|
||||
);
|
||||
$data = rtrim(base64_encode(serialize($data)), '=');
|
||||
return home_url() . '/?mailpoet&endpoint=view_in_browser&data=' . $data;
|
||||
}
|
||||
|
||||
static function processUrl($action, $url, $queue) {
|
||||
return ($queue !== false && (boolean) Setting::getValue('tracking.enabled')) ?
|
||||
self::getShortcode($action) :
|
||||
$url;
|
||||
}
|
||||
|
||||
static function processShortcodeAction(
|
||||
$shortcode_action, $newsletter, $subscriber, $queue
|
||||
) {
|
||||
switch($shortcode_action) {
|
||||
case 'subscription_unsubscribe_url':
|
||||
// track unsubscribe event
|
||||
if((boolean) Setting::getValue('tracking.enabled')) {
|
||||
$unsubscribe = new Unsubscribes();
|
||||
$unsubscribe->track($subscriber['id'], $queue['id'], $newsletter['id']);
|
||||
}
|
||||
$url = SubscriptionUrl::getUnsubscribeUrl($subscriber);
|
||||
break;
|
||||
case 'subscription_manage_url':
|
||||
$url = SubscriptionUrl::getManageUrl($subscriber);
|
||||
break;
|
||||
case 'newsletter_view_in_browser_url':
|
||||
$url = Link::getViewInBrowserUrl($newsletter, $subscriber, $queue);
|
||||
break;
|
||||
default:
|
||||
$shortcode = self::getShortcode($shortcode_action);
|
||||
$url = apply_filters(
|
||||
'mailpoet_newsletter_shortcode_link',
|
||||
$shortcode,
|
||||
$newsletter,
|
||||
$subscriber,
|
||||
$queue
|
||||
);
|
||||
$url = ($url !== $shortcode_action) ? $url : false;
|
||||
break;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
private static function getShortcode($action) {
|
||||
return sprintf('[link:%s]', $action);
|
||||
}
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
namespace MailPoet\Newsletter\Shortcodes\Categories;
|
||||
|
||||
use MailPoet\Models\SendingQueue;
|
||||
use MailPoet\Newsletter\Shortcodes\ShortcodesHelper;
|
||||
|
||||
require_once( ABSPATH . "wp-includes/pluggable.php" );
|
||||
|
||||
@@ -26,29 +27,26 @@ class Newsletter {
|
||||
{
|
||||
text: '<%= __('Issue number') %>',
|
||||
shortcode: 'newsletter:number',
|
||||
},
|
||||
{
|
||||
text: '<%= __('View in browser link') %>',
|
||||
shortcode: 'newsletter:view_in_browser',
|
||||
}
|
||||
*/
|
||||
static function process($action,
|
||||
$default_value = false,
|
||||
$newsletter, $subscriber = false, $text) {
|
||||
if(is_object($newsletter)) {
|
||||
$newsletter = $newsletter->asArray();
|
||||
}
|
||||
$newsletter,
|
||||
$subscriber,
|
||||
$queue = false,
|
||||
$content
|
||||
) {
|
||||
switch($action) {
|
||||
case 'subject':
|
||||
return ($newsletter) ? $newsletter['subject'] : false;
|
||||
break;
|
||||
|
||||
case 'total':
|
||||
return substr_count($text, 'data-post-id');
|
||||
return substr_count($content, 'data-post-id');
|
||||
break;
|
||||
|
||||
case 'post_title':
|
||||
preg_match_all('/data-post-id="(\w+)"/ism', $text, $posts);
|
||||
preg_match_all('/data-post-id="(\d+)"/ism', $content, $posts);
|
||||
$post_ids = array_unique($posts[1]);
|
||||
$latest_post = self::getLatestWPPost($post_ids);
|
||||
return ($latest_post) ? $latest_post['post_title'] : false;
|
||||
@@ -63,14 +61,6 @@ class Newsletter {
|
||||
return ++$sent_newsletters;
|
||||
break;
|
||||
|
||||
case 'view_in_browser':
|
||||
return '<a href="#TODO">'.__('View in your browser').'</a>';
|
||||
break;
|
||||
|
||||
case 'view_in_browser_url':
|
||||
return '#TODO';
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
|
@@ -1,69 +0,0 @@
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Shortcodes\Categories;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Subscription\Url as SubscriptionUrl;
|
||||
|
||||
class Subscription {
|
||||
/*
|
||||
{
|
||||
text: '<%= __('Unsubscribe') %>',-
|
||||
shortcode: 'subscription:unsubscribe',
|
||||
},
|
||||
{
|
||||
text: '<%= __('Manage subscriptions') %>',
|
||||
shortcode: 'subscription:manage',
|
||||
},
|
||||
*/
|
||||
static function process(
|
||||
$action,
|
||||
$default_value = false,
|
||||
$newsletter = false,
|
||||
$subscriber = false,
|
||||
$text = false,
|
||||
$shortcode
|
||||
) {
|
||||
switch($action) {
|
||||
case 'unsubscribe':
|
||||
return '<a target="_blank" href="'.
|
||||
self::getShortcodeUrl(
|
||||
$shortcode,
|
||||
esc_attr(SubscriptionUrl::getUnsubscribeUrl($subscriber))
|
||||
)
|
||||
.'">'.__('Unsubscribe').'</a>';
|
||||
break;
|
||||
|
||||
case 'unsubscribe_url':
|
||||
return self::getShortcodeUrl(
|
||||
$shortcode,
|
||||
SubscriptionUrl::getUnsubscribeUrl($subscriber)
|
||||
);
|
||||
break;
|
||||
|
||||
case 'manage':
|
||||
return '<a target="_blank" href="'.
|
||||
self::getShortcodeUrl(
|
||||
$shortcode,
|
||||
esc_attr(SubscriptionUrl::getManageUrl($subscriber))
|
||||
)
|
||||
.'">'.__('Manage subscription').'</a>';
|
||||
break;
|
||||
|
||||
case 'manage_url':
|
||||
return self::getShortcodeUrl(
|
||||
$shortcode,
|
||||
SubscriptionUrl::getManageUrl($subscriber)
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static function getShortcodeUrl($shortcode, $url) {
|
||||
return ((boolean) Setting::getValue('tracking.enabled')) ?
|
||||
$shortcode :
|
||||
$url;
|
||||
}
|
||||
}
|
@@ -28,10 +28,12 @@ class User {
|
||||
shortcode: 'user:count',
|
||||
}
|
||||
*/
|
||||
static function process($action, $default_value, $newsletter = false, $subscriber) {
|
||||
if(is_object($subscriber)) {
|
||||
$subscriber = $subscriber->asArray();
|
||||
}
|
||||
static function process(
|
||||
$action,
|
||||
$default_value,
|
||||
$newsletter = false,
|
||||
$subscriber
|
||||
) {
|
||||
switch($action) {
|
||||
case 'firstname':
|
||||
return ($subscriber) ? $subscriber['first_name'] : $default_value;
|
||||
|
@@ -4,61 +4,86 @@ namespace MailPoet\Newsletter\Shortcodes;
|
||||
class Shortcodes {
|
||||
public $newsletter;
|
||||
public $subscriber;
|
||||
public $queue;
|
||||
|
||||
function __construct(
|
||||
$newsletter = false,
|
||||
$subscriber = false
|
||||
$subscriber = false,
|
||||
$queue = false
|
||||
) {
|
||||
$this->newsletter = $newsletter;
|
||||
$this->subscriber = $subscriber;
|
||||
$this->newsletter = (is_object($newsletter)) ?
|
||||
$newsletter->asArray() :
|
||||
$newsletter;
|
||||
$this->subscriber = (is_object($subscriber)) ?
|
||||
$subscriber->asArray() :
|
||||
$subscriber;
|
||||
$this->queue = (is_object($queue)) ?
|
||||
$queue->asArray() :
|
||||
$queue;
|
||||
}
|
||||
|
||||
function extract($text, $limit = false) {
|
||||
$limit = (is_array($limit)) ? implode('|', $limit) : false;
|
||||
function extract($content, $categories= false) {
|
||||
$categories = (is_array($categories)) ? implode('|', $categories) : false;
|
||||
$regex = sprintf(
|
||||
'/\[%s:.*?\]/ism',
|
||||
($limit) ? '(?:' . $limit . ')' : '(?:\w+)'
|
||||
($categories) ? '(?:' . $categories . ')' : '(?:\w+)'
|
||||
);
|
||||
preg_match_all($regex, $text, $shortcodes);
|
||||
preg_match_all($regex, $content, $shortcodes);
|
||||
return array_unique($shortcodes[0]);
|
||||
}
|
||||
|
||||
function match($shortcode) {
|
||||
preg_match(
|
||||
'/\[(?P<type>\w+):(?P<action>\w+)(?:.*?default:(?P<default>.*?))?\]/',
|
||||
'/\[(?P<category>\w+)?:(?P<action>\w+)(?:.*?\|.*?default:(?P<default>.*?))?\]/',
|
||||
$shortcode,
|
||||
$match
|
||||
);
|
||||
return $match;
|
||||
}
|
||||
|
||||
function process($shortcodes, $text) {
|
||||
function process($shortcodes, $content = false) {
|
||||
$processed_shortcodes = array_map(
|
||||
function($shortcode) use($text) {
|
||||
function($shortcode) use($content) {
|
||||
$shortcode_details = $this->match($shortcode);
|
||||
$shortcode_type = ucfirst($shortcode_details['type']);
|
||||
$shortcode_action = $shortcode_details['action'];
|
||||
$shortcode_category = isset($shortcode_details['category']) ?
|
||||
ucfirst($shortcode_details['category']) :
|
||||
false;
|
||||
$shortcode_action = isset($shortcode_details['action']) ?
|
||||
$shortcode_details['action'] :
|
||||
false;
|
||||
$shortcode_class =
|
||||
__NAMESPACE__ . '\\Categories\\' . $shortcode_type;
|
||||
__NAMESPACE__ . '\\Categories\\' . $shortcode_category;
|
||||
$shortcode_default_value = isset($shortcode_details['default'])
|
||||
? $shortcode_details['default'] : false;
|
||||
if(!class_exists($shortcode_class)) return false;
|
||||
if(!class_exists($shortcode_class)) {
|
||||
$custom_shortcode = apply_filters(
|
||||
'mailpoet_newsletter_shortcode',
|
||||
$shortcode,
|
||||
$this->newsletter,
|
||||
$this->subscriber,
|
||||
$this->queue,
|
||||
$content
|
||||
);
|
||||
return ($custom_shortcode === $shortcode) ?
|
||||
false :
|
||||
$custom_shortcode;
|
||||
}
|
||||
return $shortcode_class::process(
|
||||
$shortcode_action,
|
||||
$shortcode_default_value,
|
||||
$this->newsletter,
|
||||
$this->subscriber,
|
||||
$text,
|
||||
$shortcode
|
||||
$this->queue,
|
||||
$content
|
||||
);
|
||||
}, $shortcodes);
|
||||
return $processed_shortcodes;
|
||||
}
|
||||
|
||||
function replace($text) {
|
||||
$shortcodes = $this->extract($text);
|
||||
$processed_shortcodes = $this->process($shortcodes, $text);
|
||||
function replace($content, $categories = false) {
|
||||
$shortcodes = $this->extract($content, $categories);
|
||||
$processed_shortcodes = $this->process($shortcodes, $content);
|
||||
$shortcodes = array_intersect_key($shortcodes, $processed_shortcodes);
|
||||
return str_replace($shortcodes, $processed_shortcodes, $text);
|
||||
return str_replace($shortcodes, $processed_shortcodes, $content);
|
||||
}
|
||||
}
|
76
lib/Newsletter/Viewer/ViewInBrowser.php
Normal file
76
lib/Newsletter/Viewer/ViewInBrowser.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Viewer;
|
||||
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\SendingQueue;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Newsletter\Links\Links;
|
||||
use MailPoet\Newsletter\Renderer\Renderer;
|
||||
use MailPoet\Newsletter\Shortcodes\Shortcodes;
|
||||
|
||||
class ViewInBrowser {
|
||||
public $data;
|
||||
|
||||
function __construct($data) {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
function view($data = false) {
|
||||
$data = ($data) ? $data : $this->data;
|
||||
$newsletter = ($data['newsletter'] !== false) ?
|
||||
Newsletter::findOne($data['newsletter']) :
|
||||
false;
|
||||
if(!$newsletter) $this->abort();
|
||||
$subscriber = ($data['subscriber'] !== false) ?
|
||||
$this->verifySubscriber($data['subscriber'], $data['subscriber_token']) :
|
||||
false;
|
||||
$queue = ($data['queue'] !== false) ?
|
||||
SendingQueue::findOne($data['queue']) :
|
||||
false;
|
||||
$rendered_newsletter =
|
||||
$this->getAndRenderNewsletter($newsletter, $subscriber, $queue);
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
echo $rendered_newsletter;
|
||||
exit;
|
||||
}
|
||||
|
||||
function verifySubscriber($subscriber_id, $subscriber_token) {
|
||||
$subscriber = Subscriber::findOne($subscriber_id);
|
||||
if(!$subscriber ||
|
||||
!Subscriber::verifyToken($subscriber->email, $subscriber_token)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return $subscriber;
|
||||
}
|
||||
|
||||
function getAndRenderNewsletter($newsletter, $subscriber, $queue) {
|
||||
if($queue) {
|
||||
$newsletter_body = json_decode($queue->newsletter_rendered_body, true);
|
||||
} else {
|
||||
$renderer = new Renderer($newsletter->asArray());
|
||||
$newsletter_body = $renderer->render();
|
||||
}
|
||||
$shortcodes = new Shortcodes(
|
||||
$newsletter,
|
||||
$subscriber,
|
||||
$queue
|
||||
);
|
||||
$rendered_newsletter = $shortcodes->replace($newsletter_body['html']);
|
||||
if($queue && (boolean) Setting::getValue('tracking.enabled')) {
|
||||
$rendered_newsletter = Links::replaceSubscriberData(
|
||||
$newsletter->id,
|
||||
$subscriber->id,
|
||||
$queue->id,
|
||||
$rendered_newsletter
|
||||
);
|
||||
}
|
||||
return $rendered_newsletter;
|
||||
}
|
||||
|
||||
private function abort() {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
exit;
|
||||
}
|
||||
}
|
@@ -1,24 +1,23 @@
|
||||
<?php
|
||||
namespace MailPoet\Router;
|
||||
|
||||
use MailPoet\Config\Shortcodes;
|
||||
use MailPoet\Listing;
|
||||
use MailPoet\Mailer\API\MailPoet;
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\Segment;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Models\NewsletterTemplate;
|
||||
use MailPoet\Models\NewsletterSegment;
|
||||
use MailPoet\Models\NewsletterOptionField;
|
||||
use MailPoet\Models\NewsletterOption;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Newsletter\Renderer\Renderer;
|
||||
use MailPoet\Models\SendingQueue;
|
||||
use MailPoet\Newsletter\Scheduler\Scheduler;
|
||||
use MailPoet\Newsletter\Shortcodes\Categories\Link;
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||
|
||||
class Newsletters {
|
||||
function __construct() {
|
||||
}
|
||||
@@ -134,15 +133,32 @@ class Newsletters {
|
||||
return false;
|
||||
}
|
||||
|
||||
function render($data = array()) {
|
||||
function showPreview($data = array()) {
|
||||
if(!isset($data['body'])) {
|
||||
return false;
|
||||
return array(
|
||||
'result' => false,
|
||||
'errors' => array(__('Newsletter data is missing.'))
|
||||
);
|
||||
}
|
||||
$renderer = new Renderer($data);
|
||||
$rendered_newsletter = $renderer->render();
|
||||
$shortcodes = new \MailPoet\Newsletter\Shortcodes\Shortcodes($data);
|
||||
$rendered_newsletter = $shortcodes->replace($rendered_newsletter['html']);
|
||||
return array('rendered_body' => $rendered_newsletter);
|
||||
$newsletter_id = (isset($data['id'])) ? (int) $data['id'] : 0;
|
||||
$newsletter = Newsletter::findOne($newsletter_id);
|
||||
if (!$newsletter) {
|
||||
return array(
|
||||
'result' => false,
|
||||
'errors' => array(__('Newsletter could not be read.'))
|
||||
);
|
||||
}
|
||||
$newsletter->body = $data['body'];
|
||||
$newsletter->save();
|
||||
$wp_user =wp_get_current_user();
|
||||
$subscriber = Subscriber::where('email', $wp_user->data->user_email)
|
||||
->findOne();
|
||||
$subscriber = ($subscriber) ? $subscriber->asArray() : $subscriber;
|
||||
$preview_url = Link::getViewInBrowserUrl($data, $subscriber);
|
||||
return array(
|
||||
'result' => true,
|
||||
'data' => array('url' => $preview_url)
|
||||
);
|
||||
}
|
||||
|
||||
function sendPreview($data = array()) {
|
||||
|
@@ -1,67 +1,87 @@
|
||||
<?php
|
||||
namespace MailPoet\Statistics\Track;
|
||||
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\NewsletterLink;
|
||||
use MailPoet\Models\SendingQueue;
|
||||
use MailPoet\Models\StatisticsClicks;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Subscription\Url as SubscriptionUrl;
|
||||
use MailPoet\Newsletter\Shortcodes\Categories\Link;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Clicks {
|
||||
public $url;
|
||||
public $data;
|
||||
|
||||
function __construct($url) {
|
||||
$this->url = $url;
|
||||
function __construct($data) {
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
function track($url = false) {
|
||||
$url = ($url) ? $url : $this->url;
|
||||
if(!preg_match('/\d+-\d+-\d+-[a-zA-Z0-9]/', $url)) $this->abort();
|
||||
list ($newsletter_id, $subscriber_id, $queue_id, $hash) = explode('-', $url);
|
||||
$subscriber = Subscriber::findOne($subscriber_id);
|
||||
$link = NewsletterLink::where('hash', $hash)
|
||||
->findOne();
|
||||
if(!$subscriber) return;
|
||||
if(!$link) $this->abort();
|
||||
$statistics = StatisticsClicks::where('link_id', $link->id)
|
||||
->where('subscriber_id', $subscriber_id)
|
||||
->where('newsletter_id', $newsletter_id)
|
||||
->where('queue_id', $queue_id)
|
||||
function track($data = false) {
|
||||
$data = ($data) ? $data : $this->data;
|
||||
$newsletter = $this->getNewsletter($data['newsletter']);
|
||||
$subscriber = $this->getSubscriber($data['subscriber']);
|
||||
$queue = $this->getQueue($data['queue']);
|
||||
$link = $this->getLink($data['hash']);
|
||||
if(!$subscriber || !$newsletter || !$link || !$queue) {
|
||||
$this->abort();
|
||||
}
|
||||
$statistics = StatisticsClicks::where('link_id', $link['id'])
|
||||
->where('subscriber_id', $subscriber['id'])
|
||||
->where('newsletter_id', $newsletter['id'])
|
||||
->where('queue_id', $queue['id'])
|
||||
->findOne();
|
||||
if(!$statistics) {
|
||||
// track open action in case it did not register
|
||||
$opens = new Opens($url, $display_image = false);
|
||||
$opens->track();
|
||||
// track open event in case it did not register
|
||||
$open = new Opens($data, $display_image = false);
|
||||
$open->track();
|
||||
$statistics = StatisticsClicks::create();
|
||||
$statistics->newsletter_id = $newsletter_id;
|
||||
$statistics->link_id = $link->id;
|
||||
$statistics->subscriber_id = $subscriber_id;
|
||||
$statistics->queue_id = $queue_id;
|
||||
$statistics->newsletter_id = $newsletter['id'];
|
||||
$statistics->link_id = $link['id'];
|
||||
$statistics->subscriber_id = $subscriber['id'];
|
||||
$statistics->queue_id = $queue['id'];
|
||||
$statistics->count = 1;
|
||||
$statistics->save();
|
||||
} else {
|
||||
$statistics->count++;
|
||||
$statistics->save();
|
||||
}
|
||||
$url = (preg_match('/\[subscription:.*?\]/', $link->url)) ?
|
||||
$this->processSubscriptionUrl($link->url, $subscriber, $queue_id, $newsletter_id) :
|
||||
$link->url;
|
||||
$url = $this->processUrl($link['url'], $newsletter, $subscriber, $queue);
|
||||
header('Location: ' . $url, true, 302);
|
||||
exit;
|
||||
}
|
||||
|
||||
function processSubscriptionUrl($url, $subscriber, $queue_id, $newsletter_id) {
|
||||
preg_match('/\[subscription:(.*?)\]/', $url, $match);
|
||||
$action = $match[1];
|
||||
if(preg_match('/unsubscribe/', $action)) {
|
||||
$url = SubscriptionUrl::getUnsubscribeUrl($subscriber);
|
||||
// track unsubscribe action
|
||||
$unsubscribes = new Unsubscribes();
|
||||
$unsubscribes->track($subscriber->id, $queue_id, $newsletter_id);
|
||||
}
|
||||
if(preg_match('/manage/', $action)) {
|
||||
$url = SubscriptionUrl::getManageUrl($subscriber);
|
||||
function getNewsletter($newsletter_id) {
|
||||
$newsletter = Newsletter::findOne($newsletter_id);
|
||||
return ($newsletter) ? $newsletter->asArray() : $newsletter;
|
||||
}
|
||||
|
||||
function getSubscriber($subscriber_id) {
|
||||
$subscriber = Subscriber::findOne($subscriber_id);
|
||||
return ($subscriber) ? $subscriber->asArray() : $subscriber;
|
||||
}
|
||||
|
||||
function getQueue($queue_id) {
|
||||
$queue = SendingQueue::findOne($queue_id);
|
||||
return ($queue) ? $queue->asArray() : $queue;
|
||||
}
|
||||
|
||||
function getLink($hash) {
|
||||
$link = NewsletterLink::where('hash', $hash)
|
||||
->findOne();
|
||||
return ($link) ? $link->asArray() : $link;
|
||||
}
|
||||
|
||||
function processUrl($url, $newsletter, $subscriber, $queue) {
|
||||
if(preg_match('/\[link:(?P<action>.*?)\]/', $url, $shortcode)) {
|
||||
if(!$shortcode['action']) $this->abort();
|
||||
$url = Link::processShortcodeAction(
|
||||
$shortcode['action'],
|
||||
$newsletter,
|
||||
$subscriber,
|
||||
$queue
|
||||
);
|
||||
if(!$url) $this->abort();
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
@@ -70,4 +90,4 @@ class Clicks {
|
||||
header('HTTP/1.0 404 Not Found');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
@@ -17,22 +17,20 @@ class Opens {
|
||||
|
||||
function track($data = false) {
|
||||
$data = ($data) ? $data : $this->data;
|
||||
if(!preg_match('/\d+-\d+-\d+/', $data)) $this->abort();
|
||||
list ($newsletter_id, $subscriber_id, $queue_id) = explode('-', $data);
|
||||
$subscriber = Subscriber::findOne($subscriber_id);
|
||||
$subscriber = Subscriber::findOne($data['subscriber']);
|
||||
if(!$subscriber) return;
|
||||
$statistics = StatisticsOpens::where('subscriber_id', $subscriber_id)
|
||||
->where('newsletter_id', $newsletter_id)
|
||||
->where('queue_id', $queue_id)
|
||||
$statistics = StatisticsOpens::where('subscriber_id', $subscriber->id)
|
||||
->where('newsletter_id', $data['newsletter'])
|
||||
->where('queue_id', $data['queue'])
|
||||
->findOne();
|
||||
if(!$statistics) {
|
||||
$statistics = StatisticsOpens::create();
|
||||
$statistics->newsletter_id = $newsletter_id;
|
||||
$statistics->subscriber_id = $subscriber_id;
|
||||
$statistics->queue_id = $queue_id;
|
||||
$statistics->newsletter_id = $data['newsletter'];
|
||||
$statistics->subscriber_id = $data['subscriber'];
|
||||
$statistics->queue_id = $data['queue'];
|
||||
$statistics->save();
|
||||
}
|
||||
if ($this->display_image) {
|
||||
if($this->display_image) {
|
||||
// return 1x1 pixel transparent gif image
|
||||
header('Content-Type: image/gif');
|
||||
echo "\x47\x49\x46\x38\x37\x61\x1\x0\x1\x0\x80\x0\x0\xfc\x6a\x6c\x0\x0\x0\x2c\x0\x0\x0\x0\x1\x0\x1\x0\x0\x2\x2\x44\x1\x0\x3b";
|
||||
|
@@ -45,7 +45,7 @@ class Url {
|
||||
$params = array(
|
||||
'endpoint=subscription',
|
||||
'action='.$action,
|
||||
'data='.base64_encode(serialize($data))
|
||||
'data='.rtrim(base64_encode(serialize($data)), '=')
|
||||
);
|
||||
|
||||
// add parameters
|
||||
|
@@ -4,7 +4,7 @@ if(!defined('ABSPATH')) exit;
|
||||
use \MailPoet\Config\Initializer;
|
||||
/*
|
||||
* Plugin Name: MailPoet
|
||||
* Version: 0.0.26
|
||||
* Version: 0.0.27
|
||||
* Plugin URI: http://www.mailpoet.com
|
||||
* Description: MailPoet Newsletters.
|
||||
* Author: MailPoet
|
||||
@@ -22,7 +22,7 @@ use \MailPoet\Config\Initializer;
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
define('MAILPOET_VERSION', '0.0.26');
|
||||
define('MAILPOET_VERSION', '0.0.27');
|
||||
|
||||
$initializer = new Initializer(array(
|
||||
'file' => __FILE__,
|
||||
|
@@ -22,7 +22,7 @@
|
||||
"blocks": [
|
||||
{
|
||||
"type": "header",
|
||||
"text": "Display problems? <a href=\"[newsletter:view_in_browser_url]\">View it in your browser</a>",
|
||||
"text": "Display problems? <a href=\"[link:newsletter_view_in_browser_url]\">View it in your browser</a>",
|
||||
"styles": {
|
||||
"block": {
|
||||
"backgroundColor": "#ffffff"
|
||||
@@ -1154,7 +1154,7 @@
|
||||
"blocks": [
|
||||
{
|
||||
"type": "footer",
|
||||
"text": "<p>You are receiving this email because you opted in on our website. <a href=\"[subscription:manage_url]\">Update your preferences</a> or <a href=\"[subscription:unsubscribe_url]\">Unsubscribe</a><a href=\"[subscription:manage_url]\"> </a><br />123 Maple Avenue<br />93102<br />Oakland, California </p>",
|
||||
"text": "<p>You are receiving this email because you opted in on our website. <a href=\"[link:subscription_manage_url]\">Update your preferences</a> or <a href=\"[link:subscription_unsubscribe_url]\">Unsubscribe</a><a href=\"[link:subscription_manage_url]\"> </a><br />123 Maple Avenue<br />93102<br />Oakland, California </p>",
|
||||
"styles": {
|
||||
"block": {
|
||||
"backgroundColor": "transparent"
|
||||
|
@@ -1,11 +1,13 @@
|
||||
<?php
|
||||
|
||||
use MailPoet\Models\SendingQueue;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Config\Populator;
|
||||
use MailPoet\Subscription\Url as SubscriptionUrl;
|
||||
use MailPoet\Models\SendingQueue;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Newsletter\Shortcodes\Categories\Date;
|
||||
|
||||
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||
require_once(ABSPATH . 'wp-admin/includes/user.php');
|
||||
|
||||
class ShortcodesTest extends MailPoetTest {
|
||||
public $rendered_newsletter;
|
||||
@@ -15,109 +17,206 @@ class ShortcodesTest extends MailPoetTest {
|
||||
function _before() {
|
||||
$populator = new Populator();
|
||||
$populator->up();
|
||||
$this->wp_user = $this->_createWPUser();
|
||||
$this->WP_user = $this->_createWPUser();
|
||||
$this->WP_post = $this->_createWPPost();
|
||||
$this->subscriber = $this->_createSubscriber();
|
||||
$this->newsletter = array(
|
||||
'subject' => 'some subject',
|
||||
'type' => 'notification',
|
||||
'id' => 2
|
||||
);
|
||||
$this->post_data = array(
|
||||
'post_title' => 'Sample Post',
|
||||
'post_content' => 'contents',
|
||||
'post_status' => 'publish',
|
||||
);
|
||||
$this->post_id = wp_insert_post($this->post_data);
|
||||
$this->rendered_newsletter = "
|
||||
Hello [user:displayname | default:member].
|
||||
Your first name is [user:firstname | default:First Name].
|
||||
Your last name is [user:lastname | default:Last Name].
|
||||
Thank you for subscribing with [user:email].
|
||||
We already have [user:count] users.
|
||||
|
||||
<h1 data-post-id=\"1\">some post</h1>
|
||||
<h1 data-post-id=\"{$this->post_id}\">another post</h1>
|
||||
|
||||
There are [newsletter:total] posts in this newsletter.
|
||||
You are reading [newsletter:subject].
|
||||
The latest post in this newsletter is called [newsletter:post_title].
|
||||
The issue number of this newsletter is [newsletter:number].
|
||||
|
||||
Date: [date:d].
|
||||
Ordinal date: [date:dordinal].
|
||||
Date text: [date:dtext].
|
||||
Month: [date:m].
|
||||
Month text: [date:mtext].
|
||||
Year: [date:y]
|
||||
|
||||
You can unsubscribe here: [subscription:unsubscribe_url].
|
||||
Manage your subscription here: [subscription:manage_url].
|
||||
View this newsletter in browser: [newsletter:view_in_browser_url].";
|
||||
$this->shortcodes_object = new MailPoet\Newsletter\Shortcodes\Shortcodes(
|
||||
$this->newsletter,
|
||||
$this->subscriber
|
||||
);
|
||||
Setting::setValue('tracking.enabled', false);
|
||||
}
|
||||
|
||||
function testItCanExtractShortcodes() {
|
||||
$shortcodes = $this->shortcodes_object->extract($this->rendered_newsletter);
|
||||
expect(count($shortcodes))->equals(18);
|
||||
$content = '[category:action] [notshortcode]';
|
||||
$shortcodes = $this->shortcodes_object->extract($content);
|
||||
expect(count($shortcodes))->equals(1);
|
||||
}
|
||||
|
||||
function testItCanProcessShortcodes() {
|
||||
$wp_user = get_userdata($this->wp_user);
|
||||
function testItCanExtractOnlySelectShortcodes() {
|
||||
$content = '[link:action] [newsletter:action]';
|
||||
$limit = array('link');
|
||||
$shortcodes = $this->shortcodes_object->extract($content, $limit);
|
||||
expect(count($shortcodes))->equals(1);
|
||||
expect(preg_match('/link/', $shortcodes[0]))->equals(1);
|
||||
}
|
||||
|
||||
$queue = SendingQueue::create();
|
||||
$queue->newsletter_id = $this->newsletter['id'];
|
||||
$queue->save();
|
||||
$issue_number = 1;
|
||||
function testItCanMatchShortcodeDetails() {
|
||||
$shortcodes_object = $this->shortcodes_object;
|
||||
$content = '[category:action]';
|
||||
$details = $shortcodes_object->match($content);
|
||||
expect($details['category'])->equals('category');
|
||||
expect($details['action'])->equals('action');
|
||||
$content = '[category:action|default:default_value]';
|
||||
$details = $shortcodes_object->match($content);
|
||||
expect($details['category'])->equals('category');
|
||||
expect($details['action'])->equals('action');
|
||||
expect($details['default'])->equals('default_value');
|
||||
$content = '[category:action|default]';
|
||||
$details = $shortcodes_object->match($content);
|
||||
expect($details)->isEmpty();
|
||||
$content = '[category|default:default_value]';
|
||||
$details = $shortcodes_object->match($content);
|
||||
expect($details)->isEmpty();
|
||||
}
|
||||
|
||||
$number_of_posts = 2;
|
||||
function testItCanProcessCustomShortcodes() {
|
||||
$shortcodes_object = $this->shortcodes_object;
|
||||
$shortcode = array('[some:shortcode]');
|
||||
$result = $shortcodes_object->process($shortcode);
|
||||
expect($result[0])->false();
|
||||
add_filter('mailpoet_newsletter_shortcode', function (
|
||||
$shortcode, $newsletter, $subscriber, $queue, $content) {
|
||||
if($shortcode === '[some:shortcode]') return 'success';
|
||||
}, 10, 5);
|
||||
$result = $shortcodes_object->process($shortcode);
|
||||
expect($result[0])->equals('success');
|
||||
}
|
||||
|
||||
function testItCanProcessDateShortcodes() {
|
||||
$date = new \DateTime('now');
|
||||
$subscriber_count = Subscriber::count();
|
||||
$newsletter_with_replaced_shortcodes = $this->shortcodes_object->replace(
|
||||
$this->rendered_newsletter
|
||||
expect(Date::process('d'))->equals($date->format('d'));
|
||||
expect(Date::process('dordinal'))->equals($date->format('dS'));
|
||||
expect(Date::process('dtext'))->equals($date->format('D'));
|
||||
expect(Date::process('m'))->equals($date->format('m'));
|
||||
expect(Date::process('mtext'))->equals($date->format('F'));
|
||||
expect(Date::process('y'))->equals($date->format('Y'));
|
||||
}
|
||||
|
||||
function testItCanProcessNewsletterShortcodes() {
|
||||
$shortcodes_object = $this->shortcodes_object;
|
||||
$content =
|
||||
'<a data-post-id="' . $this->WP_post . '" href="#">latest post</a>' .
|
||||
'<a data-post-id="10" href="#">another post</a>' .
|
||||
'<a href="#">not post</a>';
|
||||
$result =
|
||||
$shortcodes_object->process(array('[newsletter:subject]'));
|
||||
expect($result[0])->equals($this->newsletter['subject']);
|
||||
$result =
|
||||
$shortcodes_object->process(array('[newsletter:total]'), $content);
|
||||
expect($result[0])->equals(2);
|
||||
$result =
|
||||
$shortcodes_object->process(array('[newsletter:post_title]'));
|
||||
$wp_post = get_post($this->WP_post);
|
||||
expect($result['0'])->equals($wp_post->post_title);
|
||||
$result =
|
||||
$shortcodes_object->process(array('[newsletter:number]'));
|
||||
expect($result['0'])->equals(1);
|
||||
$queue = $this->_createQueue();
|
||||
$result =
|
||||
$shortcodes_object->process(array('[newsletter:number]'));
|
||||
expect($result['0'])->equals(2);
|
||||
}
|
||||
|
||||
function testItCanProcessUserShortcodes() {
|
||||
$shortcodes_object = $this->shortcodes_object;
|
||||
$result =
|
||||
$shortcodes_object->process(array('[user:firstname]'));
|
||||
expect($result[0])->equals($this->subscriber->first_name);
|
||||
$result =
|
||||
$shortcodes_object->process(array('[user:lastname]'));
|
||||
expect($result[0])->equals($this->subscriber->last_name);
|
||||
$result =
|
||||
$shortcodes_object->process(array('[user:displayname]'));
|
||||
expect($result[0])->equals($this->WP_user->user_login);
|
||||
$subscribers = Subscriber::where('status', 'subscribed')
|
||||
->findMany();
|
||||
$subscriber_count = count($subscribers);
|
||||
$result =
|
||||
$shortcodes_object->process(array('[user:count]'));
|
||||
expect($result[0])->equals($subscriber_count);
|
||||
$this->subscriber->status = 'unsubscribed';
|
||||
$this->subscriber->save();
|
||||
$result =
|
||||
$shortcodes_object->process(array('[user:count]'));
|
||||
expect($result[0])->equals(--$subscriber_count);
|
||||
}
|
||||
|
||||
function testItCanProcessLinkShortcodes() {
|
||||
$shortcodes_object = $this->shortcodes_object;
|
||||
$result =
|
||||
$shortcodes_object->process(array('[link:subscription_unsubscribe]'));
|
||||
expect(preg_match('/^<a.*?\/a>$/', $result['0']))->equals(1);
|
||||
expect(preg_match('/action=unsubscribe/', $result['0']))->equals(1);
|
||||
$result =
|
||||
$shortcodes_object->process(array('[link:subscription_unsubscribe_url]'));
|
||||
expect(preg_match('/^http.*?action=unsubscribe/', $result['0']))->equals(1);
|
||||
$result =
|
||||
$shortcodes_object->process(array('[link:subscription_manage]'));
|
||||
expect(preg_match('/^<a.*?\/a>$/', $result['0']))->equals(1);
|
||||
expect(preg_match('/action=manage/', $result['0']))->equals(1);
|
||||
$result =
|
||||
$shortcodes_object->process(array('[link:subscription_manage_url]'));
|
||||
expect(preg_match('/^http.*?action=manage/', $result['0']))->equals(1);
|
||||
$result =
|
||||
$shortcodes_object->process(array('[link:newsletter_view_in_browser]'));
|
||||
expect(preg_match('/^<a.*?\/a>$/', $result['0']))->equals(1);
|
||||
expect(preg_match('/endpoint=view_in_browser/', $result['0']))->equals(1);
|
||||
$result =
|
||||
$shortcodes_object->process(array('[link:newsletter_view_in_browser_url]'));
|
||||
expect(preg_match('/^http.*?endpoint=view_in_browser/', $result['0']))->equals(1);
|
||||
}
|
||||
|
||||
function testItReturnsShortcodeWhenTrackingEnabled() {
|
||||
$shortcodes_object = $this->shortcodes_object;
|
||||
$shortcode = '[link:subscription_unsubscribe_url]';
|
||||
$result =
|
||||
$shortcodes_object->process(array($shortcode));
|
||||
expect(preg_match('/^http.*?action=unsubscribe/', $result['0']))->equals(1);
|
||||
Setting::setValue('tracking.enabled', true);
|
||||
$shortcodes = array(
|
||||
'[link:subscription_unsubscribe]',
|
||||
'[link:subscription_unsubscribe_url]',
|
||||
'[link:subscription_manage]',
|
||||
'[link:subscription_manage_url]',
|
||||
'[link:newsletter_view_in_browser]',
|
||||
'[link:newsletter_view_in_browser_url]'
|
||||
);
|
||||
// tracking function only works during sending, so queue object must not be false
|
||||
$shortcodes_object->queue = true;
|
||||
$result =
|
||||
$shortcodes_object->process($shortcodes);
|
||||
// all returned shortcodes must end with url
|
||||
$result = join(',', $result);
|
||||
expect(substr_count($result, '_url'))->equals(count($shortcodes));
|
||||
}
|
||||
|
||||
$unsubscribe_url = SubscriptionUrl::getUnsubscribeUrl($this->subscriber);
|
||||
$manage_url = SubscriptionUrl::getManageUrl($this->subscriber);
|
||||
$view_in_browser_url = '#TODO';
|
||||
function testItCanProcessCustomLinkShortcodes() {
|
||||
$shortcodes_object = $this->shortcodes_object;
|
||||
$shortcode = '[link:shortcode]';
|
||||
$result = $shortcodes_object->process(array($shortcode));
|
||||
expect($result[0])->false();
|
||||
add_filter('mailpoet_newsletter_shortcode_link', function (
|
||||
$shortcode, $newsletter, $subscriber, $queue) {
|
||||
if($shortcode === '[link:shortcode]') return 'success';
|
||||
}, 10, 4);
|
||||
$result = $shortcodes_object->process(array($shortcode));
|
||||
expect($result[0])->equals('success');
|
||||
Setting::setValue('tracking.enabled', true);
|
||||
// tracking function only works during sending, so queue object must not be false
|
||||
$shortcodes_object->queue = true;
|
||||
$result = $shortcodes_object->process(array($shortcode));
|
||||
expect($result[0])->equals($shortcode);
|
||||
}
|
||||
|
||||
expect($newsletter_with_replaced_shortcodes)->equals("
|
||||
Hello {$wp_user->user_login}.
|
||||
Your first name is {$this->subscriber->first_name}.
|
||||
Your last name is {$this->subscriber->last_name}.
|
||||
Thank you for subscribing with {$this->subscriber->email}.
|
||||
We already have {$subscriber_count} users.
|
||||
|
||||
<h1 data-post-id=\"1\">some post</h1>
|
||||
<h1 data-post-id=\"{$this->post_id}\">another post</h1>
|
||||
|
||||
There are {$number_of_posts} posts in this newsletter.
|
||||
You are reading {$this->newsletter['subject']}.
|
||||
The latest post in this newsletter is called {$this->post_data['post_title']}.
|
||||
The issue number of this newsletter is {$issue_number}.
|
||||
|
||||
Date: {$date->format('d')}.
|
||||
Ordinal date: {$date->format('dS')}.
|
||||
Date text: {$date->format('D')}.
|
||||
Month: {$date->format('m')}.
|
||||
Month text: {$date->format('F')}.
|
||||
Year: {$date->format('Y')}
|
||||
|
||||
You can unsubscribe here: {$unsubscribe_url}.
|
||||
Manage your subscription here: {$manage_url}.
|
||||
View this newsletter in browser: {$view_in_browser_url}.");
|
||||
}
|
||||
function _createWPPost() {
|
||||
$data = array(
|
||||
'post_title' => 'Sample Post',
|
||||
'post_content' => 'contents',
|
||||
'post_status' => 'publish',
|
||||
);
|
||||
return wp_insert_post($data);
|
||||
}
|
||||
|
||||
function _createWPUser() {
|
||||
$wp_user = wp_create_user('phoenix_test_user', 'pass', 'phoenix@test.com');
|
||||
if(is_wp_error($wp_user)) {
|
||||
$wp_user = get_user_by('login', 'phoenix_test_user');
|
||||
$wp_user = $wp_user->ID;
|
||||
}
|
||||
return $wp_user;
|
||||
$WP_user = wp_create_user('phoenix_test_user', 'pass', 'phoenix@test.com');
|
||||
$WP_user = get_user_by('login', 'phoenix_test_user');
|
||||
return $WP_user;
|
||||
}
|
||||
|
||||
function _createSubscriber() {
|
||||
@@ -128,15 +227,25 @@ class ShortcodesTest extends MailPoetTest {
|
||||
'last_name' => 'Trump',
|
||||
'email' => 'mister@trump.com',
|
||||
'status' => Subscriber::STATUS_SUBSCRIBED,
|
||||
'wp_user_id' => $this->wp_user
|
||||
'WP_user_id' => $this->WP_user->ID
|
||||
)
|
||||
);
|
||||
$subscriber->save();
|
||||
return Subscriber::findOne($subscriber->id);
|
||||
}
|
||||
|
||||
function _createQueue() {
|
||||
$queue = SendingQueue::create();
|
||||
$queue->newsletter_id = $this->newsletter['id'];
|
||||
$queue->status = 'completed';
|
||||
$queue->save();
|
||||
return $queue;
|
||||
}
|
||||
|
||||
function _after() {
|
||||
Subscriber::deleteMany();
|
||||
wp_delete_post($this->post_id, true);
|
||||
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
|
||||
ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
|
||||
wp_delete_post($this->WP_post, true);
|
||||
wp_delete_user($this->WP_user->ID);
|
||||
}
|
||||
}
|
@@ -320,6 +320,7 @@
|
||||
'customFieldsWindowTitle': __('Select a shortcode'),
|
||||
'unsubscribeLinkMissing': __('All newsletters must include an "unsubscribe" link. Add a footer widget to your newsletter to continue.'),
|
||||
'newsletterPreviewEmailMissing': __('Please enter an email where newsletter preview should be sent to.'),
|
||||
'newsletterPreviewFailed': __('Preview failed. Pleae check console log.'),
|
||||
'newsletterPreviewSent': __('Newsletter preview email has been successfully sent!'),
|
||||
'newsletterPreviewFailedToSend': __('Attempt to send a newsletter preview email failed. Please verify that your sending method is configured correctly try again.'),
|
||||
'templateNameMissing': __('Please add a template name'),
|
||||
@@ -1024,7 +1025,7 @@
|
||||
},
|
||||
},
|
||||
footer: {
|
||||
text: '<a href="[subscription:unsubscribe_url]"><%= __('Unsubscribe') %></a> | <a href="[subscription:manage_url]"><%= __('Manage subscription') %></a><br /><b><%= __('Add your postal address here!') %></b>',
|
||||
text: '<a href="[link:subscription_unsubscribe_url]"><%= __('Unsubscribe') %></a> | <a href="[link:subscription_manage_url]"><%= __('Manage subscription') %></a><br /><b><%= __('Add your postal address here!') %></b>',
|
||||
styles: {
|
||||
block: {
|
||||
backgroundColor: 'transparent',
|
||||
@@ -1149,7 +1150,7 @@
|
||||
},
|
||||
header: {
|
||||
text: '<%= __('Display problems?') %> '+
|
||||
'<a href="[newsletter:view_in_browser_url]"><%= __('View it in your browser') %></a>',
|
||||
'<a href="[link:newsletter_view_in_browser_url]"><%= __('View it in your browser') %></a>',
|
||||
styles: {
|
||||
block: {
|
||||
backgroundColor: 'transparent',
|
||||
@@ -1239,15 +1240,15 @@
|
||||
'<%= __('Links') %>': [
|
||||
{
|
||||
text: '<%= __('Unsubscribe link') %>',
|
||||
shortcode: 'subscription:unsubscribe',
|
||||
shortcode: 'link:subscription_unsubscribe',
|
||||
},
|
||||
{
|
||||
text: '<%= __('Edit subscription page link') %>',
|
||||
shortcode: 'subscription:manage',
|
||||
shortcode: 'link:subscription_manage',
|
||||
},
|
||||
{
|
||||
text: '<%= __('View in browser link') %>',
|
||||
shortcode: 'newsletter:view_in_browser',
|
||||
shortcode: 'link:newsletter_view_in_browser',
|
||||
}
|
||||
],
|
||||
<% if customFields %>
|
||||
|
Reference in New Issue
Block a user