diff --git a/lib/Newsletter/Shortcodes/Categories/Link.php b/lib/Newsletter/Shortcodes/Categories/Link.php index 21bde82433..3c920c7613 100644 --- a/lib/Newsletter/Shortcodes/Categories/Link.php +++ b/lib/Newsletter/Shortcodes/Categories/Link.php @@ -1,55 +1,55 @@ ',- - 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)) - ); - return sprintf( - '%s', - $url, - __('Unsubscribe') - ); - break; +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)) + ); + return sprintf( + '%s', + $url, + __('Unsubscribe') + ); + break; - case 'subscription_unsubscribe_url': - return self::processUrl( - $action, - SubscriptionUrl::getUnsubscribeUrl($subscriber) - ); - break; + case 'subscription_unsubscribe_url': + return self::processUrl( + $action, + SubscriptionUrl::getUnsubscribeUrl($subscriber) + ); + break; - case 'subscription_manage': - $url = self::processUrl( + case 'subscription_manage': + $url = self::processUrl( $action = 'subscription_manage_url', esc_attr(SubscriptionUrl::getManageUrl($subscriber)) ); @@ -81,20 +81,21 @@ namespace MailPoet\Newsletter\Shortcodes\Categories; case 'newsletter_view_in_browser_url': $url = self::getViewInBrowserUrl($newsletter, $subscriber, $queue); return self::processUrl($action, $url); - break; + break; default: + $shortcode = self::getShortcode($action); $url = apply_filters( - 'mailpoet_shortcode_link', - $action, + 'mailpoet_newsletter_shortcode_link', + $shortcode, $newsletter, $subscriber, $queue ); - return ($url !== $action) ? + return ($url !== $shortcode) ? self::processUrl($action, $url) : false; - break; + break; } } @@ -130,7 +131,7 @@ namespace MailPoet\Newsletter\Shortcodes\Categories; } } return ((boolean) Setting::getValue('tracking.enabled')) ? - '[link:' . $action . ']' : + self::getShortcode($action) : $url; } @@ -153,9 +154,10 @@ namespace MailPoet\Newsletter\Shortcodes\Categories; $url = Link::getViewInBrowserUrl($newsletter, $subscriber, $queue); break; default: + $shortcode = self::getShortcode($shortcode_action); $url = apply_filters( - 'mailpoet_shortcode_link', - $shortcode_action, + 'mailpoet_newsletter_shortcode_link', + $shortcode, $newsletter, $subscriber, $queue @@ -165,4 +167,8 @@ namespace MailPoet\Newsletter\Shortcodes\Categories; } return $url; } + + private static function getShortcode($action) { + return sprintf('[link:%s]', $action); + } } \ No newline at end of file diff --git a/lib/Newsletter/Shortcodes/Categories/Newsletter.php b/lib/Newsletter/Shortcodes/Categories/Newsletter.php index c3ff7d9863..cda51c0c51 100644 --- a/lib/Newsletter/Shortcodes/Categories/Newsletter.php +++ b/lib/Newsletter/Shortcodes/Categories/Newsletter.php @@ -34,7 +34,7 @@ class Newsletter { $newsletter, $subscriber, $queue = false, - $text + $content ) { switch($action) { case 'subject': @@ -42,11 +42,11 @@ class Newsletter { 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; diff --git a/lib/Newsletter/Shortcodes/Shortcodes.php b/lib/Newsletter/Shortcodes/Shortcodes.php index 243a738811..c08826e794 100644 --- a/lib/Newsletter/Shortcodes/Shortcodes.php +++ b/lib/Newsletter/Shortcodes/Shortcodes.php @@ -34,24 +34,36 @@ class Shortcodes { function match($shortcode) { preg_match( - '/\[(?P\w+):(?P\w+)(?:.*?default:(?P.*?))?\]/', + '/\[(?P\w+):(?P\w+)(?:.*?\|.*?default:(?P\w+))?\]/ism', $shortcode, $match ); return $match; } - function process($shortcodes, $content) { + function process($shortcodes, $content = false) { $processed_shortcodes = array_map( function($shortcode) use($content) { $shortcode_details = $this->match($shortcode); - $shortcode_type = ucfirst($shortcode_details['type']); + $shortcode_category = ucfirst($shortcode_details['category']); $shortcode_action = $shortcode_details['action']; $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, diff --git a/tests/unit/Newsletter/ShortcodesTest.php b/tests/unit/Newsletter/ShortcodesTest.php index 14d1ccf994..1dfed165fb 100644 --- a/tests/unit/Newsletter/ShortcodesTest.php +++ b/tests/unit/Newsletter/ShortcodesTest.php @@ -1,11 +1,13 @@ 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. - -

some post

-

post_id}\">another post

- - 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->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() { + $content = '[category:action]'; + $details = $this->shortcodes_object->match($content); + 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'); - $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() { + $content = + 'latest post' . + 'another post' . + 'not post'; + $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('/^$/', $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('/^$/', $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('/^$/', $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); - $manage_url = SubscriptionUrl::getManageUrl($this->subscriber); + function testItCanProcessCustomLinkShortcodes() { + $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( - 'newsletter' => $this->newsletter['id'], - 'subscriber' => $this->subscriber->id, - 'subscriber_token' => Subscriber::generateToken($this->subscriber->email), - 'queue' => false - ); - $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. - -

some post

-

post_id}\">another post

- - 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}."); -} + '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() { @@ -137,15 +216,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); } } \ No newline at end of file