- Adds custom shortcode processing logic

- Updates shortcode categories code
- Completely rewrites shortcodes unit tess
This commit is contained in:
Vlad
2016-05-01 13:47:31 -04:00
parent 70fa77d333
commit cca76d0d97
4 changed files with 262 additions and 155 deletions

View File

@ -1,55 +1,55 @@
<?php <?php
namespace MailPoet\Newsletter\Shortcodes\Categories; namespace MailPoet\Newsletter\Shortcodes\Categories;
use MailPoet\Models\Setting; use MailPoet\Models\Setting;
use MailPoet\Models\Subscriber; use MailPoet\Models\Subscriber;
use MailPoet\Statistics\Track\Unsubscribes; use MailPoet\Statistics\Track\Unsubscribes;
use MailPoet\Subscription\Url as SubscriptionUrl; use MailPoet\Subscription\Url as SubscriptionUrl;
class Link { class Link {
/* /*
{ {
text: '<%= __('Unsubscribe') %>',- text: '<%= __('Unsubscribe') %>',-
shortcode: 'subscription:unsubscribe', shortcode: 'subscription:unsubscribe',
}, },
{ {
text: '<%= __('Manage subscription') %>', text: '<%= __('Manage subscription') %>',
shortcode: 'subscription:manage', shortcode: 'subscription:manage',
}, },
{ {
text: '<%= __('View in browser link') %>', text: '<%= __('View in browser link') %>',
shortcode: 'newsletter:view_in_browser', shortcode: 'newsletter:view_in_browser',
} }
*/ */
static function process($action, static function process($action,
$default_value = false, $default_value = false,
$newsletter, $newsletter,
$subscriber, $subscriber,
$queue = false $queue = false
) { ) {
switch($action) { switch($action) {
case 'subscription_unsubscribe': case 'subscription_unsubscribe':
$action = 'subscription_unsubscribe_url'; $action = 'subscription_unsubscribe_url';
$url = self::processUrl( $url = self::processUrl(
$action, $action,
esc_attr(SubscriptionUrl::getUnsubscribeUrl($subscriber)) esc_attr(SubscriptionUrl::getUnsubscribeUrl($subscriber))
); );
return sprintf( return sprintf(
'<a target="_blank" href="%s">%s</a>', '<a target="_blank" href="%s">%s</a>',
$url, $url,
__('Unsubscribe') __('Unsubscribe')
); );
break; break;
case 'subscription_unsubscribe_url': case 'subscription_unsubscribe_url':
return self::processUrl( return self::processUrl(
$action, $action,
SubscriptionUrl::getUnsubscribeUrl($subscriber) SubscriptionUrl::getUnsubscribeUrl($subscriber)
); );
break; break;
case 'subscription_manage': case 'subscription_manage':
$url = self::processUrl( $url = self::processUrl(
$action = 'subscription_manage_url', $action = 'subscription_manage_url',
esc_attr(SubscriptionUrl::getManageUrl($subscriber)) esc_attr(SubscriptionUrl::getManageUrl($subscriber))
); );
@ -81,20 +81,21 @@ namespace MailPoet\Newsletter\Shortcodes\Categories;
case 'newsletter_view_in_browser_url': case 'newsletter_view_in_browser_url':
$url = self::getViewInBrowserUrl($newsletter, $subscriber, $queue); $url = self::getViewInBrowserUrl($newsletter, $subscriber, $queue);
return self::processUrl($action, $url); return self::processUrl($action, $url);
break; break;
default: default:
$shortcode = self::getShortcode($action);
$url = apply_filters( $url = apply_filters(
'mailpoet_shortcode_link', 'mailpoet_newsletter_shortcode_link',
$action, $shortcode,
$newsletter, $newsletter,
$subscriber, $subscriber,
$queue $queue
); );
return ($url !== $action) ? return ($url !== $shortcode) ?
self::processUrl($action, $url) : self::processUrl($action, $url) :
false; false;
break; break;
} }
} }
@ -130,7 +131,7 @@ namespace MailPoet\Newsletter\Shortcodes\Categories;
} }
} }
return ((boolean) Setting::getValue('tracking.enabled')) ? return ((boolean) Setting::getValue('tracking.enabled')) ?
'[link:' . $action . ']' : self::getShortcode($action) :
$url; $url;
} }
@ -153,9 +154,10 @@ namespace MailPoet\Newsletter\Shortcodes\Categories;
$url = Link::getViewInBrowserUrl($newsletter, $subscriber, $queue); $url = Link::getViewInBrowserUrl($newsletter, $subscriber, $queue);
break; break;
default: default:
$shortcode = self::getShortcode($shortcode_action);
$url = apply_filters( $url = apply_filters(
'mailpoet_shortcode_link', 'mailpoet_newsletter_shortcode_link',
$shortcode_action, $shortcode,
$newsletter, $newsletter,
$subscriber, $subscriber,
$queue $queue
@ -165,4 +167,8 @@ namespace MailPoet\Newsletter\Shortcodes\Categories;
} }
return $url; return $url;
} }
private static function getShortcode($action) {
return sprintf('[link:%s]', $action);
}
} }

