- Implements shortcodes
- Updates newsletter router/sending queue worker to use shortcodes replacement class
This commit is contained in:
@ -6,6 +6,7 @@ use MailPoet\Models\Newsletter;
|
|||||||
use MailPoet\Models\NewsletterStatistics;
|
use MailPoet\Models\NewsletterStatistics;
|
||||||
use MailPoet\Models\Subscriber;
|
use MailPoet\Models\Subscriber;
|
||||||
use MailPoet\Newsletter\Renderer\Renderer;
|
use MailPoet\Newsletter\Renderer\Renderer;
|
||||||
|
use MailPoet\Newsletter\Shortcodes\Shortcodes;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
@ -19,17 +20,12 @@ class SendingQueue {
|
|||||||
function process() {
|
function process() {
|
||||||
// TODO: implement mailer sending frequency limits
|
// TODO: implement mailer sending frequency limits
|
||||||
foreach($this->getQueues() as $queue) {
|
foreach($this->getQueues() as $queue) {
|
||||||
$newsletter = Newsletter::findOne($queue->newsletter_id);
|
$newsletter = Newsletter::findOne($queue->newsletter_id)
|
||||||
|
->asArray();
|
||||||
if($newsletter === false) {
|
if(!$newsletter) {
|
||||||
//TODO: delete queue item if newsletter doesn't exist
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
};
|
||||||
$newsletter = $newsletter->asArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
$mailer = $this->configureMailerForNewsletter($newsletter);
|
$mailer = $this->configureMailerForNewsletter($newsletter);
|
||||||
$newsletter = $this->renderNewsletter($newsletter);
|
|
||||||
$subscribers = json_decode($queue->subscribers, true);
|
$subscribers = json_decode($queue->subscribers, true);
|
||||||
$subscribers_to_process = $subscribers['to_process'];
|
$subscribers_to_process = $subscribers['to_process'];
|
||||||
if(!isset($subscribers['processed'])) $subscribers['processed'] = array();
|
if(!isset($subscribers['processed'])) $subscribers['processed'] = array();
|
||||||
@ -41,7 +37,7 @@ class SendingQueue {
|
|||||||
$this->checkExecutionTimer();
|
$this->checkExecutionTimer();
|
||||||
$result = $this->sendNewsletter(
|
$result = $this->sendNewsletter(
|
||||||
$mailer,
|
$mailer,
|
||||||
$this->processNewsletter($newsletter),
|
$this->processNewsletter($newsletter, $db_subscriber),
|
||||||
$db_subscriber);
|
$db_subscriber);
|
||||||
if($result) {
|
if($result) {
|
||||||
$this->updateStatistics($newsletter['id'], $db_subscriber['id'], $queue->id);
|
$this->updateStatistics($newsletter['id'], $db_subscriber['id'], $queue->id);
|
||||||
@ -55,9 +51,11 @@ class SendingQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function processNewsletter($newsletter) {
|
function processNewsletter($newsletter, $subscriber) {
|
||||||
// TODO: replace shortcodes
|
$rendered_newsletter = $this->renderNewsletter($newsletter);
|
||||||
return $newsletter;
|
$shortcodes = new Shortcodes($rendered_newsletter, $newsletter, $subscriber);
|
||||||
|
$processed_newsletter = $shortcodes->replace();
|
||||||
|
return $processed_newsletter;
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendNewsletter($mailer, $newsletter, $subscriber) {
|
function sendNewsletter($mailer, $newsletter, $subscriber) {
|
||||||
|
43
lib/Newsletter/Shortcodes/Categories/Date.php
Normal file
43
lib/Newsletter/Shortcodes/Categories/Date.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Newsletter\Shortcodes\Categories;
|
||||||
|
|
||||||
|
class Date {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
text: '<%= __('Current day of the month number') %>',
|
||||||
|
shortcode: 'date:d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Current day of the month in ordinal, ie. 2nd, 3rd, etc.') %>',
|
||||||
|
shortcode: 'date:dordinal',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Full name of current day') %>',
|
||||||
|
shortcode: 'date:dtext',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Current month number') %>',
|
||||||
|
shortcode: 'date:m',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Full name of current month') %>',
|
||||||
|
shortcode: 'date:mtext',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Year') %>',
|
||||||
|
shortcode: 'date:y',
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
static function process($action) {
|
||||||
|
$date = new \DateTime('now');
|
||||||
|
$actions = array(
|
||||||
|
'd' => $date->format('d'),
|
||||||
|
'dordinal' => $date->format('dS'),
|
||||||
|
'dtext' => $date->format('D'),
|
||||||
|
'm' => $date->format('m'),
|
||||||
|
'mtext' => $date->format('F'),
|
||||||
|
'y' => $date->format('Y')
|
||||||
|
);
|
||||||
|
return (isset($actions[$action])) ? $actions[$action] : false;
|
||||||
|
}
|
||||||
|
}
|
30
lib/Newsletter/Shortcodes/Categories/Link.php
Normal file
30
lib/Newsletter/Shortcodes/Categories/Link.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Newsletter\Shortcodes\Categories;
|
||||||
|
|
||||||
|
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||||
|
|
||||||
|
class Link {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
text: '<%= __('Unsubscribe link') %>',
|
||||||
|
shortcode: 'global:unsubscribe',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Edit subscription page link') %>',
|
||||||
|
shortcode: 'global:manage',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('View in browser link') %>',
|
||||||
|
shortcode: 'global:browser',
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
static function process($action) {
|
||||||
|
// TODO: implement
|
||||||
|
$actions = array(
|
||||||
|
'unsubscribe' => '',
|
||||||
|
'manage' => '',
|
||||||
|
'browser' => ''
|
||||||
|
);
|
||||||
|
return (isset($actions[$action])) ? $actions[$action] : false;
|
||||||
|
}
|
||||||
|
}
|
43
lib/Newsletter/Shortcodes/Categories/Newsletter.php
Normal file
43
lib/Newsletter/Shortcodes/Categories/Newsletter.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Newsletter\Shortcodes\Categories;
|
||||||
|
|
||||||
|
class Newsletter {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
text: '<%= __('Newsletter Subject') %>',-
|
||||||
|
shortcode: 'newsletter:subject',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Total number of posts or pages') %>',
|
||||||
|
shortcode: 'newsletter:total',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Latest post title') %>',
|
||||||
|
shortcode: 'newsletter:post_title',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Issue number') %>',
|
||||||
|
shortcode: 'newsletter:number',
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
static function process($action, $default_value = false, $newsletter) {
|
||||||
|
if(is_object($newsletter)) {
|
||||||
|
$newsletter = $newsletter->asArray();
|
||||||
|
}
|
||||||
|
switch($action) {
|
||||||
|
case 'subject':
|
||||||
|
return ($newsletter) ? $newsletter['subject'] : false;
|
||||||
|
case 'total':
|
||||||
|
$posts = wp_count_posts();
|
||||||
|
return $posts->publish;
|
||||||
|
case 'post_title':
|
||||||
|
$post = wp_get_recent_posts(array('numberposts' => 1));
|
||||||
|
return (isset($post[0])) ? $post[0]['post_title'] : false;
|
||||||
|
case 'number':
|
||||||
|
// TODO: implement
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
lib/Newsletter/Shortcodes/Categories/User.php
Normal file
54
lib/Newsletter/Shortcodes/Categories/User.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Newsletter\Shortcodes\Categories;
|
||||||
|
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
|
||||||
|
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||||
|
|
||||||
|
class User {
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
text: '<%= __('First Name') %>',
|
||||||
|
shortcode: 'user:firstname | default:reader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Last Name') %>',
|
||||||
|
shortcode: 'user:lastname | default:reader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Email Address') %>',
|
||||||
|
shortcode: 'user:email',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Wordpress user display name') %>',
|
||||||
|
shortcode: 'user:displayname | default:member',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '<%= __('Total of subscribers') %>',
|
||||||
|
shortcode: 'user:count',
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
static function process($action, $default_value, $newsletter = false, $subscriber) {
|
||||||
|
if(is_object($subscriber)) {
|
||||||
|
$subscriber = $subscriber->asArray();
|
||||||
|
}
|
||||||
|
switch($action) {
|
||||||
|
case 'firstname':
|
||||||
|
return ($subscriber) ? $subscriber['first_name'] : $default_value;
|
||||||
|
case 'lastname':
|
||||||
|
return ($subscriber) ? $subscriber['last_name'] : $default_value;
|
||||||
|
case 'email':
|
||||||
|
return ($subscriber) ? $subscriber['email'] : false;
|
||||||
|
case 'displayname':
|
||||||
|
if($subscriber && $subscriber['wp_user_id']) {
|
||||||
|
$wp_user = get_userdata($subscriber['wp_user_id']);
|
||||||
|
return $wp_user->user_login;
|
||||||
|
};
|
||||||
|
return $default_value;
|
||||||
|
case 'count':
|
||||||
|
return Subscriber::count();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
lib/Newsletter/Shortcodes/Shortcodes.php
Normal file
53
lib/Newsletter/Shortcodes/Shortcodes.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Newsletter\Shortcodes;
|
||||||
|
|
||||||
|
class Shortcodes {
|
||||||
|
public $rendered_newsletter;
|
||||||
|
public $newsletter;
|
||||||
|
public $subscriber;
|
||||||
|
|
||||||
|
function __construct(
|
||||||
|
$rendered_newsletter,
|
||||||
|
$newsletter = false,
|
||||||
|
$subscriber = false) {
|
||||||
|
$this->rendered_newsletter = $rendered_newsletter;
|
||||||
|
$this->newsletter = $newsletter;
|
||||||
|
$this->subscriber = $subscriber;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extract() {
|
||||||
|
preg_match_all('/\[(?:\w+):.*?\]/', $this->rendered_newsletter, $shortcodes);
|
||||||
|
return array_unique($shortcodes[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function process($shortcodes) {
|
||||||
|
$processed_shortcodes = array_map(
|
||||||
|
function ($shortcode) {
|
||||||
|
// TODO: discuss renaming "global". It is a reserved name in PHP.
|
||||||
|
if($shortcode === 'global') $shortcode = 'link';
|
||||||
|
preg_match(
|
||||||
|
'/\[(?P<type>\w+):(?P<action>\w+)(?:.*?default:(?P<default>.*?))?\]/',
|
||||||
|
$shortcode,
|
||||||
|
$shortcode_details
|
||||||
|
);
|
||||||
|
$shortcode_class =
|
||||||
|
__NAMESPACE__ . '\\Categories\\' . ucfirst($shortcode_details['type']);
|
||||||
|
if(!class_exists($shortcode_class)) return false;
|
||||||
|
return $shortcode_class::process(
|
||||||
|
$shortcode_details['action'],
|
||||||
|
isset($shortcode_details['default'])
|
||||||
|
? $shortcode_details['default'] : false,
|
||||||
|
$this->newsletter,
|
||||||
|
$this->subscriber
|
||||||
|
);
|
||||||
|
}, $shortcodes);
|
||||||
|
return array_filter($processed_shortcodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
function replace() {
|
||||||
|
$shortcodes = $this->extract($this->rendered_newsletter);
|
||||||
|
$processed_shortcodes = $this->process($shortcodes);
|
||||||
|
$shortcodes = array_intersect_key($shortcodes, $processed_shortcodes);
|
||||||
|
return str_replace($shortcodes, $processed_shortcodes, $this->rendered_newsletter);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Router;
|
namespace MailPoet\Router;
|
||||||
|
|
||||||
|
use MailPoet\Config\Shortcodes;
|
||||||
use MailPoet\Listing;
|
use MailPoet\Listing;
|
||||||
use MailPoet\Mailer\API\MailPoet;
|
use MailPoet\Mailer\API\MailPoet;
|
||||||
use MailPoet\Models\Newsletter;
|
use MailPoet\Models\Newsletter;
|
||||||
@ -214,7 +215,12 @@ class Newsletters {
|
|||||||
}
|
}
|
||||||
$renderer = new Renderer($data);
|
$renderer = new Renderer($data);
|
||||||
$rendered_body = $renderer->render();
|
$rendered_body = $renderer->render();
|
||||||
wp_send_json(array('rendered_body' => $rendered_body['html']));
|
$shortcodes = new \MailPoet\Newsletter\Shortcodes\Shortcodes(
|
||||||
|
$rendered_body,
|
||||||
|
$data
|
||||||
|
);
|
||||||
|
$rendered_body = $shortcodes->replace();
|
||||||
|
wp_send_json(array('rendered_body' => $rendered_body));
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendPreview($data = array()) {
|
function sendPreview($data = array()) {
|
||||||
@ -236,10 +242,23 @@ class Newsletters {
|
|||||||
$newsletter = $newsletter->asArray();
|
$newsletter = $newsletter->asArray();
|
||||||
|
|
||||||
$renderer = new Renderer($newsletter);
|
$renderer = new Renderer($newsletter);
|
||||||
$newsletter['body'] = $renderer->render();
|
$rendered_body = $renderer->render();
|
||||||
|
$shortcodes = new \MailPoet\Newsletter\Shortcodes\Shortcodes(
|
||||||
|
$rendered_body,
|
||||||
|
$newsletter
|
||||||
|
);
|
||||||
|
$rendered_body = $shortcodes->replace();
|
||||||
|
$newsletter['body'] = array(
|
||||||
|
'html' => $rendered_body,
|
||||||
|
'text' => '',
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$mailer = new \MailPoet\Mailer\Mailer(false, false, false);
|
$mailer = new \MailPoet\Mailer\Mailer(
|
||||||
|
$mailer = false,
|
||||||
|
$sender = false,
|
||||||
|
$reply_to = false
|
||||||
|
);
|
||||||
|
|
||||||
wp_send_json(array(
|
wp_send_json(array(
|
||||||
'result' => $mailer->send($newsletter, $data['subscriber'])
|
'result' => $mailer->send($newsletter, $data['subscriber'])
|
||||||
|
105
tests/unit/Newsletter/ShortcodesCest.php
Normal file
105
tests/unit/Newsletter/ShortcodesCest.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
|
||||||
|
class ShortcodesCest {
|
||||||
|
public $rendered_newsletter;
|
||||||
|
public $newsletter;
|
||||||
|
public $subscriber;
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
$this->wp_user = $this->_createWPUser();
|
||||||
|
$this->subscriber = $this->_createSubscriber();
|
||||||
|
$this->newsletter['subject'] = 'some subject';
|
||||||
|
$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.
|
||||||
|
|
||||||
|
There are [newsletter:total] posts on this blog.
|
||||||
|
You are reading [newsletter:subject].
|
||||||
|
The latest post on this blog 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 usubscribe here: [global:unsubscribe].
|
||||||
|
Manage your subscription here: [global:manage].
|
||||||
|
View this newsletter in browser: [global:browser].';
|
||||||
|
$this->shortcodes_object = new MailPoet\Newsletter\Shortcodes\Shortcodes(
|
||||||
|
$this->rendered_newsletter,
|
||||||
|
$this->newsletter,
|
||||||
|
$this->subscriber
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function itCanProcessShortcodes() {
|
||||||
|
$shortcodes = $this->shortcodes_object->extract();
|
||||||
|
expect(count($shortcodes))->equals(18);
|
||||||
|
$wp_user = get_userdata($this->wp_user);
|
||||||
|
$wp_post_count = wp_count_posts();
|
||||||
|
$wp_latest_post = wp_get_recent_posts(array('numberposts' => 1));
|
||||||
|
$wp_latest_post = (isset($wp_latest_post)) ?
|
||||||
|
$wp_latest_post[0]['post_title'] :
|
||||||
|
false;
|
||||||
|
$date = new \DateTime('now');
|
||||||
|
$subscriber_count = Subscriber::count();
|
||||||
|
$newsletter_with_replaced_shortcodes = $this->shortcodes_object->replace();
|
||||||
|
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.
|
||||||
|
|
||||||
|
There are {$wp_post_count->publish} posts on this blog.
|
||||||
|
You are reading {$this->newsletter['subject']}.
|
||||||
|
The latest post on this blog is called {$wp_latest_post}.
|
||||||
|
The issue number of this newsletter is [newsletter: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 usubscribe here: [global:unsubscribe].
|
||||||
|
Manage your subscription here: [global:manage].
|
||||||
|
View this newsletter in browser: [global:browser].");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _createSubscriber() {
|
||||||
|
$subscriber = Subscriber::create();
|
||||||
|
$subscriber->hydrate(
|
||||||
|
array(
|
||||||
|
'first_name' => 'Donald',
|
||||||
|
'last_name' => 'Trump',
|
||||||
|
'email' => 'mister@trump.com',
|
||||||
|
'wp_user_id' => $this->wp_user
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$subscriber->save();
|
||||||
|
return Subscriber::findOne($subscriber->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _after() {
|
||||||
|
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user