Compare commits

..

55 Commits

Author SHA1 Message Date
c915fcfdff Release 3.0.0 2017-09-20 15:21:55 +01:00
02966c3b93 Sets cron daemon timeout to 5s across the plugin
Adds hook to override cron request arguments
2017-09-20 14:59:48 +01:00
84dc48daec Allow passing cron timeouts
[MAILPOET-1114]
2017-09-20 14:59:48 +01:00
12225004f4 Apply hook on cron timeout
[MAILPOET-1114]
2017-09-20 14:59:48 +01:00
320dfa2ec5 Extracts duplicate code into reusable methods
Updates unit test
2017-09-20 14:59:48 +01:00
b5f3016085 Removes URL from user agent
(https://mailpoet.slack.com/archives/C02MTKAJL/p1505488541000029?thread_ts=1505488163.000795&cid=C02MTKAJL)
2017-09-20 14:59:48 +01:00
cd53e369d0 Allows accessing full URL from within custom cron hook 2017-09-20 14:59:48 +01:00
6fc11af774 Returns error message instead of empty body 2017-09-20 14:59:48 +01:00
03d0de74e4 Merge pull request #1108 from mailpoet/send_twice_tooltip
Show a tooltip about sending an email twice only when the Send button is disabled [MAILPOET-1098]
2017-09-19 20:38:10 -04:00
28c75c5b96 Adds a thousand separator 2017-09-19 09:55:38 -04:00
6f255854f2 Merge pull request #1112 from mailpoet/copy_update
Update free MSS plan size to 2000 subscribers [MAILPOET-1112]
2017-09-19 12:46:36 +03:00
91c5f9c43e Clarify Premium plugin benefits 2017-09-19 12:41:25 +03:00
62acd6404a Update free MSS plan size to 2k subscribers, update plugin description 2017-09-19 12:15:46 +03:00
adc1461771 Don't show send tooltip for paused newsletters [MAILPOET-1098] 2017-09-19 08:51:16 +03:00
66cc0964ce Merge pull request #1106 from mailpoet/fix-tests
Fixing MP API test
2017-09-18 18:23:20 -04:00
10d77720ad Merge pull request #1107 from mailpoet/hooks_unit_test_update
Updates hooks unit test [MAILPOET-1110]
2017-09-18 17:39:50 +02:00
d831b2df55 Explicitly sets up hooks instead of assuming they are already set up 2017-09-18 10:43:17 -04:00
16ff630e88 Show a tooltip about sending an email twice only when the Send button is dsiabled [MAILPOET-1098] 2017-09-18 17:42:24 +03:00
d35763662e Fixing MP API test 2017-09-18 12:00:43 +00:00
10be411b12 Prepare release v3.0.0 2017-09-18 11:35:59 +01:00
6ecce192f7 Merge pull request #1105 from mailpoet/wp_sync_multisite
Fix WP sync throwing 'Table "users" doesn't exist' errors on multisite subsites [MAILPOET-1107]
2017-09-18 11:48:30 +03:00
ee07e60fe9 Adds new survey 2017-09-18 09:13:06 +01:00
a35d7a1154 Fix WP sync throwing 'Table users doesn't exist' errors on multisite subsites [MAILPOET-1107] 2017-09-18 10:55:49 +03:00
ebba8dbfd6 Merge pull request #1103 from mailpoet/twig_version_conflict_detection_improvement
Updates Twig version conflict detection logic [MAILPOET-1068]
2017-09-18 10:42:51 +03:00
44c637c06b Merge pull request #1101 from mailpoet/premium_key_in_beacon
Add Premium key to Help Scout beacon [MAILPOET-1090]
2017-09-17 12:08:52 -04:00
d54ba734bf Adds a min-max range of supported Twig versions 2017-09-17 11:25:35 -04:00
b45fc22306 Updates coding style and cleans up JS script inclusion part 2017-09-16 11:34:21 -04:00
994935d4ae Adds check for minimum Twig version loaded by external plugins 2017-09-16 11:33:40 -04:00
ceb5ce850c Removes deprecated Twig_ExtensionInterface::getName()
(https://github.com/twigphp/Twig/blob/2.x/CHANGELOG#L207)
Removes deprecated Twig_Extension_GlobalsInterface
(https://github.com/twigphp/Twig/blob/2.x/CHANGELOG#L259)
2017-09-16 11:30:40 -04:00
97b5ed945d Merge pull request #1100 from mailpoet/update-send-copy
Update send copy [MAILPOET-1101]
2017-09-14 20:02:28 +02:00
873b322245 Translate
[MAILPOET-1101]
2017-09-14 18:52:33 +01:00
12ad9e41e7 Translate a string
[MAILPOET-1101]
2017-09-14 18:40:04 +01:00
96b418e455 Our free plan will be for 1,000 subscribers and not 250
[MAILPOET-1101]
2017-09-14 17:35:15 +01:00
8ea7861f77 Merge pull request #1102 from mailpoet/welcome-tab-update
Update welcome tab [MAILPOET-1099]
2017-09-14 19:34:01 +03:00
821976c881 Make text random
[MAILPOET-1099]
2017-09-14 17:19:55 +01:00
6f1443e43d Update welcome tab
[MAILPOET-1099]
2017-09-14 15:35:07 +01:00
09fcaecdfc Add Premium key to Help Scout beacon [MAILPOET-1090] 2017-09-14 16:24:15 +03:00
efd72ca9f6 Merge pull request #1099 from mailpoet/update-readme
Update readme.txt for launch v3
2017-09-14 15:38:36 +03:00
550b5e9aed More readme.txt updates
[MAILPOET-1105]
2017-09-14 13:37:10 +01:00
4b7ae5fcff Fix typo
[MAILPOET-1105]
2017-09-14 13:28:44 +01:00
fa85e12127 Update premium section in readme.txt
[MAILPOET-1105]
2017-09-14 13:27:07 +01:00
1cce50902b Update Send with... other copy
[MAILPOET-1101]
2017-09-14 11:39:20 +01:00
2048fa5cf9 Update Send with... mailpoet copy
[MAILPOET-1101]
2017-09-14 11:31:43 +01:00
f438c8fd31 Update readme.txt for launch v3
[MAILPOET-1105]
2017-09-14 10:15:00 +01:00
0bfa832dad Merge pull request #1098 from mailpoet/subscribers-fix
Subscribers fix [MAILPOET-1102]
2017-09-13 18:17:56 +03:00
483dfbe1ec Fix removal of WP segment subscribers without wp_user_id [MAILPOET-1102] 2017-09-13 16:46:50 +03:00
561fee491d Merge pull request #1097 from mailpoet/makepot_views_fix
Fix makepot adding extra slashes to escaped characters in views [MAILPOET-1093]
2017-09-13 14:54:25 +02:00
97d157192a Remove orphaned links
[MAILPOET-1102]
2017-09-13 13:30:23 +01:00
6b14a8a057 Remove data from usermeta
[MAILPOET-1102]
2017-09-13 13:18:39 +01:00
d27b187f5e Fix QA problems
[MAILPOET-1102]
2017-09-13 13:15:50 +01:00
02d49ba2ca DELETE subscribers in WP list which are not WP users
[MAILPOET-1102]
2017-09-13 13:07:01 +01:00
f3571a5855 Add another testing scenario
[MAILPOET-1102]
2017-09-13 08:54:54 +01:00
3d5f0df213 Don't delete subscribers with wp_user_id = 0 [MAILPOET-1102] 2017-09-13 10:15:09 +03:00
595a201fe7 Stop deleting subscribers
[MAILPOET-1102]
2017-09-12 17:53:12 +01:00
fd65117a5d Fix makepot adding extra slashes to escaped characters in views [MAILPOET-1093] 2017-09-12 11:17:04 +03:00
26 changed files with 394 additions and 199 deletions

View File

@ -33,3 +33,6 @@ Custom styles for MailPoet pages.
p.top-space-triple
margin-top: 3em
p.mailpoet-top-text
margin-right: 0

View File

@ -62,6 +62,15 @@
margin-bottom: 2em
margin-top: 2em
.sending-free-plan-button
background: #FF5301
border-color: #e64c03
text-shadow: 0 -1px 1px #e64c03
box-shadow: 0 1px 0 #e64c03
margin: 10px 0
strong
text-transform: uppercase
.mailpoet_success_item::before
content ' '

View File

@ -285,6 +285,7 @@ define(
}
return newField;
});
const sendButtonOptions = this.getSendButtonOptions();
return (
<div>
<h1>{MailPoet.I18n.t('finalNewsletterStep')}</h1>
@ -313,7 +314,7 @@ define(
type="button"
onClick={ this.handleSend }
value={MailPoet.I18n.t('send')}
{...this.getSendButtonOptions()}
{...sendButtonOptions}
/>
}
&nbsp;
@ -330,10 +331,12 @@ define(
{MailPoet.I18n.t('goBackToDesign')}
</a>.
</p>
<HelpTooltip
tooltip={MailPoet.I18n.t('helpTooltipSendEmail')}
tooltipId="helpTooltipSendEmail"
/>
{ !isPaused && sendButtonOptions['disabled'] && sendButtonOptions['disabled'] === 'disabled' && (
<HelpTooltip
tooltip={MailPoet.I18n.t('helpTooltipSendEmail')}
tooltipId="helpTooltipSendEmail"
/>
) }
</Form>
</div>
);

View File

@ -13,6 +13,7 @@ class RequirementsChecker {
const TEST_XML_EXTENSION = 'XmlExtension';
const TEST_ZIP_EXTENSION = 'ZipExtension';
const TEST_VENDOR_SOURCE = 'VendorSource';
const TWIG_SUPPORTED_VERSIONS = '1.26.0-1.34.4';
public $display_error_notice;
public $vendor_classes = array(
@ -22,7 +23,6 @@ class RequirementsChecker {
'\Twig_Loader_Filesystem',
'\Twig_Lexer',
'\Twig_Extension',
'\Twig_Extension_GlobalsInterface',
'\Twig_SimpleFunction',
'\Swift_Mailer',
'\Swift_SmtpTransport',
@ -141,13 +141,30 @@ class RequirementsChecker {
$dependency_path
);
return $this->processError($error);
$return_error = true;
// if a Twig dependency is loaded by another plugin, check for valid version
if(strpos($dependency, '\Twig_') === 0) {
$return_error = ($this->isValidTwigVersion()) ? false : $return_error;
}
if($return_error) return $this->processError($error);
}
}
return true;
}
function isValidTwigVersion() {
list($minimum_version, $maximum_version) = explode('-', self::TWIG_SUPPORTED_VERSIONS);
return (
class_exists('\Twig_Environment') &&
defined('\Twig_Environment::VERSION') &&
version_compare(\Twig_Environment::VERSION, $minimum_version, '>=') &&
version_compare(\Twig_Environment::VERSION, $maximum_version, '<=')
);
}
private function getDependencyPath($namespaced_class) {
try {
$reflector = new \ReflectionClass($namespaced_class);
@ -163,4 +180,4 @@ class RequirementsChecker {
}
return false;
}
}
}

View File

@ -13,7 +13,7 @@ if(!defined('ABSPATH')) exit;
class CronHelper {
const DAEMON_EXECUTION_LIMIT = 20; // seconds
const DAEMON_EXECUTION_TIMEOUT = 35; // seconds
const DAEMON_REQUEST_TIMEOUT = 2; // seconds
const DAEMON_REQUEST_TIMEOUT = 5; // seconds
const DAEMON_SETTING = 'cron_daemon';
static function createDaemon($token) {
@ -49,45 +49,53 @@ class CronHelper {
}
static function pingDaemon() {
$url = Router::buildRequest(
CronDaemonEndpoint::ENDPOINT,
$url = self::getCronUrl(
CronDaemonEndpoint::ACTION_PING_RESPONSE
);
$url = str_replace(home_url(), self::getSiteUrl(), $url);
$args = array(
'blocking' => true,
'sslverify' => false,
'timeout' => self::DAEMON_REQUEST_TIMEOUT,
'user-agent' => 'MailPoet (www.mailpoet.com) Cron'
);
$result = wp_remote_get($url, $args);
return wp_remote_retrieve_body($result);
$result = self::queryCronUrl($url);
return (is_wp_error($result)) ?
$result->get_error_message() :
wp_remote_retrieve_body($result);
}
static function accessDaemon($token, $timeout = self::DAEMON_REQUEST_TIMEOUT) {
static function accessDaemon($token) {
$data = array('token' => $token);
$url = Router::buildRequest(
CronDaemonEndpoint::ENDPOINT,
$url = self::getCronUrl(
CronDaemonEndpoint::ACTION_RUN,
$data
);
$url = str_replace(home_url(), self::getSiteUrl(), $url);
$args = array(
'blocking' => true,
'sslverify' => false,
'timeout' => $timeout,
'user-agent' => 'MailPoet (www.mailpoet.com) Cron'
);
$result = wp_remote_get($url, $args);
$result = self::queryCronUrl($url);
return wp_remote_retrieve_body($result);
}
static function queryCronUrl($url) {
$args = WPHooks::applyFilters(
'mailpoet_cron_request_args',
array(
'blocking' => true,
'sslverify' => false,
'timeout' => self::DAEMON_REQUEST_TIMEOUT,
'user-agent' => 'MailPoet Cron'
)
);
return wp_remote_get($url, $args);
}
static function getCronUrl($action, $data = false) {
$url = Router::buildRequest(
CronDaemonEndpoint::ENDPOINT,
$action,
$data
);
$custom_cron_url = WPHooks::applyFilters('mailpoet_cron_request_url', $url);
return ($custom_cron_url === $url) ?
str_replace(home_url(), self::getSiteUrl(), $url) :
$custom_cron_url;
}
static function getSiteUrl($site_url = false) {
// additional check for some sites running inside a virtual machine or behind
// proxy where there could be different ports (e.g., host:8080 => guest:80)
$custom_cron_url = WPHooks::applyFilters('mailpoet_cron_request_url', null);
if($custom_cron_url) return $custom_cron_url;
$site_url = ($site_url) ? $site_url : home_url();
$parsed_url = parse_url($site_url);
$scheme = '';

View File

@ -13,7 +13,6 @@ class Daemon {
public $daemon;
public $request_data;
public $timer;
const REQUEST_TIMEOUT = 5; // seconds
function __construct($request_data = false) {
$this->request_data = $request_data;
@ -100,7 +99,7 @@ class Daemon {
}
function callSelf() {
CronHelper::accessDaemon($this->token, self::REQUEST_TIMEOUT);
CronHelper::accessDaemon($this->token);
return $this->terminateRequest();
}

View File

@ -5,6 +5,7 @@ use MailPoet\Models\Subscriber;
use MailPoet\Models\Setting;
use MailPoet\Router\Endpoints\CronDaemon;
use MailPoet\Router\Router;
use MailPoet\Services\Bridge;
if(!defined('ABSPATH')) exit;
@ -20,12 +21,14 @@ class Beacon {
CronDaemon::ACTION_PING
);
$cron_ping_url = str_replace(home_url(), CronHelper::getSiteUrl(), $cron_ping_url);
$premium_key = Setting::getValue(Bridge::PREMIUM_KEY_SETTING_NAME) ?: Setting::getValue(Bridge::API_KEY_SETTING_NAME);
return array(
'name' => $current_user->display_name,
'email' => $current_user->user_email,
'PHP version' => PHP_VERSION,
'MailPoet Free version' => MAILPOET_VERSION,
'MailPoet Premium version' => (defined('MAILPOET_PREMIUM_VERSION')) ? MAILPOET_PREMIUM_VERSION : 'N/A',
'MailPoet Premium/MSS key' => $premium_key,
'WordPress version' => get_bloginfo('version'),
'Database version' => $db_version,
'Web server' => (!empty($_SERVER["SERVER_SOFTWARE"])) ? $_SERVER["SERVER_SOFTWARE"] : 'N/A',

View File

@ -97,10 +97,10 @@ class WP {
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
UPDATE IGNORE %s
JOIN %susers as wu ON %s.wp_user_id = wu.id
JOIN %s as wu ON %s.wp_user_id = wu.id
SET email = user_email
WHERE %s.wp_user_id IS NOT NULL
', $subscribers_table, $wpdb->prefix, $subscribers_table, $subscribers_table));
', $subscribers_table, $wpdb->users, $subscribers_table, $subscribers_table));
}
private static function insertSubscribers() {
@ -108,10 +108,10 @@ class WP {
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
INSERT IGNORE INTO %s(wp_user_id, email, status, created_at)
SELECT wu.id, wu.user_email, "subscribed", CURRENT_TIMESTAMP() FROM %susers wu
SELECT wu.id, wu.user_email, "subscribed", CURRENT_TIMESTAMP() FROM %s wu
LEFT JOIN %s mps ON wu.id = mps.wp_user_id
WHERE mps.wp_user_id IS NULL
', $subscribers_table, $wpdb->prefix, $subscribers_table));
', $subscribers_table, $wpdb->users, $subscribers_table));
}
private static function updateFirstNames() {
@ -119,11 +119,11 @@ class WP {
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
UPDATE %s
JOIN %susermeta as wpum ON %s.wp_user_id = wpum.user_id AND meta_key = "first_name"
JOIN %s as wpum ON %s.wp_user_id = wpum.user_id AND meta_key = "first_name"
SET first_name = meta_value
WHERE %s.first_name = ""
AND %s.wp_user_id IS NOT NULL
', $subscribers_table, $wpdb->prefix, $subscribers_table, $subscribers_table, $subscribers_table));
', $subscribers_table, $wpdb->usermeta, $subscribers_table, $subscribers_table, $subscribers_table));
}
private static function updateLastNames() {
@ -131,11 +131,11 @@ class WP {
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
UPDATE %s
JOIN %susermeta as wpum ON %s.wp_user_id = wpum.user_id AND meta_key = "last_name"
JOIN %s as wpum ON %s.wp_user_id = wpum.user_id AND meta_key = "last_name"
SET last_name = meta_value
WHERE %s.last_name = ""
AND %s.wp_user_id IS NOT NULL
', $subscribers_table, $wpdb->prefix, $subscribers_table, $subscribers_table, $subscribers_table));
', $subscribers_table, $wpdb->usermeta, $subscribers_table, $subscribers_table, $subscribers_table));
}
private static function updateFristNameIfMissing() {
@ -143,11 +143,11 @@ class WP {
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
UPDATE %s
JOIN %susers wu ON %s.wp_user_id = wu.id
JOIN %s wu ON %s.wp_user_id = wu.id
SET first_name = display_name
WHERE %s.first_name = ""
AND %s.wp_user_id IS NOT NULL
', $subscribers_table, $wpdb->prefix, $subscribers_table, $subscribers_table, $subscribers_table));
', $subscribers_table, $wpdb->users, $subscribers_table, $subscribers_table, $subscribers_table));
}
private static function insertUsersToSegment() {
@ -157,14 +157,14 @@ class WP {
Subscriber::raw_execute(sprintf('
INSERT IGNORE INTO %s(subscriber_id, segment_id, created_at)
SELECT mps.id, "%s", CURRENT_TIMESTAMP() FROM %s mps
WHERE mps.wp_user_id IS NOT NULL
WHERE mps.wp_user_id > 0
', $wp_mailpoet_subscriber_segment_table, $wp_segment->id, $subscribers_table));
}
private static function removeFromTrash() {
$subscribers_table = Subscriber::$_table;
Subscriber::raw_execute(sprintf('
UPDATE %s
UPDATE %s
SET deleted_at = NULL
WHERE %s.wp_user_id IS NOT NULL
', $subscribers_table, $subscribers_table));
@ -175,13 +175,13 @@ class WP {
// e.g. if wp users were deleted directly from the database
global $wpdb;
Subscriber::table_alias('wpms')
->leftOuterJoin($wpdb->prefix . 'users', array('wpms.wp_user_id', '=', 'wu.id'), 'wu')
$wp_segment = Segment::getWPSegment();
$wp_segment->subscribers()
->leftOuterJoin($wpdb->users, array(MP_SUBSCRIBERS_TABLE . '.wp_user_id', '=', 'wu.id'), 'wu')
->whereNull('wu.id')
->findResultSet()
->set('wp_user_id', null)
->delete();
}
}

View File

@ -1,4 +1,5 @@
<?php
namespace MailPoet\Twig;
use MailPoet\Analytics\Reporter;
@ -7,11 +8,6 @@ use MailPoet\Analytics\Analytics as AnalyticsGenerator;
if(!defined('ABSPATH')) exit;
class Analytics extends \Twig_Extension {
public function getName() {
return 'analytics';
}
public function getFunctions() {
$analytics = new AnalyticsGenerator(new Reporter());
return array(

View File

@ -1,25 +1,16 @@
<?php
namespace MailPoet\Twig;
use MailPoet\Config\Env;
namespace MailPoet\Twig;
if(!defined('ABSPATH')) exit;
class Assets extends \Twig_Extension implements \Twig_Extension_GlobalsInterface {
class Assets extends \Twig_Extension {
private $_globals;
function __construct($globals) {
$this->_globals = $globals;
}
function getName() {
return 'assets';
}
function getGlobals() {
return $this->_globals;
}
function getFunctions() {
return array(
new \Twig_SimpleFunction(

View File

@ -7,11 +7,6 @@ use MailPoet\Config\ServicesChecker;
if(!defined('ABSPATH')) exit;
class Functions extends \Twig_Extension {
function getName() {
return 'functions';
}
function getFunctions() {
return array(
new \Twig_SimpleFunction(
@ -173,4 +168,4 @@ class Functions extends \Twig_Extension {
function isRtl() {
return is_rtl();
}
}
}

View File

@ -1,23 +1,23 @@
<?php
namespace MailPoet\Twig;
if(!defined('ABSPATH')) exit;
class Handlebars extends \Twig_Extension {
public function getName() {
return 'handlebars';
}
public function getFunctions() {
return array(
new \Twig_SimpleFunction(
'partial',
array($this, 'generatePartial'),
array(
$this,
'generatePartial'
),
array(
'needs_environment' => true,
'needs_context' => true,
'is_safe' => array('all'))
'needs_context' => true,
'is_safe' => array('all')
)
)
);
}
@ -41,23 +41,28 @@ class Handlebars extends \Twig_Extension {
return;
}
$output = array();
$rendered_template = twig_include($env, $context, $file);
$output[] = '<script id="'.$id.'" type="text/x-handlebars-template">';
$output[] = twig_include($env, $context, $file);
$output[] = '</script>';
$output = <<<EOL
<script id="$id" type="text/x-handlebars-template">
$rendered_template
</script>
EOL;
if($alias !== null) {
$output[] = '<script type="text/javascript">';
$output[] = 'jQuery(function($) {';
$output[] = '$(function() {';
$output[] = ' Handlebars.registerPartial(
"'.$alias.'",
jQuery("#'.$id.'").html());';
$output[] = '});';
$output[] = '});';
$output[] = '</script>';
$output .= <<<EOL
<script type="text/javascript">
jQuery(function($) {
$(function() {
Handlebars.registerPartial(
'$alias',
jQuery('#$id').html()
);
});
});
</script>
EOL;
}
return join("\n", $output);
return $output;
}
}

View File

@ -1,14 +1,10 @@
<?php
namespace MailPoet\Twig;
if(!defined('ABSPATH')) exit;
class Helpscout extends \Twig_Extension {
public function getName() {
return 'helpscout';
}
public function getFunctions() {
return array(
new \Twig_SimpleFunction(

View File

@ -1,4 +1,5 @@
<?php
namespace MailPoet\Twig;
if(!defined('ABSPATH')) exit;
@ -12,10 +13,6 @@ class I18n extends \Twig_Extension {
$this->_text_domain = $text_domain;
}
function getName() {
return 'i18n';
}
function getFunctions() {
// twig custom functions
$twig_functions = array();

View File

@ -4,7 +4,7 @@ if(!defined('ABSPATH')) exit;
/*
* Plugin Name: MailPoet 3 (new)
* Version: 3.0.0-rc.2.0.3
* Version: 3.0.0
* Plugin URI: http://www.mailpoet.com
* Description: Create and send newsletters, post notifications and welcome emails from your WordPress.
* Author: MailPoet
@ -21,7 +21,7 @@ if(!defined('ABSPATH')) exit;
*/
$mailpoet_plugin = array(
'version' => '3.0.0-rc.2.0.3',
'version' => '3.0.0',
'filename' => __FILE__,
'path' => dirname(__FILE__),
'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',

View File

@ -1,42 +1,53 @@
=== MailPoet 3 (new) ===
=== MailPoet 3 (New) ===
Contributors: mailpoet, wysija
Tags: newsletter, email, welcome email, post notification, autoresponder, signup, subscription, SMTP
Requires at least: 4.6
Tested up to: 4.8
Requires PHP: 5.3
Stable tag: 3.0.0-rc.2.0.3
Stable tag: 3.0.0
License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.html
Create and send beautiful emails and newsletters from WordPress.
== Description ==
This is the release candidate of our completely new email newsletter plugin.
The new MailPoet is here! With our new free sending plan, send unlimited emails to up to 2,000 subscribers. All without ever leaving WordPress.
= What's new? =
= What's inside? =
* New designer
* Responsive templates
* Send with MailPoet (optional)
* New designer with responsive templates
* Send your emails with MailPoets Sending Service (optional)
* Improved user experience
* Easier configuration
* Easy configuration
* Solid reliability
* Import subscribers, lists, forms and settings from old MailPoet
* Weekly releases
= See it in action. =
[Test the demo](http://demo3.mailpoet.com/launch/) or [see the 2 min. video](https://vimeo.com/223581490)
[vimeo https://vimeo.com/223581490]
= What is a release candidate? =
= Before you install =
MailPoet version 3 is considered production ready and will soon replace version 2 officially. It's fully featured, stable and supported. We only expect minor issues. Further notes:
Take note:
* Not optimized for right-to-left (RTL) languages yet
* Multisite works, but is not officially supported
* Please check the translations in your language
* Review [our minimum requirements](http://beta.docs.mailpoet.com/article/152-minimum-requirements-for-mailpoet-3)
* Weekly releases with bug fixes and improvements
* Report bugs directly from the user interface
* Not optimized for right-to-left (RTL) languages, but it works
* Multisite works but is not officially supported
= What about the Premium? =
= Premium version available =
MailPoet is fully featured in its free version and works up until you have 2000 subscribers.
[Get in touch](https://www.mailpoet.com/support/sales-pre-sales-questions/) if you are an existing customer and you want to switch.
The Premium version adds the following features:
* for each newsletter, see which subscribers opened it and which links they clicked
* ability to send Welcome Emails automatically; i.e. "Welcome to my Newsletter” autoresponders or multi-email courses
* removes the small MailPoet logo in the footer of your emails
* same day support (Monday to Friday)
* send to over 2000 subscribers with your own sending method
* see the [short video summary on the Premium](http://beta.docs.mailpoet.com/article/208-video-overview-of-mailpoet-premium)
Plus: if you sign up to one of our sending plans, youll get all of these fancy features for free. Visit the Premium page inside the plugin for more info.
= Translations =
@ -50,8 +61,15 @@ MailPoet version 3 is considered production ready and will soon replace version
* Russian
* Japanese
* Persian (IR)
* Norwegian
* Swedish
* Turkish
We welcome translators to translate directly on [our Transifex project](https://www.transifex.com/wysija/mp3/). Please note that any translations submitted via the "Translating WordPress" web site will not work!
We welcome experienced translators to translate directly on [our Transifex project](https://www.transifex.com/wysija/mp3/). Please note that any translations submitted via the "Translating WordPress" web site will not work.
= Security =
[Security audits are made by LogicalTrust](https://logicaltrust.net/en/), an independent third party.
== Installation ==
@ -60,7 +78,7 @@ There are 3 ways to install this plugin:
= 1. The super easy way =
1. In your WordPress dashboard, navigate to Plugins > Add New
1. Search for `MailPoet`
1. Click on "install now" under "MailPoet 3 Beta Version"
1. Click on "install now"
1. Activate the plugin
1. A new `MailPoet` menu will appear in your WordPress dashboard
@ -82,7 +100,7 @@ There are 3 ways to install this plugin:
= Need help? =
Our [support site](https://beta.docs.mailpoet.com) has plenty of articles. You can write to us on the forums too.
Stop by our [support site](https://www.mailpoet.com/support).
== Screenshots ==
@ -94,6 +112,11 @@ Our [support site](https://beta.docs.mailpoet.com) has plenty of articles. You c
== Changelog ==
= 3.0.0 - 2017-09-20 =
* Official launch of the new MailPoet. :)
* Improved: MailPoet 3 now works with other plugins that use a supported version of Twig templating engine. Thanks @supsysticcom;
* Added: we now offer a free sending plan for 2000 subscribers or less. Thx MailPoet!
= 3.0.0-rc.2.0.3 - 2017-09-12 =
* Added: hook to override default cron URL. Thanks Fred;
* Improved: WordPress user sync optimized for large membership sites; Thanks Nagui and @deltafactory!

View File

@ -289,7 +289,7 @@ class StringExtractor {
$arguments = array();
foreach($arguments_matches[0] as $argument) {
// Remove surrounding quotes of the same type from argument strings
$arguments[] = preg_replace("/^(('|\")+)(.*)\\1$/", "\\3", $argument);
$arguments[] = preg_replace("/^(('|\")+)(.*)\\1$/", "\\3", stripslashes($argument));
}
$call = array(

View File

@ -99,7 +99,7 @@ class APITest extends \MailPoetTest {
}
}
function testItSubscriberSubscriberToMultupleLists() {
function testItSubscribesSubscriberToMultupleLists() {
$subscriber = Subscriber::create();
$subscriber->hydrate(Fixtures::get('subscriber_template'));
$subscriber->save();
@ -111,7 +111,7 @@ class APITest extends \MailPoetTest {
);
$result = API::MP(self::VERSION)->subscribeToLists($subscriber->id, array($segment->id));
expect($result['id'])->equals($subscriber->id);
expect($result['subscriptions'][0]['id'])->equals($segment->id);
expect($result['subscriptions'][0]['segment_id'])->equals($segment->id);
}
function testItSubscribesSubscriberToSingleList() {
@ -127,7 +127,7 @@ class APITest extends \MailPoetTest {
$result = API::MP(self::VERSION)->subscribeToList($subscriber->id, $segment->id);
expect($result['id'])->equals($subscriber->id);
expect($result['subscriptions'])->notEmpty();
expect($result['subscriptions'][0]['id'])->equals($segment->id);
expect($result['subscriptions'][0]['segment_id'])->equals($segment->id);
}
function testItSubscribesSubscriberWithEmailIdentifier() {
@ -143,7 +143,7 @@ class APITest extends \MailPoetTest {
$result = API::MP(self::VERSION)->subscribeToList($subscriber->email, $segment->id);
expect($result['id'])->equals($subscriber->id);
expect($result['subscriptions'])->notEmpty();
expect($result['subscriptions'][0]['id'])->equals($segment->id);
expect($result['subscriptions'][0]['segment_id'])->equals($segment->id);
}
function testItGetsSegments() {
@ -242,7 +242,7 @@ class APITest extends \MailPoetTest {
$result = API::MP(self::VERSION)->addSubscriber($subscriber, array($segment->id));
expect($result['id'])->greaterThan(0);
expect($result['email'])->equals($subscriber['email']);
expect($result['subscriptions'][0]['id'])->equals($segment->id);
expect($result['subscriptions'][0]['segment_id'])->equals($segment->id);
}
function testItSchedulesWelcomeNotificationByDefaultAfterAddingSubscriber() {
@ -325,4 +325,4 @@ class APITest extends \MailPoetTest {
\ORM::raw_execute('TRUNCATE ' . Segment::$_table);
\ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
}
}
}

View File

@ -1,8 +1,12 @@
<?php
namespace MailPoet\Test\Config;
use MailPoet\Config\Hooks;
class HooksTest extends \MailPoetTest {
function testItHooksSchedulerToMultiplePostTypes() {
$hooks = new Hooks();
$hooks->setupPostNotifications();
$post_types = get_post_types();
foreach($post_types as $post_type) {
expect(has_filter('publish_' . $post_type, '\MailPoet\Newsletter\Scheduler\Scheduler::schedulePostNotification'))->notEmpty();

View File

@ -2,9 +2,9 @@
namespace MailPoet\Test\Cron;
use AspectMock\Test as Mock;
use MailPoet\Cron\CronHelper;
use MailPoet\Models\Setting;
use MailPoet\WP\Hooks;
class CronHelperTest extends \MailPoetTest {
function _before() {
@ -14,7 +14,7 @@ class CronHelperTest extends \MailPoetTest {
function testItDefinesConstants() {
expect(CronHelper::DAEMON_EXECUTION_LIMIT)->equals(20);
expect(CronHelper::DAEMON_EXECUTION_TIMEOUT)->equals(35);
expect(CronHelper::DAEMON_REQUEST_TIMEOUT)->equals(2);
expect(CronHelper::DAEMON_REQUEST_TIMEOUT)->equals(5);
expect(CronHelper::DAEMON_SETTING)->equals('cron_daemon');
}
@ -74,38 +74,30 @@ class CronHelperTest extends \MailPoetTest {
function testItCreatesRandomToken() {
// random token is a string of 5 characters
$token1 = CronHelper::createToken();
$token2 = CronHelper::createToken();
$token1 = CronHelper::createToken();
$token2 = CronHelper::createToken();
expect($token1)->notEquals($token2);
expect(is_string($token1))->true();
expect(strlen($token1))->equals(5);
}
function testItGetsSiteUrl() {
// 1. do nothing when the url is manually overridden via a hook
$filter = function() {
return 'custom_url';
};
add_filter('mailpoet_cron_request_url', $filter);
expect(CronHelper::getSiteUrl())->equals('custom_url');
remove_filter('mailpoet_cron_request_url', $filter);
// 2. do nothing when the url does not contain port
// 1. do nothing when the url does not contain port
$site_url = 'http://example.com';
expect(CronHelper::getSiteUrl($site_url))->equals($site_url);
if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return;
// 3. when url contains valid port, try connecting to it
// 2. when url contains valid port, try connecting to it
$site_url = 'http://example.com:80';
expect(CronHelper::getSiteUrl($site_url))->equals($site_url);
// 4. when url contains invalid port, try connecting to it. when connection fails,
// 3. when url contains invalid port, try connecting to it. when connection fails,
// another attempt will be made to connect to the standard port derived from URL schema
$site_url = 'http://example.com:8080';
expect(CronHelper::getSiteUrl($site_url))->equals('http://example.com');
// 5. when connection can't be established, exception should be thrown
// 4. when connection can't be established, exception should be thrown
$site_url = 'https://invalid:80';
try {
CronHelper::getSiteUrl($site_url);
@ -126,12 +118,49 @@ class CronHelperTest extends \MailPoetTest {
}
}
function testItAllowsSettingCustomCronUrl() {
$filter = function($url) {
expect($url)->contains('&endpoint=cron');
return 'http://custom_cron_url';
};
add_filter('mailpoet_cron_request_url', $filter);
expect(CronHelper::getCronUrl('sample_action'))->equals('http://custom_cron_url');
remove_filter('mailpoet_cron_request_url', $filter);
}
function testItAllowsSettingCustomCronRequestArguments() {
$request_args = array(
'blocking' => 'custom_blocking',
'sslverify' => 'custom_ssl_verify',
'timeout' => 'custom_timeout',
'user-agent' => 'custom_user_agent'
);
$filter = function($args) use ($request_args) {
expect($args)->notEmpty();
return $request_args;
};
add_filter('mailpoet_cron_request_args', $filter);
Mock::func('MailPoet\Cron', 'wp_remote_get', function($url, $args) {
return $args;
});
expect(CronHelper::queryCronUrl('test'))->equals($request_args);
remove_filter('mailpoet_cron_request_args', $filter);
}
function testItReturnsErrorMessageAsPingResponseWhenCronUrlCannotBeAccessed() {
Mock::double('MailPoet\Cron\CronHelper', array(
'getSiteUrl' => false
));
expect(CronHelper::pingDaemon())->equals('A valid URL was not provided.');
}
function testItPingsDaemon() {
if(getenv('WP_TEST_ENABLE_NETWORK_TESTS') !== 'true') return;
expect(CronHelper::pingDaemon())->equals('pong');
}
function _after() {
Mock::clean();
\ORM::raw_execute('TRUNCATE ' . Setting::$_table);
}
}

View File

@ -7,10 +7,6 @@ use MailPoet\Cron\Daemon;
use MailPoet\Models\Setting;
class DaemonTest extends \MailPoetTest {
function testItDefinesConstants() {
expect(Daemon::REQUEST_TIMEOUT)->equals(5);
}
function testItConstructs() {
Setting::setValue(
CronHelper::DAEMON_SETTING,

View File

@ -4,6 +4,7 @@ namespace MailPoet\Test\Helpscout;
use MailPoet\Helpscout\Beacon;
use MailPoet\Models\Setting;
use MailPoet\Models\Subscriber;
use MailPoet\Services\Bridge;
class BeaconTest extends \MailPoetTest {
function _before() {
@ -130,4 +131,10 @@ class BeaconTest extends \MailPoetTest {
(defined('MAILPOET_PREMIUM_VERSION')) ? MAILPOET_PREMIUM_VERSION : 'N/A'
);
}
}
function testItReturnsPremiumKey() {
expect($this->beacon_data['MailPoet Premium/MSS key'])->equals(
Setting::getValue(Bridge::PREMIUM_KEY_SETTING_NAME) ?: Setting::getValue(Bridge::API_KEY_SETTING_NAME)
);
}
}

View File

@ -7,6 +7,7 @@ require_once(ABSPATH . 'wp-admin/includes/user.php');
use Carbon\Carbon;
use MailPoet\Models\Segment;
use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberSegment;
use MailPoet\Segments\WP;
class WPTest extends \MailPoetTest {
@ -67,6 +68,15 @@ class WPTest extends \MailPoetTest {
expect($subscriber->first_name)->equals('First name');
}
function testItSynchronizeFirstNamesFromMetaNotDisplayName() {
$id = $this->insertUser();
update_user_meta($id, 'first_name', 'First name');
$this->updateWPUserDisplayName($id, 'display_name');
WP::synchronizeUsers();
$subscriber = Subscriber::where('wp_user_id', $id)->findOne();
expect($subscriber->first_name)->equals('First name');
}
function testItSynchronizeSegment() {
$this->insertUser();
$this->insertUser();
@ -108,6 +118,54 @@ class WPTest extends \MailPoetTest {
expect($subscribers->count())->equals(1);
}
function testItDoesntDeleteNonWPData() {
$this->insertUser();
// wp_user_id is null
$subscriber = Subscriber::create();
$subscriber->hydrate(array(
'first_name' => 'John',
'last_name' => 'John',
'email' => 'user-sync-test' . rand() . '@example.com',
));
$subscriber->status = Subscriber::STATUS_UNCONFIRMED;
$subscriber->save();
// wp_user_id is zero
$subscriber2 = Subscriber::create();
$subscriber2->hydrate(array(
'first_name' => 'Mike',
'last_name' => 'Mike',
'email' => 'user-sync-test2' . rand() . '@example.com',
'wp_user_id' => 0,
));
$subscriber2->status = Subscriber::STATUS_SUBSCRIBED;
$subscriber2->save();
WP::synchronizeUsers();
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(3);
}
function testItRemovesSubscribersInWPSegmentWithoutWPId() {
$subscriber = Subscriber::create();
$subscriber->hydrate(array(
'first_name' => 'Mike',
'last_name' => 'Mike',
'email' => 'user-sync-test' . rand() . '@example.com',
'wp_user_id' => null,
));
$subscriber->status = Subscriber::STATUS_SUBSCRIBED;
$subscriber->save();
$wp_segment = Segment::getWPSegment();
$association = SubscriberSegment::create();
$association->subscriber_id = $subscriber->id;
$association->segment_id = $wp_segment->id;
$association->save();
$subscribersCount = $this->getSubscribersCount();
expect($subscribersCount)->equals(1);
WP::synchronizeUsers();
$subscribersCount = $this->getSubscribersCount(0);
expect($subscribersCount)->equals(0);
}
function _before() {
$this->cleanData();
}
@ -118,18 +176,37 @@ class WPTest extends \MailPoetTest {
private function cleanData() {
\ORM::raw_execute('TRUNCATE ' . Segment::$_table);
\ORM::raw_execute('TRUNCATE ' . SubscriberSegment::$_table);
global $wpdb;
$db = \ORM::getDb();
$db->exec(sprintf('
DELETE FROM
%susers
%s
WHERE
subscriber_id IN (select id from %s WHERE email LIKE "user-sync-test%%")
', SubscriberSegment::$_table, Subscriber::$_table));
$db->exec(sprintf('
DELETE FROM
%s
WHERE
user_id IN (select id from %s WHERE user_email LIKE "user-sync-test%%")
', $wpdb->usermeta, $wpdb->users));
$db->exec(sprintf('
DELETE FROM
%s
WHERE
user_email LIKE "user-sync-test%%"
', $wpdb->prefix));
', $wpdb->users));
$db->exec(sprintf('
DELETE FROM
%s
WHERE
email LIKE "user-sync-test%%"
', Subscriber::$_table));
}
private function getSubscribersCount() {
return Subscriber::whereIn("wp_user_id", $this->userIds)->count();
private function getSubscribersCount($a = null) {
return Subscriber::whereLike("email", "user-sync-test%")->count();
}
/**
@ -143,14 +220,14 @@ class WPTest extends \MailPoetTest {
global $wpdb;
$db = \ORM::getDb();
$db->exec(sprintf('
INSERT INTO
%susers(user_login, user_email, user_registered)
VALUES
INSERT INTO
%s (user_login, user_email, user_registered)
VALUES
(
CONCAT("user-sync-test", rand()),
CONCAT("user", rand(), "@example.com"),
CONCAT("user-sync-test", rand()),
CONCAT("user-sync-test", rand(), "@example.com"),
"2017-01-02 12:31:12"
)', $wpdb->prefix));
)', $wpdb->users));
$id = $db->lastInsertId();
$this->userIds[] = $id;
return $id;
@ -161,11 +238,11 @@ class WPTest extends \MailPoetTest {
$db = \ORM::getDb();
$db->exec(sprintf('
UPDATE
%susers
%s
SET user_email = "%s"
WHERE
id = %s
', $wpdb->prefix, $email, $id));
', $wpdb->users, $email, $id));
}
private function updateWPUserDisplayName($id, $name) {
@ -173,11 +250,11 @@ class WPTest extends \MailPoetTest {
$db = \ORM::getDb();
$db->exec(sprintf('
UPDATE
%susers
%s
SET display_name = "%s"
WHERE
id = %s
', $wpdb->prefix, $name, $id));
', $wpdb->users, $name, $id));
}
private function deleteWPUser($id) {
@ -185,10 +262,10 @@ class WPTest extends \MailPoetTest {
$db = \ORM::getDb();
$db->exec(sprintf('
DELETE FROM
%susers
%s
WHERE
id = %s
', $wpdb->prefix, $id));
', $wpdb->users, $id));
}
}

View File

@ -61,12 +61,7 @@
>
<div class="mailpoet_sending_method_description">
<h3>
<img
src="<%= assets_url %>/img/mailpoet_logo.png"
alt="MailPoet"
width="137"
height="54"
/>
<%= __('MailPoet Sending Service') %>
</h3>
<p
@ -83,19 +78,26 @@
id="mailpoet_sending_method_inactive_text"
>
<strong><%= __("Solve all of your sending problems!") %></strong>
<br />
<%= __("Let MailPoet send your emails and get the Premium features for as little as 10 dollars or euros per month.") %>
<ul class="sending-method-benefits mailpoet_success">
<li class="mailpoet_success_item"><%= __('Reach the inbox, not the spam box.') %>
<li class="mailpoet_success_item"><%= __('Send emails up to 20 times faster than other sending methods.') %>
<li class="mailpoet_success_item"><%= __('SPF & DKIM signatures are already set up! No configuration required.') %>
<li class="mailpoet_success_item"><%= __('Super fast: send up to 50,000 emails per hour.') %>
<li class="mailpoet_success_item"><%= __('All emails are signed with SPF & DKIM.') %>
<li class="mailpoet_success_item"><%= __('Automatically remove invalid and bounced addresses (bounce handling) to keep your lists clean.') %>
<li class="mailpoet_success_item"><%= __('Configuration is dead-simple: simply enter a key to activate the sending service.') %>
<li class="mailpoet_success_item"><strong><%= __('Coming soon:')%></strong> <%= __('MailPoet will send your WordPress site and account emails, too!') %>
<li class="mailpoet_success_item"><strong><%= __('Plus:')%></strong> <%= __('get the Premium features for free.') %>
</li>
</ul>
<a
href="<%= admin_url('admin.php?page=mailpoet-premium') %>"
class="button button-primary"
target="_blank"
><%= __('Find out more') %></a>
><%= __('Find out more about our monthly plans') %></a>
<a href="https://www.mailpoet.com/free-plan/" class="button button-primary sending-free-plan-button" target="_blank">
<strong><%= __('new!') %></strong> <%= __('Try it for free (for up to 2,000 subscribers)') %>
</a>
</div>
</div>
<div class="mailpoet_status">
@ -118,14 +120,17 @@
<div class="mailpoet_sending_method_description">
<h3><%= __('Other') %></h3>
<div class="mailpoet_description">
<strong><%= __('Send with your website or third party') %></strong>
<br />
<%= __('Choose to send emails through your website (not recommended) or a third party sender.') %>
<strong><%= __('Send emails via your host (not recommended!) or via a third-party sender.') %></strong>
<ul class="sending-method-benefits mailpoet_error">
<li class="mailpoet_error_item"><%= __("You'll probably end up in spam.") %>
<li class="mailpoet_error_item"><%= __('Sending speed is limited by your web host.') %>
<li class="mailpoet_error_item"><%= __('Manual configuration of SPF and DKIM required.') %>
<li class="mailpoet_error_item"><%= __('Bounce handling is available, but only with an extra add-on.') %>
<li class="mailpoet_error_item"><%= __("Unless you're a pro, youll probably end up in spam.") %>
<li class="mailpoet_error_item"><%= __("Sending speed is limited by your host and/or your third-party (with a 2,000 per hour maximum).") %>
<li class="mailpoet_error_item"><%= __("Manual configuration of SPF and DKIM required.") %>
<li class="mailpoet_error_item"><%=
__("Bounce handling is available, but only with an extra [link]add-on[/link].")
|replaceLinkTags('https://wordpress.org/plugins/bounce-handler-mailpoet/', {'target' : '_blank'})
|raw
%>
<li class="mailpoet_error_item"><%= __("Youll need a separate plugin to send your WordPress site emails (optional).") %>
</ul>
</div>
</div>

View File

@ -6,7 +6,7 @@
<h1><%= __('Greetings, humans.') %></h1>
<p class="about-text"><%= __('Thanks for using MailPoet! We really appreciate all of your love, affection, [link]and (good) plugin reviews.[/link]')
|replaceLinkTags('https://wordpress.org/support/plugin/wysija-newsletters/reviews/', {'target' : '_blank'})
|replaceLinkTags('https://wordpress.org/support/plugin/mailpoet/reviews/', {'target' : '_blank'})
|raw
%>
</p>
@ -60,8 +60,18 @@
<div class="feature-section one-col mailpoet_centered">
<h2><%= __('Care to Give Your Opinion?') %></h2>
<script type="text/javascript" charset="utf-8" src="//secure.polldaddy.com/p/9801036.js"></script>
<noscript><a href="//polldaddy.com/poll/9801036/">Should MailPoet include more default templates?</a></noscript>
<div class="pd-embed" id="pd_1505214143"></div>
<script type="text/javascript">
var _polldaddy = [] || _polldaddy;
_polldaddy.push( {
type: "iframe",
auto: "1",
domain: "mailpoet.polldaddy.com/s/",
id: "what-s-one-feature-that-s-missing-in-mailpoet",
placeholder: "pd_1505214143"
} );
(function(d,c,j){if(!document.getElementById(j)){var pd=d.createElement(c),s;pd.id=j;pd.src=('https:'==document.location.protocol)?'https://polldaddy.com/survey.js':'http://i0.poll.fm/survey.js';s=document.getElementsByTagName(c)[0];s.parentNode.insertBefore(pd,s);}}(document,'script','pd-embed'));
</script>
</div>
<hr>

View File

@ -6,7 +6,7 @@
<h1><%= __('Greetings, humans.') %></h1>
<p class="about-text"><%= __('Thanks for using MailPoet! We really appreciate all of your love, affection, [link]and (good) plugin reviews.[/link]')
|replaceLinkTags('https://wordpress.org/support/plugin/wysija-newsletters/reviews/', {'target' : '_blank'})
|replaceLinkTags('https://wordpress.org/support/plugin/mailpoet/reviews/', {'target' : '_blank'})
|raw
%>
</p>
@ -17,9 +17,32 @@
<a href="admin.php?page=mailpoet-update" class="nav-tab"><%= __("What's new") %></a>
</h2>
<% set random = random(2) %>
<div <% if random != 0 %>style="display: none;"<% endif %>>
<h2><%= __('Coming this Fall to a WordPress plugin page near you') %></h2>
<p class="about-text mailpoet_centered mailpoet-top-text"><%= __('The highly-anticipated sequel to Dead Poets Society, Introduction to MailPoet will keep you on the edge of your seat.
“Five out of five stars,” says Rafael Ehlers, MailPoet Support Manager.
“A must-watch for aspiring email poets.”') %>
</div>
<div <% if random != 1 %>style="display: none;"<% endif %>>
<h2><%= __('But first, watch this video') %></h2>
<p class="about-text mailpoet_centered mailpoet-top-text"><%= __('Wait a second. Dont click that big blue button just yet.
Yeah, were talking to you. Before you do anything, you should really watch this video.
It wont change your life, but it will save you (and our support team) a ton of time.
And what is life without time? So, maybe it is life-changing, after all…') %>
</div>
<div <% if random != 2 %>style="display: none;"<% endif %>>
<h2><%= __('Explanatory videos are boring, we know') %></h2>
<p class="about-text mailpoet_centered mailpoet-top-text"><%= __('But this video is really important!
We promise. Over the course of three minutes, youll learn how to send your first newsletter,
manage your lists, make billions of dollars and live happily ever after.
Thats right its that good. So get watching.') %>
</div>
<div class="headline-feature feature-video">
<div class="videoWrapper">
<iframe width="1050" height="591" src="https://player.vimeo.com/video/184501111?title=0&byline=0&portrait=0" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
<iframe width="1050" height="591" src="https://player.vimeo.com/video/229737424" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
</div>
</div>
@ -28,13 +51,12 @@
<div class="feature-section two-col">
<h2><%= __('Want to Make MailPoet Even Better?') %></h2>
<div class="col">
<h3><%= __('We Need Your Feedback!') %></h3>
<p><%= __('As a beta tester, you have a very important job: to tell us what you think about this new version. If you love it, tell us! If you hate it, let us know! Any and all feedback is useful.') %></p>
<p><%= __('To get in touch with us, simply click on the blue circle in the bottom right corner of your screen. This button is visible on all MailPoet pages on your WordPress dashboard.') %> <img width="30" style="margin:0" src="<%= image_url('welcome_template/beacon.png') %>" alt="Beacon" /></p>
<h3><%= __('Documentation Is One Click Away') %></h3>
<p><%= __('Simply click on the blue circle in the bottom right corner of any of the MailPoet pages to access our documentation.') %> <em><%= __('Voilà!') %></em>
</div>
<div class="col">
<h3><%= __('Sharing is Caring') %></h3>
<p><%= __("By sharing your data <i>anonymously</i> with us, you can help us understand <i>how people use MailPoet</i> and <i>what sort of features they like and don't like</i>.") %> <a href="http://beta.docs.mailpoet.com/article/130-sharing-your-data-with-us" target="_blank"><%= __('Find out more') %> &rarr;</a>
<p><%= __("By sharing your data <i>anonymously</i> with us, you can help us understand how people use MailPoet and what sort of features they like and don't like.") %> <a href="http://beta.docs.mailpoet.com/article/130-sharing-your-data-with-us" target="_blank"><%= __('Find out more') %> &rarr;</a>
<br><br>
<label>
<input type="checkbox" id="mailpoet_analytics_enabled" value="1"
@ -58,7 +80,7 @@
</div>
<div class="col">
<h3><%= __("Learn the Ropes") %></h3>
<p><%= __("New to MailPoet? Check out our brand new email course. Over the span of 3 weeks, we'll teach you how to create and send your first MailPoet email newsletter. Sign up below!") %></p>
<p><%= __("New to MailPoet? Check out our brand new email course. Over the course of a week, we'll teach you how to create and send your first MailPoet email newsletter. Sign up below!") %></p>
<p>
<iframe width="100%" height="100%" scrolling="no" frameborder="0" src="http://newsletters.mailpoet.com?mailpoet_form_iframe=4" class="mailpoet_form_iframe" vspace="0" tabindex="0" onload="if(window['MailPoet']) MailPoet.Iframe.autoSize(this);" marginwidth="0" marginheight="0" hspace="0" allowtransparency="true"></iframe>
</p>