View File

@ -34,7 +34,7 @@ class Newsletter {
$newsletter, $newsletter,
$subscriber, $subscriber,
$queue = false, $queue = false,
$text $content
) { ) {
switch($action) { switch($action) {
case 'subject': case 'subject':
@ -42,11 +42,11 @@ class Newsletter {
break; break;
case 'total': case 'total':
return substr_count($text, 'data-post-id'); return substr_count($content, 'data-post-id');
break; break;
case 'post_title': 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]); $post_ids = array_unique($posts[1]);
$latest_post = self::getLatestWPPost($post_ids); $latest_post = self::getLatestWPPost($post_ids);
return ($latest_post) ? $latest_post['post_title'] : false; return ($latest_post) ? $latest_post['post_title'] : false;

View File

@ -34,24 +34,36 @@ class Shortcodes {
function match($shortcode) { function match($shortcode) {
preg_match( preg_match(
'/\[(?P<type>\w+):(?P<action>\w+)(?:.*?default:(?P<default>.*?))?\]/', '/\[(?P<category>\w+):(?P<action>\w+)(?:.*?\|.*?default:(?P<default>\w+))?\]/ism',
$shortcode, $shortcode,
$match $match
); );
return $match; return $match;
} }
function process($shortcodes, $content) { function process($shortcodes, $content = false) {
$processed_shortcodes = array_map( $processed_shortcodes = array_map(
function($shortcode) use($content) { function($shortcode) use($content) {
$shortcode_details = $this->match($shortcode); $shortcode_details = $this->match($shortcode);
$shortcode_type = ucfirst($shortcode_details['type']); $shortcode_category = ucfirst($shortcode_details['category']);
$shortcode_action = $shortcode_details['action']; $shortcode_action = $shortcode_details['action'];
$shortcode_class = $shortcode_class =
__NAMESPACE__ . '\\Categories\\' . $shortcode_type; __NAMESPACE__ . '\\Categories\\' . $shortcode_category;
$shortcode_default_value = isset($shortcode_details['default']) $shortcode_default_value = isset($shortcode_details['default'])
? $shortcode_details['default'] : false; ? $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( return $shortcode_class::process(
$shortcode_action, $shortcode_action,
$shortcode_default_value, $shortcode_default_value,

View File

@ -1,11 +1,13 @@
<?php <?php
use MailPoet\Models\SendingQueue;
use MailPoet\Models\Subscriber;
use MailPoet\Config\Populator; 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-includes/pluggable.php');
require_once(ABSPATH . 'wp-admin/includes/user.php');
class ShortcodesTest extends MailPoetTest { class ShortcodesTest extends MailPoetTest {
public $rendered_newsletter; public $rendered_newsletter;
@ -15,118 +17,195 @@ class ShortcodesTest extends MailPoetTest {
function _before() { function _before() {
$populator = new Populator(); $populator = new Populator();
$populator->up(); $populator->up();
$this->wp_user = $this->_createWPUser(); $this->WP_user = $this->_createWPUser();
$this->WP_post = $this->_createWPPost();
$this->subscriber = $this->_createSubscriber(); $this->subscriber = $this->_createSubscriber();
$this->newsletter = array( $this->newsletter = array(
'subject' => 'some subject', 'subject' => 'some subject',
'type' => 'notification', 'type' => 'notification',
'id' => 2 '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: [link:subscription_unsubscribe_url].
Manage your subscription here: [link:subscription_manage_url].
View this newsletter in browser: [link:newsletter_view_in_browser_url].";
$this->shortcodes_object = new MailPoet\Newsletter\Shortcodes\Shortcodes( $this->shortcodes_object = new MailPoet\Newsletter\Shortcodes\Shortcodes(
$this->newsletter, $this->newsletter,
$this->subscriber $this->subscriber
); );
Setting::setValue('tracking.enabled', false);
} }
function testItCanExtractShortcodes() { function testItCanExtractShortcodes() {
$shortcodes = $this->shortcodes_object->extract($this->rendered_newsletter); $content = '[category:action] [notshortcode]';
expect(count($shortcodes))->equals(18); $shortcodes = $this->shortcodes_object->extract($content);
expect(count($shortcodes))->equals(1);
} }
function testItCanProcessShortcodes() { function testItCanExtractOnlySelectShortcodes() {
$wp_user = get_userdata($this->wp_user); $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(); function testItCanMatchShortcodeDetails() {
$queue->newsletter_id = $this->newsletter['id']; $content = '[category:action]';
$queue->save(); $details = $this->shortcodes_object->match($content);
$issue_number = 1; expect($details['category'])->equals('category');
expect($details['action'])->equals('action');
$content = '[category:action|default:default_value]';
$details = $this->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 = $this->shortcodes_object->match($content);
expect($details)->isEmpty();
$content = '[category|default:default_value]';
$details = $this->shortcodes_object->match($content);
expect($details)->isEmpty();
}
$number_of_posts = 2; function testItCanProcessCustomShortcodes() {
$shortcode = array('[some:shortcode]');
$result = $this->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 = $this->shortcodes_object->process($shortcode);
expect($result[0])->equals('success');
}
function testItCanProcessDateShortcodes() {
$date = new \DateTime('now'); $date = new \DateTime('now');
$subscriber_count = Subscriber::count(); expect(Date::process('d'))->equals($date->format('d'));
$newsletter_with_replaced_shortcodes = $this->shortcodes_object->replace( expect(Date::process('dordinal'))->equals($date->format('dS'));
$this->rendered_newsletter 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() {
$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 =
$this->shortcodes_object->process(array('[newsletter:subject]'));
expect($result[0])->equals($this->newsletter['subject']);
$result =
$this->shortcodes_object->process(array('[newsletter:total]'), $content);
expect($result[0])->equals(2);
$result =
$this->shortcodes_object->process(array('[newsletter:post_title]'));
$wp_post = get_post($this->WP_post);
expect($result['0'])->equals($wp_post->post_title);
$result =
$this->shortcodes_object->process(array('[newsletter:number]'));
expect($result['0'])->equals(1);
$queue = $this->_createQueue();
$result =
$this->shortcodes_object->process(array('[newsletter:number]'));
expect($result['0'])->equals(2);
}
function testItCanProcessUserShortcodes() {
$result =
$this->shortcodes_object->process(array('[user:firstname]'));
expect($result[0])->equals($this->subscriber->first_name);
$result =
$this->shortcodes_object->process(array('[user:lastname]'));
expect($result[0])->equals($this->subscriber->last_name);
$result =
$this->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 =
$this->shortcodes_object->process(array('[user:count]'));
expect($result[0])->equals($subscriber_count);
$this->subscriber->status = 'unsubscribed';
$this->subscriber->save();
$result =
$this->shortcodes_object->process(array('[user:count]'));
expect($result[0])->equals(--$subscriber_count);
}
function testItCanProcessLinkShortcodes() {
$result =
$this->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 =
$this->shortcodes_object->process(array('[link:subscription_unsubscribe_url]'));
expect(preg_match('/^http.*?action=unsubscribe/', $result['0']))->equals(1);
$result =
$this->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 =
$this->shortcodes_object->process(array('[link:subscription_manage_url]'));
expect(preg_match('/^http.*?action=manage/', $result['0']))->equals(1);
$result =
$this->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 =
$this->shortcodes_object->process(array('[link:newsletter_view_in_browser_url]'));
expect(preg_match('/^http.*?endpoint=view_in_browser/', $result['0']))->equals(1);
}
function testItReturnsShortcodeWhenTrackingEnabled() {
$shortcode = '[link:subscription_unsubscribe_url]';
$result =
$this->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]'
); );
$result =
$this->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); function testItCanProcessCustomLinkShortcodes() {
$manage_url = SubscriptionUrl::getManageUrl($this->subscriber); $shortcode = '[link:shortcode]';
$result = $this->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 = $this->shortcodes_object->process(array($shortcode));
expect($result[0])->equals('success');
Setting::setValue('tracking.enabled', true);
$result = $this->shortcodes_object->process(array($shortcode));
expect($result[0])->equals($shortcode);
}
function _createWPPost() {
$data = array( $data = array(
'newsletter' => $this->newsletter['id'], 'post_title' => 'Sample Post',
'subscriber' => $this->subscriber->id, 'post_content' => 'contents',
'subscriber_token' => Subscriber::generateToken($this->subscriber->email), 'post_status' => 'publish',
'queue' => false );
); return wp_insert_post($data);
$data = rtrim(base64_encode(serialize($data)), '='); }
$view_in_browser_url =
home_url() . '/?mailpoet&endpoint=view_in_browser&data=' . $data;
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 _createWPUser() { function _createWPUser() {
$wp_user = wp_create_user('phoenix_test_user', 'pass', 'phoenix@test.com'); $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 = get_user_by('login', 'phoenix_test_user'); return $WP_user;
$wp_user = $wp_user->ID;
}
return $wp_user;
} }
function _createSubscriber() { function _createSubscriber() {
@ -137,15 +216,25 @@ class ShortcodesTest extends MailPoetTest {
'last_name' => 'Trump', 'last_name' => 'Trump',
'email' => 'mister@trump.com', 'email' => 'mister@trump.com',
'status' => Subscriber::STATUS_SUBSCRIBED, 'status' => Subscriber::STATUS_SUBSCRIBED,
'wp_user_id' => $this->wp_user 'WP_user_id' => $this->WP_user->ID
) )
); );
$subscriber->save(); $subscriber->save();
return Subscriber::findOne($subscriber->id); 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() { function _after() {
Subscriber::deleteMany(); ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
wp_delete_post($this->post_id, true); ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
wp_delete_post($this->WP_post, true);
wp_delete_user($this->WP_user->ID);
} }
} }