Compare commits

...

94 Commits

Author SHA1 Message Date
fbeddb8af2 Bump up release version to 3.0.0-beta.4 2016-11-15 12:45:51 +02:00
8c3525589c Merge pull request #708 from mailpoet/editor_shortcodes
Fix URLs containing shortcodes in TinyMCE [MAILPOET-670]
2016-11-14 18:09:16 -05:00
58f97ea43d Merge pull request #711 from mailpoet/issue_645
[MAILPOET-645] Protect some fields from being specified when subscribing
2016-11-14 18:39:27 +02:00
8e4c3ea7ea Merge pull request #710 from mailpoet/subscriber_limit_fix
Fixes total subscriber count [MAILPOET-671]
2016-11-14 17:43:46 +02:00
3865a8e8cd protect some fields from being edit when subscribing 2016-11-14 15:20:18 +01:00
02221f6833 Merge pull request #707 from mailpoet/template_cache
Gracefully display Twig exceptions as error messages [MAILPOET-667]
2016-11-14 10:07:58 +01:00
b63ef8cca0 - Updates total subscriber count to exclude trashed records
- Updates unit test
2016-11-12 19:33:46 -05:00
aabe71d473 - Change TinyMCE to not convert URLs containing shortcodes;
- Refactor TinyMCE calls into reusable Behavior;
MAILPOET-670
2016-11-11 15:30:09 +02:00
1405249712 Merge pull request #706 from mailpoet/issue_644
MAILPOET-644
2016-11-10 12:47:03 -05:00
16ee5e934a Fix typo in property name 2016-11-10 19:17:23 +02:00
74276b45c5 use verifyToken instead of generateToken 2016-11-10 17:50:38 +01:00
b046c9ea4b Gracefully catches Twig exceptions and displays error messages
MAILPOET-667 #time 3h
2016-11-10 16:33:50 +02:00
8bd7f5f169 added token verification when updating subscription 2016-11-10 12:21:20 +01:00
ee119215c0 Merge pull request #705 from mailpoet/issue_646
Mass subscriptions protection + EU laws compliance
2016-11-09 12:54:02 +02:00
c22d3c8957 Renamed 'ip' column to 'subscribed_ip'
- updated code based on PR review
2016-11-09 11:43:08 +01:00
0dd7a3990f Merge pull request #703 from mailpoet/hs_beacon
HelpScout Beacon update
2016-11-08 12:54:06 -05:00
1a6b032943 Added subscription limit in order to avoid mass subscriptions 2016-11-08 17:29:28 +01:00
1220f47d87 Clear vendor files in build before reinstalling production deps 2016-11-08 12:28:55 +02:00
583b34a5c1 Bump up release version to 3.0.0-beta.3 2016-11-08 11:56:18 +02:00
b36d13a087 Merge pull request #699 from mailpoet/php53-fix
Fixes various errors on PHP 5.3.x
2016-11-07 16:48:18 +01:00
1a3aa7a4e4 Merge pull request #701 from mailpoet/rendering_update
Rendering update
2016-11-07 16:27:48 +01:00
70a13a4774 Update helpscout beacon code to include support KB article search 2016-11-07 17:27:28 +02:00
6ce13df2f3 Merge pull request #696 from mailpoet/beacon_report
HS Beacon enhanced report
2016-11-07 15:59:06 +02:00
4eb85c5d7e Merge pull request #697 from mailpoet/php7_compatibility_update
PHP 7.0 compatibility update
2016-11-07 15:40:48 +02:00
6eb6636e8b Merge pull request #694 from mailpoet/newsletter_number_shortcode_fix
Newsletter number shortcode fix
2016-11-07 14:03:01 +02:00
9635fb5365 - Replaces   with spaces in all templates 2016-11-06 20:06:26 -05:00
d4b39cb1f4 - Replaces &nbsp with spaces in text blocks 2016-11-06 20:04:18 -05:00
af36e7a0d9 - Converts template to UTF-8 2016-11-06 20:03:21 -05:00
1db8626e35 - Fixes 'Cannot access self:: when no class scope is active' error in PHP 5.3 2016-11-06 18:55:20 -05:00
61c255564f - Fixes 'Using $this when not in object context' error in PHP 5.3 2016-11-06 18:55:12 -05:00
7e5047d98f - Sets default timezone for CI's PHP configuration
- Prevents PHP Compatibility sniffer from throwing a "default timeezone is
  required" error
2016-11-05 19:54:56 -04:00
4698d5a4db - Indirectly invokes hash_equals() functions. This prevents PHP Compatibility sniffer
from complains about the function not present in <5.6. WP provides a shim for older
  PHP versions in wp-includes/compat.php
2016-11-05 19:54:55 -04:00
864c9cbe95 - Updates code sniffer rules to run PHP Compatibility sniff 2016-11-05 19:54:54 -04:00
011b6f9b3c - Adds PHP Compatibility sniffer dependency
- Updates build script to ignore running post-update|install commands
2016-11-05 19:54:53 -04:00
e45fc0c0a0 - Renames functions that start with underscores (i.e., names reserved by PHP)
- Removes the unused date_format function
2016-11-05 19:54:46 -04:00
6bebdd6e95 - Removes unused PHPMailer dependency 2016-11-05 11:27:58 -04:00
8df4da768a Merge pull request #695 from mailpoet/plugin_activation
Fix Populator in plugin activation
2016-11-04 17:56:59 +01:00
67f4c21aa8 Fix coding standard issue - extra space after foreach 2016-11-04 17:00:10 +02:00
5eba0e2731 Fix referencing $this in anonymous function context 2016-11-04 17:00:10 +02:00
3efa429a1b - Updates newsletters listing to display rendered subject for post
notification history emails
2016-11-04 09:51:50 -04:00
3a78441a83 Merge pull request #691 from mailpoet/editor_fixes
Fitting text in template selection boxes
2016-11-04 09:38:28 -04:00
c05be7d987 remove useless comment (containing a typo on top of that...) 2016-11-04 14:14:48 +01:00
b8cb1da777 added custom information to HS Beacon 2016-11-04 14:11:37 +01:00
ac8d1d808f Merge pull request #689 from mailpoet/index_files
Adds folder index files
2016-11-04 11:21:03 +01:00
9cd7b1a204 - Updates unit tests
- Addresses #628 (3)
2016-11-03 20:56:25 -04:00
0d32c09df3 - Replaces model arrays with model objects 2016-11-03 20:45:53 -04:00
9f288ae11a - Removes unused classes
- Fixes [newsletter:number] shortcode not working
2016-11-03 20:38:20 -04:00
e87ccd6b92 - Corrects/updates code comments 2016-11-03 18:11:00 -04:00
8a2b6ac69b Merge pull request #690 from mailpoet/obsolete_dependencies
Remove obsolete JS dependencies
2016-11-03 17:57:56 +01:00
43bd2d4413 Fixes template selection boxes to fit text in different configurations 2016-11-03 18:17:45 +02:00
9fdb99a06b Merge pull request #688 from mailpoet/editor_xss
Reflected XSS in newsletter editor
2016-11-03 16:56:25 +01:00
f3c69c8353 Remove obsolete JS dependencies 2016-11-03 14:29:40 +02:00
29a32d3da9 Enumerate build.sh steps to improve visibility for any issues 2016-11-03 14:12:49 +02:00
8412cc852d Add index files during build to ensure dirs aren't browsable #650 2016-11-03 14:12:12 +02:00
b4e4320508 Fix newsletter editor XSS #638 2016-11-03 13:20:22 +02:00
dbd6e6f310 Remove obsolete JS libraries: d3, c3, swag, xss 2016-11-02 17:12:51 +02:00
bdcb7f0e58 Merge pull request #687 from mailpoet/issue_681_670
fixed HTML export of subscription form + updated docs url in settings
2016-11-02 16:15:07 +02:00
85c9b121f5 Merge pull request #678 from mailpoet/ci_improvements
CI improvements [MAILPOET-618]
2016-11-02 08:46:04 -04:00
069bc95297 fixed HTML export of subscription form + updated docs url in settings 2016-11-02 13:24:55 +01:00
0b711e6341 Add running QA scripts in CI, disable checking for useless overrides 2016-11-02 13:10:23 +02:00
2a961cca01 Eliminate an extra level of indentation 2016-11-02 13:10:23 +02:00
e855fdbbaf Fix composer installation for CI 2016-11-02 13:10:23 +02:00
288464e8cb Change Robo tasks to return error exit codes when they fail 2016-11-02 13:10:23 +02:00
1331ed70f1 Remove phpseclib dependency, which is no longer needed 2016-11-02 13:10:23 +02:00
411188c345 Remove PopulatorData from coverage reports as it's irrelevant 2016-11-02 13:03:15 +02:00
ee275532b1 Merge pull request #679 from mailpoet/secissue_640
XSS in listing sort by
2016-11-02 12:48:40 +02:00
b2eef93516 Merge pull request #685 from mailpoet/issue_489
fixed NaN in sending stats, show 'no subscribers' instead
2016-11-02 12:23:31 +02:00
40ca54c447 sort by defaults to 'id' if invalid 2016-11-02 11:17:27 +01:00
b65db1afbf Merge pull request #684 from mailpoet/issue_639
removed risky file from css-tidy vendor when building
2016-11-02 12:11:29 +02:00
c258b1c3a2 Merge pull request #680 from mailpoet/css_inliner_update
Fixes PHP 7 compatibility issue with CSS  inliner
2016-11-02 11:43:46 +02:00
7a5a726400 removed risky file from css-tidy vendor when building 2016-11-02 10:30:57 +01:00
e553922eca Update composer.lock and remove leftover comment 2016-11-02 11:30:52 +02:00
04e9e8a45d fixed NaN in sending stats, show 'no subscribers' instead 2016-11-02 10:21:02 +01:00
f037e1271d - Removes php-simple-html-dom-parser dependency
- Updates CSS inliner to use pQuery DOM parser
2016-10-31 19:01:48 -04:00
f4563e18cd use filter_var instead of regex 2016-10-31 17:36:53 +01:00
feaac5eb54 constrain sort_by to alphanumeric/underscore in order to avoid xss in error notices 2016-10-31 17:36:53 +01:00
a6059d5bc3 Update to 3.0.0-beta.2 release 2016-10-31 12:45:03 +02:00
f2104ef30f Merge pull request #677 from mailpoet/plugin_description
Updated plugin description
2016-10-31 12:31:43 +02:00
e7f760328e updated plugin description 2016-10-31 11:15:36 +01:00
c09bcd51ad Merge pull request #675 from mailpoet/amazon_ses_fix
Fixes const value declaration for PHP <5.6
2016-10-28 17:29:57 +03:00
01af4d3401 - Fixes const value declaration for PHP <5.6 2016-10-28 10:13:56 -04:00
2ba9d95a2e Update plugin repo icon to "beta" 2016-10-28 16:03:14 +03:00
b2d4bfc760 Initial MailPoet 3.0.0-beta.1 release 2016-10-28 13:52:40 +03:00
57f5f16bb6 Merge pull request #674 from mailpoet/premium_hook
Bypasses subscriber count enforcement for premium users
2016-10-27 20:47:14 +03:00
7d2e13b9a3 - Updates license check logic
- Updates subscriber limit check logic
- Updates unit tests
- Updates Menu's check for subscriber limit
2016-10-27 12:35:57 -04:00
6d39f9fa78 Merge pull request #671 from mailpoet/plugin_repository_assets
Preparation for plugin repository
2016-10-27 11:36:57 -04:00
a4395f2350 - Adds unit tests 2016-10-27 11:16:30 -04:00
411969b3eb - Adds check for premium plugin status
- Bypasses subscriber count enforcement if premium is enabled
2016-10-27 10:20:05 -04:00
1868ca3155 Merge pull request #673 from mailpoet/scheduler_update
Scheduler update
2016-10-27 13:17:03 +03:00
e765471f5d - Changes month days count to start from 1 instead of 0
- Closes #672
2016-10-26 21:18:07 -04:00
bdce7c5e5a - Remove unused dependency 2016-10-26 11:43:32 -04:00
773be9f5c8 Add assets for plugin repository 2016-10-26 13:59:02 +03:00
6ae46b05e5 Merge pull request #669 from mailpoet/string_updates
String updates
2016-10-25 18:00:44 +03:00
217894745d - Updates text strings
- Closes #655
2016-10-25 10:21:23 -04:00
99 changed files with 1530 additions and 865 deletions

View File

@ -3,14 +3,21 @@
class RoboFile extends \Robo\Tasks {
function install() {
$this->_exec('./composer.phar install');
$this->_exec('npm install');
return $this->taskExecStack()
->stopOnFail()
->exec('./composer.phar install')
->exec('npm install')
->run();
}
function update() {
$this->say(getenv('WP_TEST_URL'));
$this->_exec('./composer.phar update');
$this->_exec('npm update');
return $this->taskExecStack()
->stopOnFail()
->exec('./composer.phar update')
->exec('npm update')
->run();
}
protected function rsearch($folder, $extensions = array()) {
@ -61,12 +68,14 @@ class RoboFile extends \Robo\Tasks {
}
function compileAll() {
$this->compileJs();
$this->compileCss();
$collection = $this->collection();
$collection->add(array($this, 'compileJs'));
$collection->add(array($this, 'compileCss'));
return $collection->run();
}
function compileJs() {
$this->_exec('./node_modules/webpack/bin/webpack.js');
return $this->_exec('./node_modules/webpack/bin/webpack.js --bail');
}
function compileCss() {
@ -78,7 +87,7 @@ class RoboFile extends \Robo\Tasks {
'assets/css/src/importExport.styl'
);
$this->_exec(join(' ', array(
return $this->_exec(join(' ', array(
'./node_modules/stylus/bin/stylus',
'--include ./node_modules',
'--include-css',
@ -89,14 +98,14 @@ class RoboFile extends \Robo\Tasks {
}
function makepot() {
$this->_exec('./node_modules/.bin/grunt makepot'.
return $this->_exec('./node_modules/.bin/grunt makepot'.
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
' --base_path '.__DIR__
);
}
function pushpot() {
$this->_exec('./node_modules/.bin/grunt pushpot'.
return $this->_exec('./node_modules/.bin/grunt pushpot'.
' --gruntfile '.__DIR__.'/tasks/makepot/makepot.js'.
' --base_path '.__DIR__
);
@ -152,22 +161,26 @@ class RoboFile extends \Robo\Tasks {
function testDebug() {
$this->_exec('vendor/bin/codecept build');
$this->loadEnv();
$this->_exec('vendor/bin/codecept run unit --debug');
return $this->_exec('vendor/bin/codecept run unit --debug');
}
function testFailed() {
$this->loadEnv();
$this->_exec('vendor/bin/codecept build');
$this->_exec('vendor/bin/codecept run -g failed');
return $this->_exec('vendor/bin/codecept run -g failed');
}
function qa() {
$this->qaLint();
$this->qaCodeSniffer('all');
$collection = $this->collection();
$collection->add(array($this, 'qaLint'));
$collection->add(function() {
return $this->qaCodeSniffer('all');
});
return $collection->run();
}
function qaLint() {
$this->_exec('./tasks/php_lint.sh lib/ tests/ mailpoet.php');
return $this->_exec('./tasks/php_lint.sh lib/ tests/ mailpoet.php');
}
function qaCodeSniffer($severity='errors') {
@ -176,7 +189,7 @@ class RoboFile extends \Robo\Tasks {
} else {
$severityFlag = '-n';
}
$this->_exec(
return $this->_exec(
'./vendor/bin/phpcs '.
'--standard=./tasks/code_sniffer/MailPoet '.
'--ignore=./lib/Util/Sudzy/*,./lib/Util/CSS.php,./lib/Util/XLSXWriter.php,'.

View File

@ -1,3 +1,15 @@
$box-width = 425px
$box-height = 150px
$thumbnail-width = $box-height
$thumbnail-height = $thumbnail-width
$box-description-space-between-heading-and-paragraph = 5px
$box-description-height = 110px
$box-description-text-height = $box-description-height - $box-description-space-between-heading-and-paragraph
$box-heading-line-height = $box-description-text-height / 4
$box-heading-font-size = $box-heading-line-height * 5/7
$box-description-line-height = $box-heading-line-height / 2
$box-description-font-size = $box-description-line-height
.mailpoet_boxes.mailpoet_boxes_loading
opacity: 0.2
@ -6,8 +18,8 @@
position: relative
padding: 15px
margin: 15px 25px 0 0
width: 425px
height: 150px
width: $box-width
height: $box-height
border: 1px solid #dedede
background-color: #fff
@ -18,15 +30,15 @@
background-position: center
color: #222
border: 1px solid #ccc
width: 150px
height: 150px
width: $thumbnail-height
height: $thumbnail-width
margin-right: 15px
float: left
overflow: hidden
position: relative
img
min-width: 150px
min-width: $thumbnail-width
height: auto
width: 110%
position: relative
@ -60,20 +72,21 @@
.mailpoet_boxes .mailpoet_description
float:left
width: 245px
max-height: calc(115px - 2em)
padding-bottom: 2em
max-height: $box-description-height
padding-bottom: 0
overflow: hidden
h3
margin: 0 0 0.7em 0
margin: 0 0 $box-description-space-between-heading-and-paragraph 0
overflow: hidden
max-width: 210px
line-height: 1.4em
line-height: $box-heading-line-height
font-size: $box-heading-font-size
p
font-size: 13px
line-height: 1.5
margin: 1em 0
font-size: $box-description-font-size
line-height: $box-description-line-height
margin: 0
.mailpoet_boxes .mailpoet_actions
position: absolute

View File

@ -1,3 +1,3 @@
define([], function() {
!function(e,o,n){window.HSCW=o,window.HS=n,n.beacon=n.beacon||{};var t=n.beacon;t.userConfig={},t.readyQueue=[],t.config=function(e){this.userConfig=e},t.ready=function(e){this.readyQueue.push(e)},o.config={docs:{enabled:!1,baseUrl:""},contact:{enabled:!0,formId:"e5c408c7-895e-11e5-9e75-0a7d6919297d"}};var r=e.getElementsByTagName("script")[0],c=e.createElement("script");c.type="text/javascript",c.async=!0,c.src="https://djtflbt20bdde.cloudfront.net/",r.parentNode.insertBefore(c,r)}(document,window.HSCW||{},window.HS||{});
!function(e,o,n){window.HSCW=o,window.HS=n,n.beacon=n.beacon||{};var t=n.beacon;t.userConfig={},t.readyQueue=[],t.config=function(e){this.userConfig=e},t.ready=function(e){this.readyQueue.push(e)},o.config={docs:{enabled:!0,baseUrl:"//mailpoet3.helpscoutdocs.com/"},contact:{enabled:!0,formId:"aa21ca80-a4f5-11e6-91aa-0a5fecc78a4d"}};var r=e.getElementsByTagName("script")[0],c=e.createElement("script");c.type="text/javascript",c.async=!0,c.src="https://djtflbt20bdde.cloudfront.net/",r.parentNode.insertBefore(c,r)}(document,window.HSCW||{},window.HS||{});
});

View File

@ -0,0 +1,76 @@
/**
* Text Editor Behavior
*
* Adds TinyMCE text editing capabilities to a view
*/
define([
'backbone.marionette',
'underscore',
'newsletter_editor/behaviors/BehaviorsLookup'
], function(Marionette, _, BehaviorsLookup) {
BehaviorsLookup.TextEditorBehavior = Marionette.Behavior.extend({
defaults: {
selector: '.mailpoet_content',
toolbar1: "bold italic link unlink forecolor mailpoet_shortcodes",
toolbar2: "",
validElements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br",
invalidElements: "script",
blockFormats: 'Paragraph=p',
plugins: "link textcolor colorpicker mailpoet_shortcodes",
configurationFilter: function(originalConfig) { return originalConfig; },
},
onDomRefresh: function() {
var that = this;
if (this.view.disableTextEditor === true) {
return;
}
this.$(this.options.selector).tinymce(this.options.configurationFilter({
inline: true,
menubar: false,
toolbar1: this.options.toolbar1,
toolbar2: this.options.toolbar2,
valid_elements: this.options.validElements,
invalid_elements: this.options.invalidElements,
block_formats: this.options.blockFormats,
relative_urls: false,
remove_script_host: false,
convert_urls: true,
urlconverter_callback: function(url, node, on_save, name) {
if (url.match(/\[.+\]/g)) {
// Do not convert URLs with shortcodes
return url;
}
return this.documentBaseURI.toAbsolute(
url,
this.settings.remove_script_host
);
},
plugins: this.options.plugins,
setup: function(editor) {
editor.on('change', function(e) {
that.view.triggerMethod('text:editor:change', editor.getContent());
});
editor.on('click', function(e) {
editor.focus();
});
editor.on('focus', function(e) {
that.view.triggerMethod('text:editor:focus');
});
editor.on('blur', function(e) {
that.view.triggerMethod('text:editor:blur');
});
},
}));
}
});
});

View File

@ -42,53 +42,31 @@ define([
modelEvents: _.extend({
'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render',
}, _.omit(base.BlockView.prototype.modelEvents, 'change')),
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
TextEditorBehavior: {
configurationFilter: function(originalSettings) {
return _.extend({}, originalSettings, {
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle'),
});
}
},
}),
onDragSubstituteBy: function() { return Module.FooterWidgetView; },
onRender: function() {
this.toolsView = new Module.FooterBlockToolsView({ model: this.model });
this.toolsRegion.show(this.toolsView);
},
onDomRefresh: function() {
this.attachTextEditor();
onTextEditorChange: function(newContent) {
this.model.set('text', newContent);
},
attachTextEditor: function() {
var that = this;
this.$('.mailpoet_content').tinymce({
inline: true,
menubar: false,
toolbar: "bold italic link unlink forecolor mailpoet_shortcodes",
valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br",
invalid_elements: "script",
block_formats: 'Paragraph=p',
relative_urls: false,
remove_script_host: false,
plugins: "link textcolor colorpicker mailpoet_shortcodes",
setup: function(editor) {
editor.on('change', function(e) {
that.model.set('text', editor.getContent());
});
editor.on('click', function(e) {
editor.focus();
});
editor.on('focus', function(e) {
that.disableDragging();
that.disableShowingTools();
});
editor.on('blur', function(e) {
that.enableDragging();
that.enableShowingTools();
});
},
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle'),
});
onTextEditorFocus: function() {
this.disableDragging();
this.disableShowingTools();
},
onTextEditorBlur: function() {
this.enableDragging();
this.enableShowingTools();
},
disableDragging: function() {
this.$('.mailpoet_content').addClass('mailpoet_ignore_drag');

View File

@ -42,53 +42,31 @@ define([
modelEvents: _.extend({
'change:styles.block.backgroundColor change:styles.text.fontColor change:styles.text.fontFamily change:styles.text.fontSize change:styles.text.textAlign change:styles.link.fontColor change:styles.link.textDecoration': 'render',
}, _.omit(base.BlockView.prototype.modelEvents, 'change')),
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
TextEditorBehavior: {
configurationFilter: function(originalSettings) {
return _.extend({}, originalSettings, {
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle'),
});
}
},
}),
onDragSubstituteBy: function() { return Module.HeaderWidgetView; },
onRender: function() {
this.toolsView = new Module.HeaderBlockToolsView({ model: this.model });
this.toolsRegion.show(this.toolsView);
},
onDomRefresh: function() {
this.attachTextEditor();
onTextEditorChange: function(newContent) {
this.model.set('text', newContent);
},
attachTextEditor: function() {
var that = this;
this.$('.mailpoet_content').tinymce({
inline: true,
menubar: false,
toolbar: "bold italic link unlink forecolor mailpoet_shortcodes",
valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],strong[class|style],em[class|style],strike,br",
invalid_elements: "script",
block_formats: 'Paragraph=p',
relative_urls: false,
remove_script_host: false,
plugins: "link textcolor colorpicker mailpoet_shortcodes",
setup: function(editor) {
editor.on('change', function(e) {
that.model.set('text', editor.getContent());
});
editor.on('click', function(e) {
editor.focus();
});
editor.on('focus', function(e) {
that.disableDragging();
that.disableShowingTools();
});
editor.on('blur', function(e) {
that.enableDragging();
that.enableShowingTools();
});
},
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle'),
});
onTextEditorFocus: function() {
this.disableDragging();
this.disableShowingTools();
},
onTextEditorBlur: function() {
this.enableDragging();
this.enableShowingTools();
},
disableDragging: function() {
this.$('.mailpoet_content').addClass('mailpoet_ignore_drag');

View File

@ -25,12 +25,30 @@ define([
className: "mailpoet_block mailpoet_text_block mailpoet_droppable_block",
getTemplate: function() { return templates.textBlock; },
modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'), // Prevent rerendering on model change due to text editor redrawing
behaviors: _.extend({}, base.BlockView.prototype.behaviors, {
TextEditorBehavior: {
toolbar1: "formatselect bold italic forecolor | link unlink",
toolbar2: "alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_shortcodes",
validElements: "p[class|style],span[class|style],a[href|class|title|target|style],h1[class|style],h2[class|style],h3[class|style],ol[class|style],ul[class|style],li[class|style],strong[class|style],em[class|style],strike,br,blockquote[class|style],table[class|style],tr[class|style],th[class|style],td[class|style]",
invalidElements: "script",
blockFormats: 'Heading 1=h1;Heading 2=h2;Heading 3=h3;Paragraph=p',
plugins: "link code textcolor colorpicker mailpoet_shortcodes",
configurationFilter: function(originalSettings) {
return _.extend({}, originalSettings, {
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle'),
});
}
},
}),
initialize: function(options) {
base.BlockView.prototype.initialize.apply(this, arguments);
this.renderOptions = _.defaults(options.renderOptions || {}, {
disableTextEditor: false,
});
this.disableTextEditor = this.renderOptions.disableTextEditor;
},
onDragSubstituteBy: function() { return Module.TextWidgetView; },
onRender: function() {
@ -42,53 +60,18 @@ define([
});
this.toolsRegion.show(this.toolsView);
},
onDomRefresh: function() {
this.attachTextEditor();
onTextEditorChange: function(newContent) {
this.model.set('text', newContent);
},
attachTextEditor: function() {
var that = this;
if (!this.renderOptions.disableTextEditor) {
this.$('.mailpoet_content').tinymce({
inline: true,
menubar: false,
toolbar1: "formatselect bold italic forecolor | link unlink",
toolbar2: "alignleft aligncenter alignright alignjustify | bullist numlist blockquote | code mailpoet_shortcodes",
//forced_root_block: 'p',
valid_elements: "p[class|style],span[class|style],a[href|class|title|target|style],h1[class|style],h2[class|style],h3[class|style],ol[class|style],ul[class|style],li[class|style],strong[class|style],em[class|style],strike,br,blockquote[class|style],table[class|style],tr[class|style],th[class|style],td[class|style]",
invalid_elements: "script",
block_formats: 'Heading 1=h1;Heading 2=h2;Heading 3=h3;Paragraph=p',
relative_urls: false,
remove_script_host: false,
plugins: "link code textcolor colorpicker mailpoet_shortcodes",
setup: function(editor) {
editor.on('change', function(e) {
that.model.set('text', editor.getContent());
});
editor.on('click', function(e) {
editor.focus();
});
editor.on('focus', function(e) {
that.disableDragging();
that.disableShowingTools();
});
editor.on('blur', function(e) {
that.enableDragging();
that.enableShowingTools();
});
},
mailpoet_shortcodes: App.getConfig().get('shortcodes').toJSON(),
mailpoet_shortcodes_window_title: MailPoet.I18n.t('shortcodesWindowTitle'),
});
}
onTextEditorFocus: function() {
this.disableDragging();
this.disableShowingTools();
},
onTextEditorBlur: function() {
this.enableDragging();
this.enableShowingTools();
},
disableDragging: function() {
this.$('.mailpoet_content').addClass('mailpoet_ignore_drag');
},

View File

@ -61,7 +61,7 @@ const _QueueMixin = {
);
// calculate percentage done
const percentage = Math.round(
let percentage = Math.round(
(newsletter.queue.count_processed * 100) / (newsletter.queue.count_total)
);
@ -108,15 +108,24 @@ const _QueueMixin = {
);
}
let progress_bar_width = 0;
if (isNaN(percentage)) {
percentage = MailPoet.I18n.t('noSubscribers');
} else {
progress_bar_width = percentage;
percentage += "%";
}
return (
<div>
<div className={ progressClasses }>
<span
className="mailpoet_progress_bar"
style={ { width: percentage + "%"} }
style={ { width: progress_bar_width + "%"} }
></span>
<span className="mailpoet_progress_label">
{ percentage + "%" }
{ percentage }
</span>
</div>
<p style={{ textAlign:'center' }}>

View File

@ -68,7 +68,7 @@ const NewsletterListNotificationHistory = React.createClass({
<a
href={ newsletter.preview_url }
target="_blank"
>{ newsletter.subject }</a>
>{ newsletter.queue.newsletter_rendered_subject }</a>
</strong>
{ actions }
</td>

View File

@ -62,7 +62,7 @@ const _monthDayValues = _.object(
} else {
label = MailPoet.I18n.t('nth').replace("%$1d", day + 1);
}
return [day, label];
return [day + 1, label];
}
)
);

View File

@ -1,6 +1,5 @@
import _ from 'underscore'
import React from 'react'
import MailPoet from 'mailpoet'
import Select from 'form/fields/select.jsx'
import {
intervalValues,

View File

@ -871,7 +871,7 @@ define(
'<span class="mailpoet_data_match mailpoet_import_error" title="'
+ MailPoet.I18n.t('noDateFieldMatch') + '">'
+ MailPoet.I18n.t('emptyFirstRowDate')
+ '</span>';
+ '</span> ';
preventNextStep = true;
}
else {
@ -901,7 +901,7 @@ define(
+ '<span class="mailpoet_data_match" title="'
+ MailPoet.I18n.t('verifyDateMatch') + '">'
+ MailPoet.Date.format(date)
+ '</span>'
+ '</span> '
);
}
else {
@ -910,7 +910,7 @@ define(
+ '<span class="mailpoet_data_match mailpoet_import_error" title="'
+ MailPoet.I18n.t('noDateFieldMatch') + '">'
+ (new Handlebars.SafeString(MailPoet.I18n.t('dateMatchError')))
+ '</span>'
+ '</span> '
);
preventNextStep = true;
};

View File

@ -1,25 +1,32 @@
#!/bin/sh
# Translations (npm install & composer install need to be run before)
echo '[BUILD] Generating translations'
./do makepot
plugin_name='mailpoet'
# Remove previous build.
echo '[BUILD] Removing previous build'
rm $plugin_name.zip
# Create temp dir.
echo '[BUILD] Creating temporary directory'
mkdir $plugin_name
# Production assets.
echo '[BUILD] Generating production CSS and JS assets'
rm -rf node_modules
npm install
./do compile:all
# Production libraries.
./composer.phar install --no-dev --prefer-dist --optimize-autoloader
echo '[BUILD] Fetching production libraries'
rm -rf vendor
./composer.phar install --no-dev --prefer-dist --optimize-autoloader --no-scripts
# Copy release folders.
echo '[BUILD] Copying release folders'
cp -Rf lang $plugin_name
cp -RfL assets $plugin_name
cp -Rf lib $plugin_name
@ -29,12 +36,13 @@ rm -Rf $plugin_name/assets/css/src
rm -Rf $plugin_name/assets/js/src
# Remove extra files (docs, examples,...) from 3rd party extensions
echo '[BUILD] Removing obsolete files from vendor libraries'
find $plugin_name/vendor -type f -regextype posix-egrep -iregex ".*\/*\.(markdown|md|txt)" -print0 | xargs -0 rm -f
find $plugin_name/vendor -type f -regextype posix-egrep -iregex ".*\/(readme|license|version|changes|changelog)" -print0 | xargs -0 rm -f
find $plugin_name/vendor -type d -regextype posix-egrep -iregex ".*\/(docs?|examples?|\.git)" -print0 | xargs -0 rm -rf
# Remove unit tests from 3rd party extensions
rm $plugin_name/vendor/j4mie/idiorm/demo.php
echo '[BUILD] Removing unit tests from vendor libraries'
rm -rf $plugin_name/vendor/twig/twig/test
rm -rf $plugin_name/vendor/symfony/translation/Tests
rm -rf $plugin_name/vendor/phpmailer/phpmailer/test
@ -43,18 +51,33 @@ rm -rf $plugin_name/vendor/mtdowling/cron-expression/tests
rm -rf $plugin_name/vendor/swiftmailer/swiftmailer/tests
rm -rf $plugin_name/vendor/cerdic/css-tidy/testing
# Remove risky files from 3rd party extensions
echo '[BUILD] Removing risky and demo files from vendor libraries'
rm -f $plugin_name/vendor/j4mie/idiorm/demo.php
rm -f $plugin_name/vendor/cerdic/css-tidy/css_optimiser.php
# Copy release files.
echo '[BUILD] Copying release files'
cp license.txt $plugin_name
cp index.php $plugin_name
cp $plugin_name.php $plugin_name
cp readme.txt $plugin_name
cp uninstall.php $plugin_name
# Add index files if they don't exist to all folders
echo '[BUILD] Adding index files to all project folders'
find $plugin_name -type d -exec touch {}/index.php \;
# Zip final release.
echo '[BUILD] Creating final release zip'
zip -r $plugin_name.zip $plugin_name
# Remove temp dir.
echo '[BUILD] Removing temp directory'
rm -rf $plugin_name
# Reinstall dev dependencies.
echo '[BUILD] Reinstalling dev dependencies'
./composer.phar install
echo '[BUILD] Build finished!'

View File

@ -17,7 +17,8 @@ dependencies:
- sudo a2enmod rewrite
- sudo service apache2 restart
# install Phoenix dependencies
- composer install
- curl -sS https://getcomposer.org/installer | php
- ./composer.phar install
- ./do install
# Set up Wordpress
# No password is required for the MySQL user `ubuntu`
@ -46,6 +47,10 @@ dependencies:
## tests override
test:
override:
# Add default timezone to PHP's configuration (required for PHP >=5.4)
- echo "date.timezone = UTC" > /opt/circleci/php/$(phpenv global)/etc/conf.d/date.ini
# Run QA scripts
- ./do qa
# Run JS tests
- mkdir $CIRCLE_TEST_REPORTS/mocha
- ./do t:j $CIRCLE_TEST_REPORTS/mocha/junit.xml

View File

@ -27,6 +27,7 @@ coverage:
include:
- lib/*
exclude:
- lib/Config/PopulatorData/*
- lib/Util/Sudzy/*
- lib/Util/CSS.php
- lib/Util/Helpers.php

View File

@ -8,13 +8,10 @@
"require": {
"php": ">=5.3.3",
"twig/twig": "1.*",
"phpmailer/phpmailer": "~5.2",
"cerdic/css-tidy": "*",
"sunra/php-simple-html-dom-parser": "*",
"tburry/pquery": "*",
"j4mie/paris": "1.5.4",
"swiftmailer/swiftmailer": "^5.4",
"phpseclib/phpseclib": "*",
"mtdowling/cron-expression": "^1.1",
"nesbot/carbon": "^1.21",
"soundasleep/html2text": "dev-master"
@ -26,12 +23,18 @@
"vlucas/phpdotenv": "*",
"umpirsky/twig-gettext-extractor": "1.1.*",
"raveren/kint": "^1.0",
"squizlabs/php_codesniffer": "2.*"
"squizlabs/php_codesniffer": "*",
"wimg/php-compatibility": "*",
"simplyadmire/composer-plugins" : "@dev"
},
"autoload": {
"psr-4": {
"MailPoet\\": "lib/",
"Sudzy\\": "lib/Util/Sudzy"
}
},
"scripts": {
"post-update-cmd": "rm -rf vendor/squizlabs/php_codesniffer/CodeSniffer/Standards/PHPCompatibility; cp -rpd vendor/wimg/php-compatibility vendor/squizlabs/php_codesniffer/CodeSniffer/Standards/PHPCompatibility",
"post-install-cmd": "rm -rf vendor/squizlabs/php_codesniffer/CodeSniffer/Standards/PHPCompatibility; cp -rpd vendor/wimg/php-compatibility vendor/squizlabs/php_codesniffer/CodeSniffer/Standards/PHPCompatibility"
}
}
}

841
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -73,7 +73,7 @@ class Subscribers extends APIEndpoint {
if(empty($segment_ids)) {
return $this->badRequest(array(
APIError::BAD_REQUEST => __('Please select a list', 'mailpoet')
APIError::BAD_REQUEST => __('Please select a list.', 'mailpoet')
));
}

View File

@ -27,7 +27,6 @@ class Env {
static $db_password;
static $db_charset;
static $db_timezone_offset;
static $subscribers_limit = 2000;
static function init($file, $version) {
global $wpdb;
@ -39,11 +38,11 @@ class Env {
self::$assets_path = self::$path . '/assets';
self::$assets_url = plugins_url('/assets', $file);
$wp_upload_dir = wp_upload_dir();
self::$temp_path = $wp_upload_dir['basedir'].'/'.self::$plugin_name;
self::$temp_path = $wp_upload_dir['basedir'] . '/' . self::$plugin_name;
if(!is_dir(self::$temp_path)) {
mkdir(self::$temp_path);
}
self::$temp_url = $wp_upload_dir['baseurl'].'/'.self::$plugin_name;
self::$temp_url = $wp_upload_dir['baseurl'] . '/' . self::$plugin_name;
self::$languages_path = self::$path . '/lang';
self::$lib_path = self::$path . '/lib';
self::$plugin_prefix = 'mailpoet_';

View File

@ -4,6 +4,7 @@ namespace MailPoet\Config;
use MailPoet\Cron\CronTrigger;
use MailPoet\Router;
use MailPoet\API;
use MailPoet\Util\License\License as License;
use MailPoet\WP\Notice as WPNotice;
if(!defined('ABSPATH')) exit;
@ -116,6 +117,7 @@ class Initializer {
function onInit() {
if(!$this->plugin_initialized) {
define('MAILPOET_INITIALIZED', false);
return;
}
@ -126,6 +128,8 @@ class Initializer {
} catch(\Exception $e) {
$this->handleFailedInitialization($e);
}
define('MAILPOET_INITIALIZED', true);
}
function setupWidget() {
@ -142,8 +146,9 @@ class Initializer {
}
function setupRenderer() {
$renderer = new Renderer();
$this->renderer = $renderer->init();
$caching = !WP_DEBUG;
$debugging = WP_DEBUG;
$this->renderer = new Renderer($caching, $debugging);
}
function setupLocalizer() {

View File

@ -14,7 +14,9 @@ use MailPoet\Settings\Hosts;
use MailPoet\Settings\Pages;
use MailPoet\Subscribers\ImportExport\ImportExportFactory;
use MailPoet\Listing;
use MailPoet\Util\License\Features\Subscribers as SubscribersFeature;
use MailPoet\WP\DateTime;
use MailPoet\WP\Notice as WPNotice;
if(!defined('ABSPATH')) exit;
@ -22,6 +24,8 @@ class Menu {
function __construct($renderer, $assets_url) {
$this->renderer = $renderer;
$this->assets_url = $assets_url;
$subscribers_feature = new SubscribersFeature();
$this->subscribers_over_limit = $subscribers_feature->check();
}
function init() {
@ -34,16 +38,6 @@ class Menu {
);
}
function checkSubscribersLimit() {
$subscribers_count = Subscriber::getTotalSubscribers();
if($subscribers_count > Env::$subscribers_limit) {
echo $this->renderer->render('limit.html', array(
'limit' => Env::$subscribers_limit
));
exit;
}
}
function setup() {
$main_page_slug = 'mailpoet-newsletters';
@ -59,8 +53,8 @@ class Menu {
$newsletters_page = add_submenu_page(
$main_page_slug,
$this->setPageTitle(__('Newsletters', 'mailpoet')),
__('Newsletters', 'mailpoet'),
$this->setPageTitle(__('Emails', 'mailpoet')),
__('Emails', 'mailpoet'),
'manage_options',
$main_page_slug,
array($this, 'newsletters')
@ -222,7 +216,7 @@ class Menu {
'redirect_url' => $redirect_url,
'sub_menu' => 'mailpoet-newsletters'
);
echo $this->renderer->render('welcome.html', $data);
$this->displayPage('welcome.html', $data);
}
function update() {
@ -248,11 +242,11 @@ class Menu {
'sub_menu' => 'mailpoet-newsletters'
);
echo $this->renderer->render('update.html', $data);
$this->displayPage('update.html', $data);
}
function settings() {
$this->checkSubscribersLimit();
if ($this->subscribers_over_limit) return $this->displaySubscriberLimitExceededTemplate();
$settings = Setting::getAll();
$flags = $this->_getFlags();
@ -270,7 +264,7 @@ class Menu {
)
);
echo $this->renderer->render('settings.html', $data);
$this->displayPage('settings.html', $data);
}
private function _getFlags() {
@ -322,30 +316,30 @@ class Menu {
$data['date_formats'] = Block\Date::getDateFormats();
$data['month_names'] = Block\Date::getMonthNames();
echo $this->renderer->render('subscribers/subscribers.html', $data);
$this->displayPage('subscribers/subscribers.html', $data);
}
function segments() {
$this->checkSubscribersLimit();
if ($this->subscribers_over_limit) return $this->displaySubscriberLimitExceededTemplate();
$data = array();
$data['items_per_page'] = $this->getLimitPerPage('segments');
echo $this->renderer->render('segments.html', $data);
$this->displayPage('segments.html', $data);
}
function forms() {
$this->checkSubscribersLimit();
if ($this->subscribers_over_limit) return $this->displaySubscriberLimitExceededTemplate();
$data = array();
$data['items_per_page'] = $this->getLimitPerPage('forms');
$data['segments'] = Segment::findArray();
echo $this->renderer->render('forms.html', $data);
$this->displayPage('forms.html', $data);
}
function newsletters() {
$this->checkSubscribersLimit();
if ($this->subscribers_over_limit) return $this->displaySubscriberLimitExceededTemplate();
global $wp_roles;
@ -371,7 +365,7 @@ class Menu {
wp_enqueue_script('jquery-ui');
wp_enqueue_script('jquery-ui-datepicker');
echo $this->renderer->render('newsletters.html', $data);
$this->displayPage('newsletters.html', $data);
}
function newletterEditor() {
@ -384,7 +378,7 @@ class Menu {
wp_enqueue_media();
wp_enqueue_script('tinymce-wplink', includes_url('js/tinymce/plugins/wplink/plugin.js'));
wp_enqueue_style('editor', includes_url('css/editor.css'));
echo $this->renderer->render('newsletter/editor.html', $data);
$this->displayPage('newsletter/editor.html', $data);
}
function import() {
@ -396,14 +390,14 @@ class Menu {
'month_names' => Block\Date::getMonthNames(),
'sub_menu' => 'mailpoet-subscribers'
));
echo $this->renderer->render('subscribers/importExport/import.html', $data);
$this->displayPage('subscribers/importExport/import.html', $data);
}
function export() {
$export = new ImportExportFactory('export');
$data = $export->bootstrap();
$data['sub_menu'] = 'mailpoet-subscribers';
echo $this->renderer->render('subscribers/importExport/export.html', $data);
$this->displayPage('subscribers/importExport/export.html', $data);
}
function formEditor() {
@ -424,7 +418,7 @@ class Menu {
'sub_menu' => 'mailpoet-forms'
);
echo $this->renderer->render('form/editor.html', $data);
$this->displayPage('form/editor.html', $data);
}
function setPageTitle($title) {
@ -435,6 +429,13 @@ class Menu {
);
}
function displaySubscriberLimitExceededTemplate() {
$this->displayPage('limit.html', array(
'limit' => SubscribersFeature::SUBSCRIBERS_LIMIT
));
exit;
}
private function getLimitPerPage($model = null) {
if($model === null) {
return Listing\Handler::DEFAULT_LIMIT_PER_PAGE;
@ -447,4 +448,13 @@ class Menu {
? (int)$listing_per_page
: Listing\Handler::DEFAULT_LIMIT_PER_PAGE;
}
private function displayPage($template, $data) {
try {
echo $this->renderer->render($template, $data);
} catch (\Exception $e) {
$notice = new WPNotice(WPNotice::TYPE_ERROR, $e->getMessage());
$notice->displayWPNotice();
}
}
}

View File

@ -52,8 +52,9 @@ class Migrator {
function down() {
global $wpdb;
$drop_table = function($model) use($wpdb) {
$table = $this->prefix . $model;
$_this = $this;
$drop_table = function($model) use($wpdb, $_this) {
$table = $_this->prefix . $model;
$wpdb->query("DROP TABLE {$table}");
};
@ -133,6 +134,9 @@ class Migrator {
'last_name tinytext NOT NULL DEFAULT "",',
'email varchar(150) NOT NULL,',
'status varchar(12) NOT NULL DEFAULT "' . Subscriber::STATUS_UNCONFIRMED . '",',
'subscribed_ip varchar(32) NULL,',
'confirmed_ip varchar(32) NULL,',
'confirmed_at TIMESTAMP NULL,',
'created_at TIMESTAMP NULL,',
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
'deleted_at TIMESTAMP NULL,',

View File

@ -211,13 +211,12 @@ class Populator {
$modelMethod = Helpers::underscoreToCamelCase($model);
$rows = $this->$modelMethod();
$table = $this->prefix . $model;
$_this = $this;
array_map(function($row) use ($_this, $table) {
if(!$_this->rowExists($table, $row)) {
$_this->insertRow($table, $row);
foreach($rows as $row) {
if(!$this->rowExists($table, $row)) {
$this->insertRow($table, $row);
}
}, $rows);
}
}
private function rowExists($table, $columns) {

View File

@ -88,7 +88,7 @@ class FranksRoastHouseTemplate {
),
array(
"type" => "text",
"text" => __("<p>Hi there&nbsp;[subscriber:firstname | default:coffee drinker]</p>\n<p></p>\n<p>Sit back&nbsp;and enjoy your favorite roast as you read this week's newsletter.&nbsp;</p>", 'mailpoet')
"text" => __("<p>Hi there [subscriber:firstname | default:coffee drinker]</p>\n<p></p>\n<p>Sit back and enjoy your favorite roast as you read this week's newsletter. </p>", 'mailpoet')
),
array(
"type" => "image",
@ -106,7 +106,7 @@ class FranksRoastHouseTemplate {
),
array(
"type" => "text",
"text" => __("<h1 style=\"text-align: center;\">--- Guest Coffee Roaster: <em>Brew Bros. ---</em></h1>\n<p><em></em></p>\n<p>Visit our Center Avenue store to try the latest guest coffee from Brew Bros, a local coffee roaster. This young duo started only two years ago, but have quickly gained&nbsp;popularity through pop-up shops, local events, and collaborations with food trucks.</p>\n<p></p>\n<blockquote>\n<p><span style=\"color: #ff6600;\"><em>Tasting notes: A rich, caramel flavor with subtle hints of molasses. The perfect wake-up morning espresso!</em></span></p>\n</blockquote>", 'mailpoet')
"text" => __("<h1 style=\"text-align: center;\">--- Guest Coffee Roaster: <em>Brew Bros. ---</em></h1>\n<p><em></em></p>\n<p>Visit our Center Avenue store to try the latest guest coffee from Brew Bros, a local coffee roaster. This young duo started only two years ago, but have quickly gained popularity through pop-up shops, local events, and collaborations with food trucks.</p>\n<p></p>\n<blockquote>\n<p><span style=\"color: #ff6600;\"><em>Tasting notes: A rich, caramel flavor with subtle hints of molasses. The perfect wake-up morning espresso!</em></span></p>\n</blockquote>", 'mailpoet')
)
)
)
@ -250,7 +250,7 @@ class FranksRoastHouseTemplate {
),
array(
"type" => "text",
"text" => __("<p>Watch out Broad Street, we're coming to you very soon!&nbsp;</p>\n<p></p>\n<p>Keep an eye on your inbox, as we'll have some special offers for our email subscribers plus an exclusive launch party invite!<br /><br /></p>", 'mailpoet')
"text" => __("<p>Watch out Broad Street, we're coming to you very soon! </p>\n<p></p>\n<p>Keep an eye on your inbox, as we'll have some special offers for our email subscribers plus an exclusive launch party invite!<br /><br /></p>", 'mailpoet')
),
array(
"type" => "text",

View File

@ -52,7 +52,7 @@ class NewsletterBlank121Column {
"blocks" => array(
array(
"type" => "header",
"text" => __("Display problems?&nbsp;<a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"text" => __("Display problems? <a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"styles" => array(
"block" => array(
"backgroundColor" => "transparent"
@ -116,7 +116,7 @@ class NewsletterBlank121Column {
),
array(
"type" => "text",
"text" => __("<h1 style=\"text-align: center;\"><strong>Let's Get Started!</strong></h1>\n<p>It's time to design your newsletter! On&nbsp;the right sidebar, you'll find four menu items that will help&nbsp;you&nbsp;customize your&nbsp;newsletter:</p>\n<ol>\n<li>Content</li>\n<li>Layout</li>\n<li>Styles</li>\n<li>Preview</li>\n</ol>", 'mailpoet')
"text" => __("<h1 style=\"text-align: center;\"><strong>Let's Get Started!</strong></h1>\n<p>It's time to design your newsletter! On the right sidebar, you'll find four menu items that will help you customize your newsletter:</p>\n<ol>\n<li>Content</li>\n<li>Layout</li>\n<li>Styles</li>\n<li>Preview</li>\n</ol>", 'mailpoet')
),
array(
"type" => "divider",
@ -158,7 +158,7 @@ class NewsletterBlank121Column {
),
array(
"type" => "text",
"text" => __("<p>In the right sidebar, you can&nbsp;add layout blocks to your email:</p>\n<ul>\n<li>1 column</li>\n<li>2 columns</li>\n<li>3 columns</li>\n</ul>", 'mailpoet')
"text" => __("<p>In the right sidebar, you can add layout blocks to your email:</p>\n<ul>\n<li>1 column</li>\n<li>2 columns</li>\n<li>3 columns</li>\n</ul>", 'mailpoet')
)
)
),
@ -177,7 +177,7 @@ class NewsletterBlank121Column {
),
array(
"type" => "text",
"text" => __("<p>You can change a layout's background color by clicking on the settings icon on the right edge of the&nbsp;Designer. Simply hover&nbsp;over this area to see the Settings (gear) icon.</p>", 'mailpoet')
"text" => __("<p>You can change a layout's background color by clicking on the settings icon on the right edge of the Designer. Simply hover over this area to see the Settings (gear) icon.</p>", 'mailpoet')
)
)
)
@ -237,7 +237,7 @@ class NewsletterBlank121Column {
"blocks" => array(
array(
"type" => "text",
"text" => __("<h3 style=\"text-align: center;\"><span style=\"font-weight: 600;\">Let's end with&nbsp;a single column.&nbsp;</span></h3>\n<p style=\"line-height: 25.6px;\">In the right sidebar, you can&nbsp;add these layout blocks to your&nbsp;email:</p>\n<p style=\"line-height: 25.6px;\"></p>\n<ul style=\"line-height: 25.6px;\">\n<li>1 column</li>\n<li>2 columns</li>\n<li>3 columns</li>\n</ul>", 'mailpoet')
"text" => __("<h3 style=\"text-align: center;\"><span style=\"font-weight: 600;\">Let's end with a single column. </span></h3>\n<p style=\"line-height: 25.6px;\">In the right sidebar, you can add these layout blocks to your email:</p>\n<p style=\"line-height: 25.6px;\"></p>\n<ul style=\"line-height: 25.6px;\">\n<li>1 column</li>\n<li>2 columns</li>\n<li>3 columns</li>\n</ul>", 'mailpoet')
)
)
)

View File

@ -52,7 +52,7 @@ class NewsletterBlank12Column {
"blocks" => array(
array(
"type" => "header",
"text" => __("Display problems?&nbsp;<a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"text" => __("Display problems? <a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"styles" => array(
"block" => array(
"backgroundColor" => "transparent"
@ -116,7 +116,7 @@ class NewsletterBlank12Column {
),
array(
"type" => "text",
"text" => __("<h1 style=\"text-align: center;\"><strong>Let's Get Started!</strong></h1>\n<p></p>\n<p>It's time to design your newsletter! In the right sidebar, you'll find 4 menu items that will&nbsp;help you customize your&nbsp;newsletter:</p>\n<ol>\n<li>Content</li>\n<li>Layout</li>\n<li>Styles</li>\n<li>Preview</li>\n</ol>", 'mailpoet')
"text" => __("<h1 style=\"text-align: center;\"><strong>Let's Get Started!</strong></h1>\n<p></p>\n<p>It's time to design your newsletter! In the right sidebar, you'll find 4 menu items that will help you customize your newsletter:</p>\n<ol>\n<li>Content</li>\n<li>Layout</li>\n<li>Styles</li>\n<li>Preview</li>\n</ol>", 'mailpoet')
),
array(
"type" => "divider",
@ -158,7 +158,7 @@ class NewsletterBlank12Column {
),
array(
"type" => "text",
"text" => __("<p>In the right sidebar, you can&nbsp;add these layout blocks to your email:</p>\n<ul>\n<li>1 column</li>\n<li>2 columns</li>\n<li>3 columns</li>\n</ul>", 'mailpoet')
"text" => __("<p>In the right sidebar, you can add these layout blocks to your email:</p>\n<ul>\n<li>1 column</li>\n<li>2 columns</li>\n<li>3 columns</li>\n</ul>", 'mailpoet')
)
)
),
@ -177,7 +177,7 @@ class NewsletterBlank12Column {
),
array(
"type" => "text",
"text" => __("<p><span style=\"line-height: 25.6px;\">You can change a layout's background color by clicking on the settings icon on the right edge of the Designer. Simply hover&nbsp;over this area to see the Settings (gear) icon.</span></p>", 'mailpoet')
"text" => __("<p><span style=\"line-height: 25.6px;\">You can change a layout's background color by clicking on the settings icon on the right edge of the Designer. Simply hover over this area to see the Settings (gear) icon.</span></p>", 'mailpoet')
)
)
)

View File

@ -52,7 +52,7 @@ class NewsletterBlank13Column {
"blocks" => array(
array(
"type" => "header",
"text" => __("Display problems?&nbsp;<a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"text" => __("Display problems? <a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"styles" => array(
"block" => array(
"backgroundColor" => "transparent"
@ -116,7 +116,7 @@ class NewsletterBlank13Column {
),
array(
"type" => "text",
"text" => __("<h1 style=\"text-align: center;\"><strong>Let's Get Started!&nbsp;</strong></h1>\n<p></p>\n<p>It's time to design your newsletter! On&nbsp;the right sidebar, you'll find four menu items that will help&nbsp;you&nbsp;customize your&nbsp;newsletter:</p>\n<ol>\n<li>Content</li>\n<li>Layout</li>\n<li>Styles</li>\n<li>Preview</li>\n</ol>", 'mailpoet')
"text" => __("<h1 style=\"text-align: center;\"><strong>Let's Get Started! </strong></h1>\n<p></p>\n<p>It's time to design your newsletter! On the right sidebar, you'll find four menu items that will help you customize your newsletter:</p>\n<ol>\n<li>Content</li>\n<li>Layout</li>\n<li>Styles</li>\n<li>Preview</li>\n</ol>", 'mailpoet')
),
array(
"type" => "divider",
@ -154,11 +154,11 @@ class NewsletterBlank13Column {
"blocks" => array(
array(
"type" => "text",
"text" => __("<h3>This template...&nbsp;</h3>", 'mailpoet')
"text" => __("<h3>This template... </h3>", 'mailpoet')
),
array(
"type" => "text",
"text" => __("<p>In the right sidebar, you can&nbsp;add layout blocks to your newsletter.</p>", 'mailpoet')
"text" => __("<p>In the right sidebar, you can add layout blocks to your newsletter.</p>", 'mailpoet')
)
)
),
@ -173,7 +173,7 @@ class NewsletterBlank13Column {
"blocks" => array(
array(
"type" => "text",
"text" => __("<h3>... has&nbsp;a...&nbsp;</h3>", 'mailpoet')
"text" => __("<h3>... has a... </h3>", 'mailpoet')
),
array(
"type" => "text",

View File

@ -52,7 +52,7 @@ class NewsletterBlank1Column {
"blocks" => array(
array(
"type" => "header",
"text" => __("Display problems?&nbsp;<a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"text" => __("Display problems? <a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"styles" => array(
"block" => array(
"backgroundColor" => "transparent"
@ -116,7 +116,7 @@ class NewsletterBlank1Column {
),
array(
"type" => "text",
"text" => __("<h1 style=\"text-align: center;\"><strong>Let's Get Started!&nbsp;</strong></h1>\n<p></p>\n<p>It's time to design your newsletter! In the right sidebar, you'll find 4 menu items that will&nbsp;help you customize your newsletter:</p>\n<ol>\n<li>Content</li>\n<li>Layout</li>\n<li>Styles</li>\n<li>Preview</li>\n</ol>", 'mailpoet')
"text" => __("<h1 style=\"text-align: center;\"><strong>Let's Get Started! </strong></h1>\n<p></p>\n<p>It's time to design your newsletter! In the right sidebar, you'll find 4 menu items that will help you customize your newsletter:</p>\n<ol>\n<li>Content</li>\n<li>Layout</li>\n<li>Styles</li>\n<li>Preview</li>\n</ol>", 'mailpoet')
)
)
)

View File

@ -52,7 +52,7 @@ class PostNotificationsBlank1Column {
"blocks" => array(
array(
"type" => "header",
"text" => __("Display problems?&nbsp;<a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"text" => __("Display problems? <a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"styles" => array(
"block" => array(
"backgroundColor" => "transparent"
@ -116,7 +116,7 @@ class PostNotificationsBlank1Column {
),
array(
"type" => "text",
"text" => __("<h1 style=\"text-align: center;\"><strong>Check Out Our New Blog Posts!&nbsp;</strong></h1>\n<p></p>\n<p>MailPoet&nbsp;can&nbsp;<span style=\"line-height: 1.6em; background-color: inherit;\"><em>automatically</em>&nbsp;</span><span style=\"line-height: 1.6em; background-color: inherit;\">send your new blog posts to your subscribers.</span></p>\n<p><span style=\"line-height: 1.6em; background-color: inherit;\"></span></p>\n<p><span style=\"line-height: 1.6em; background-color: inherit;\">Below, you'll find three&nbsp;recent&nbsp;posts, which are displayed automatically, thanks to the&nbsp;<em>Automatic Latest Content</em>&nbsp;widget, which can be found on the right sidebar, under&nbsp;<em>Content</em>.</span></p>\n<p><span style=\"line-height: 1.6em; background-color: inherit;\"></span></p>\n<p><span style=\"line-height: 1.6em; background-color: inherit;\">To edit the settings and styles of your post, simply click on&nbsp;a&nbsp;post below.</span></p>", 'mailpoet')
"text" => __("<h1 style=\"text-align: center;\"><strong>Check Out Our New Blog Posts! </strong></h1>\n<p></p>\n<p>MailPoet can <span style=\"line-height: 1.6em; background-color: inherit;\"><em>automatically</em> </span><span style=\"line-height: 1.6em; background-color: inherit;\">send your new blog posts to your subscribers.</span></p>\n<p><span style=\"line-height: 1.6em; background-color: inherit;\"></span></p>\n<p><span style=\"line-height: 1.6em; background-color: inherit;\">Below, you'll find three recent posts, which are displayed automatically, thanks to the <em>Automatic Latest Content</em> widget, which can be found on the right sidebar, under <em>Content</em>.</span></p>\n<p><span style=\"line-height: 1.6em; background-color: inherit;\"></span></p>\n<p><span style=\"line-height: 1.6em; background-color: inherit;\">To edit the settings and styles of your post, simply click on a post below.</span></p>", 'mailpoet')
),
array(
"type" => "divider",

View File

@ -332,7 +332,7 @@ class Restaurant {
))
), array(
"type" => "header",
"text" => "<p><a href=\"[link:newsletter_view_in_browser_url]\">View&nbsp;this email in your web browser</a></p>",
"text" => "<p><a href=\"[link:newsletter_view_in_browser_url]\">View this email in your web browser</a></p>",
"styles" => array(
"block" => array(
"backgroundColor" => "transparent"

View File

@ -75,7 +75,7 @@ class SimpleText {
),
array(
"type" => "text",
"text" => __("<p style=\"text-align: left;\">Hi&nbsp;[subscriber:firstname | default:subscriber],</p>\n<p style=\"text-align: left;\"></p>\n<p style=\"text-align: left;\">In MailPoet, you can write emails in plain text,&nbsp;just like in a regular email.&nbsp;This can make your email newsletters&nbsp;more personal and attention-grabbing.</p>\n<p style=\"text-align: left;\"></p>\n<p style=\"text-align: left;\">Is this too&nbsp;simple?&nbsp;You can still style your text with basic&nbsp;formatting,&nbsp;like&nbsp;<strong>bold</strong>&nbsp;or <em>italics.</em></p>\n<p style=\"text-align: left;\"></p>\n<p style=\"text-align: left;\">Finally, you can also add a call-to-action button between 2 blocks of text, like this:</p>", 'mailpoet')
"text" => __("<p style=\"text-align: left;\">Hi [subscriber:firstname | default:subscriber],</p>\n<p style=\"text-align: left;\"></p>\n<p style=\"text-align: left;\">In MailPoet, you can write emails in plain text, just like in a regular email. This can make your email newsletters more personal and attention-grabbing.</p>\n<p style=\"text-align: left;\"></p>\n<p style=\"text-align: left;\">Is this too simple? You can still style your text with basic formatting, like <strong>bold</strong> or <em>italics.</em></p>\n<p style=\"text-align: left;\"></p>\n<p style=\"text-align: left;\">Finally, you can also add a call-to-action button between 2 blocks of text, like this:</p>", 'mailpoet')
)
)
)
@ -131,7 +131,7 @@ class SimpleText {
),
array(
"type" => "text",
"text" => __("<p>Thanks for&nbsp;reading. See you soon!</p>\n<p></p>\n<p><strong><em>The MailPoet Team</em></strong></p>", 'mailpoet')
"text" => __("<p>Thanks for reading. See you soon!</p>\n<p></p>\n<p><strong><em>The MailPoet Team</em></strong></p>", 'mailpoet')
),
array(
"type" => "footer",

View File

@ -70,7 +70,7 @@ class StoreDiscount {
)
), array(
"type" => "text",
"text" => __("<p></p>\n<p>Hi&nbsp;[subscriber:firstname | default:reader]</p>\n<p class=\"\"></p>\n<p>Fancy 15% off your next order? Use this coupon&nbsp;on all your favourite products from our store&nbsp;until Wednesday. Just&nbsp;enter the code on the payments page and&nbsp;your discount will applied.</p>", 'mailpoet')
"text" => __("<p></p>\n<p>Hi [subscriber:firstname | default:reader]</p>\n<p class=\"\"></p>\n<p>Fancy 15% off your next order? Use this coupon on all your favourite products from our store until Wednesday. Just enter the code on the payments page and your discount will applied.</p>", 'mailpoet')
), array(
"type" => "spacer",
"styles" => array(
@ -173,7 +173,7 @@ class StoreDiscount {
)
), array(
"type" => "text",
"text" => __("<h1 style=\"text-align: center;\"><strong><em>Use your discount on these great&nbsp;products...</em></strong></h1>", 'mailpoet')
"text" => __("<h1 style=\"text-align: center;\"><strong><em>Use your discount on these great products...</em></strong></h1>", 'mailpoet')
), array(
"type" => "spacer",
"styles" => array(

View File

@ -70,7 +70,7 @@ class TravelEmail {
)
), array(
"type" => "text",
"text" => __("<h1 style=\"text-align: center;\">Hi&nbsp;[subscriber:firstname | default:reader]!</h1>\n<p></p>\n<p>Greetings from New Zealand, we're here enjoying the sights and sounds (and bad smells!) of Rotarua. Yesterday we took advantage of the local amenities and visited&nbsp;the hot springs!&nbsp;</p>\n<p>Don't forget to stay up-to-date via twitter!</p>", 'mailpoet')
"text" => __("<h1 style=\"text-align: center;\">Hi [subscriber:firstname | default:reader]!</h1>\n<p></p>\n<p>Greetings from New Zealand, we're here enjoying the sights and sounds (and bad smells!) of Rotarua. Yesterday we took advantage of the local amenities and visited the hot springs! </p>\n<p>Don't forget to stay up-to-date via twitter!</p>", 'mailpoet')
), array(
"type" => "social",
"iconSet" => "circles",
@ -414,7 +414,7 @@ class TravelEmail {
)
), array(
"type" => "text",
"text" => __("<p>Tomorrow we're heading towards Taupo where we'll visit the&nbsp;'Craters of the moon' and go prawn fishing!&nbsp;Hopefully the weather will stay good.</p>\n<p></p>\n<p>Keep on travellin'</p>\n<p>Jane &amp; Steven</p>", 'mailpoet')
"text" => __("<p>Tomorrow we're heading towards Taupo where we'll visit the 'Craters of the moon' and go prawn fishing! Hopefully the weather will stay good.</p>\n<p></p>\n<p>Keep on travellin'</p>\n<p>Jane &amp; Steven</p>", 'mailpoet')
))
))
), array(
@ -446,7 +446,7 @@ class TravelEmail {
)
), array(
"type" => "header",
"text" => ("Display problems?&nbsp;<a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>"),
"text" => ("Display problems? <a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>"),
"styles" => array(
"block" => array(
"backgroundColor" => "transparent"

View File

@ -52,7 +52,7 @@ class WelcomeBlank12Column {
"blocks" => array(
array(
"type" => "header",
"text" => __("Display problems?&nbsp;<a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"text" => __("Display problems? <a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"styles" => array(
"block" => array(
"backgroundColor" => "transparent"
@ -116,7 +116,7 @@ class WelcomeBlank12Column {
),
array(
"type" => "text",
"text" => __("<h1 style=\"text-align: center;\"><strong>Hi, new subscriber!</strong></h1>\n<p></p>\n<p>[subscriber:firstname | default:Subscriber],</p>\n<p></p>\n<p>You recently joined our list and we'd like to give&nbsp;you a warm welcome!</p>", 'mailpoet')
"text" => __("<h1 style=\"text-align: center;\"><strong>Hi, new subscriber!</strong></h1>\n<p></p>\n<p>[subscriber:firstname | default:Subscriber],</p>\n<p></p>\n<p>You recently joined our list and we'd like to give you a warm welcome!</p>", 'mailpoet')
),
array(
"type" => "divider",
@ -182,7 +182,7 @@ class WelcomeBlank12Column {
"blocks" => array(
array(
"type" => "text",
"text" => __("<h3>What's&nbsp;Next?</h3>", 'mailpoet')
"text" => __("<h3>What's Next?</h3>", 'mailpoet')
),
array(
"type" => "text",

View File

@ -52,7 +52,7 @@ class WelcomeBlank1Column {
"blocks" => array(
array(
"type" => "header",
"text" => __("Display problems?&nbsp;<a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"text" => __("Display problems? <a href=\"[link:newsletter_view_in_browser_url]\">Open this email in your web browser</a>", 'mailpoet'),
"styles" => array(
"block" => array(
"backgroundColor" => "transparent"
@ -116,7 +116,7 @@ class WelcomeBlank1Column {
),
array(
"type" => "text",
"text" => __("<h1 style=\"text-align: center;\"><strong>Hi,&nbsp;new subscriber!</strong></h1>\n<p></p>\n<p>[subscriber:firstname | default:Subscriber],</p>\n<p></p>\n<p>You recently joined our list and we'd like to give&nbsp;you a warm welcome!</p>\n<p></p>\n<p>Want to get to know us better? Check&nbsp;out&nbsp;some of our most popular&nbsp;articles:&nbsp;</p>\n<ol>\n<li><a href=\"http://www.mailpoet.com/the-importance-of-focus-when-writing/\">The Importance of Focus When Writing</a></li>\n<li><a href=\"http://www.mailpoet.com/write-great-subject-line/\">How to Write a Great Subject Line</a></li>\n<li><a href=\"http://www.mailpoet.com/just-sit-write-advice-motivation-ernest-hemingway/\">Just Sit Down and Write &ndash; Advice on Motivation from Ernest Hemingway</a></li>\n</ol>", 'mailpoet')
"text" => __("<h1 style=\"text-align: center;\"><strong>Hi, new subscriber!</strong></h1>\n<p></p>\n<p>[subscriber:firstname | default:Subscriber],</p>\n<p></p>\n<p>You recently joined our list and we'd like to give you a warm welcome!</p>\n<p></p>\n<p>Want to get to know us better? Check out some of our most popular articles: </p>\n<ol>\n<li><a href=\"http://www.mailpoet.com/the-importance-of-focus-when-writing/\">The Importance of Focus When Writing</a></li>\n<li><a href=\"http://www.mailpoet.com/write-great-subject-line/\">How to Write a Great Subject Line</a></li>\n<li><a href=\"http://www.mailpoet.com/just-sit-write-advice-motivation-ernest-hemingway/\">Just Sit Down and Write &ndash; Advice on Motivation from Ernest Hemingway</a></li>\n</ol>", 'mailpoet')
)
)
)

View File

@ -8,27 +8,33 @@ use \MailPoet\Twig;
if(!defined('ABSPATH')) exit;
class Renderer {
function __construct() {
protected $cache_path;
protected $caching_enabled;
protected $debugging_enabled;
protected $renderer;
function __construct($caching_enabled = false, $debugging_enabled = false) {
$this->caching_enabled = $caching_enabled;
$this->debugging_enabled = $debugging_enabled;
$this->cache_path = Env::$temp_path . '/cache';
$file_system = new TwigFileSystem(Env::$views_path);
$this->renderer = new TwigEnv(
$file_system,
array(
'cache' => $this->detectCache(),
'debug' => WP_DEBUG,
'debug' => $this->debugging_enabled,
'auto_reload' => true
)
);
}
function init() {
$this->setupDebug();
$this->setupTranslations();
$this->setupFunctions();
$this->setupHandlebars();
$this->setupHelpscout();
$this->setupGlobalVariables();
$this->setupSyntax();
return $this->renderer;
}
function setupTranslations() {
@ -43,6 +49,10 @@ class Renderer {
$this->renderer->addExtension(new Twig\Handlebars());
}
function setupHelpscout() {
$this->renderer->addExtension(new Twig\Helpscout());
}
function setupGlobalVariables() {
$this->renderer->addExtension(new Twig\Assets(array(
'assets_url' => Env::$assets_url,
@ -61,16 +71,30 @@ class Renderer {
}
function detectCache() {
$cache_path = Env::$temp_path . '/cache';
if(WP_DEBUG === false) {
return $cache_path;
}
return false;
return $this->caching_enabled ? $this->cache_path : false;
}
function setupDebug() {
if(WP_DEBUG === true) {
if($this->debugging_enabled) {
$this->renderer->addExtension(new \Twig_Extension_Debug());
}
}
function render($template, $context = array()) {
try {
return $this->renderer->render($template, $context);
} catch(\RuntimeException $e) {
throw new \Exception(sprintf(
__('Failed to render template "%s". Please ensure the template cache folder "%s" exists and has write permissions. Terminated with error: "%s"'),
$template,
$this->cache_path,
$e->getMessage()
));
}
}
function addGlobal($key, $value) {
return $this->renderer->addGlobal($key, $value);
}
}

View File

@ -73,7 +73,11 @@ class Widget {
)
);
echo $this->renderer->render('form/iframe.html', $data);
try {
echo $this->renderer->render('form/iframe.html', $data);
} catch(\Exception $e) {
echo $e->getMessage();
}
}
exit();
}

View File

@ -25,8 +25,7 @@ class Newsletter {
if(!$newsletter) {
return false;
}
// if the newsletter was previously rendered, return it
// otherwise, process/render it
// return the newsletter if it was previously rendered
if(!is_null($queue->getNewsletterRenderedBody())) {
return $newsletter;
}
@ -34,7 +33,7 @@ class Newsletter {
if($this->tracking_enabled) {
// hook to the newsletter post-processing filter and add tracking image
$this->tracking_image_inserted = OpenTracking::addTrackingImage();
// render newsletter and save its
// render newsletter
$rendered_newsletter = $newsletter->render();
// hash and save all links
$rendered_newsletter = LinksTask::process($rendered_newsletter, $newsletter, $queue);

View File

@ -1,6 +1,7 @@
<?php
namespace MailPoet\Form\Util;
use MailPoet\Form\Widget;
use MailPoet\Config\Env;
class Export {
static function getAll($form = null) {
@ -41,39 +42,50 @@ class Export {
case 'php':
$output = array(
'$form_widget = new \MailPoet\Form\Widget();',
'echo $form_widget->widget(array(\'form\' => '.(int)$form['id'].', \'form_type\' => \'php\'));'
'echo $form_widget->widget(array(\'form\' => '.
(int)$form['id'].
', \'form_type\' => \'php\'));'
);
return join("\n", $output);
case 'html':
// TODO: get locale setting in order to load translations
$wp_locale = \get_locale();
$output = array();
$output[] = '<!-- BEGIN Scripts : you should place them in the header of your theme -->';
$output[] = '<!-- '.
__(
'BEGIN Scripts: you should place them in the header of your theme',
'mailpoet'
).
' -->';
// jQuery
$output[] = '<script type="text/javascript" src="'.includes_url().'js/jquery/jquery.js'.'?mpv='.MAILPOET_VERSION.'"></script>';
// CSS
$output[] = '<link rel="stylesheet" type="text/css" href="'.
Env::$assets_url.'/css/public.css?mp_ver='.MAILPOET_VERSION.
'" />';
// (JS) form validation
$output[] = '<script type="text/javascript" src="'.plugins_url('wysija-newsletters/'.'lib/jquery.validationEngine.js?mpv='.MAILPOET_VERSION).'"></script>';
$output[] = '<script type="text/javascript" src="'.plugins_url('wysija-newsletters/'.'lib/jquery.validationEngine-en.js?mpv='.MAILPOET_VERSION).'"></script>';
// jQuery
$output[] = '<script type="text/javascript" src="'.
includes_url().'js/jquery/jquery.js?mp_ver'.MAILPOET_VERSION.
'"></script>';
// (CSS) form validation styles
$output[] = '<link rel="stylesheet" type="text/css" href="'.plugins_url('wysija-newsletters/'.'lib/validationEngine.jquery.css?mpv='.MAILPOET_VERSION).'">';
// JS
$output[] = '<script type="text/javascript" src="'.
Env::$assets_url.'/js/vendor.js?mp_ver='.MAILPOET_VERSION.
'"></script>';
$output[] = '<script type="text/javascript" src="'.
Env::$assets_url.'/js/public.js?mp_ver='.MAILPOET_VERSION.
'"></script>';
// (JS) form submission
$output[] = '<script type="text/javascript" src="'.plugins_url('wysija-newsletters/'.'www/mailpoet_form_subscribe.js?mpv='.MAILPOET_VERSION).'"></script>';
// (JS) variables...
// (JS) variables...
$output[] = '<script type="text/javascript">';
$output[] = ' var MailPoetData = MailPoetData || {';
$output[] = ' var MailPoetForm = MailPoetForm || {';
$output[] = ' is_rtl: '.((int)is_rtl()).",";
$output[] = ' ajax_url: "'.admin_url('admin-ajax.php').'"';
$output[] = ' };';
$output[] = '</script>';
$output[] = '<!--END Scripts-->';
$output[] = '<!-- '.
__('END Scripts', 'mailpoet').
'-->';
$form_widget = new Widget();
$output[] = $form_widget->widget(array(

View File

@ -165,9 +165,12 @@ class Widget extends \WP_Widget {
// render form
$renderer = new Renderer();
$renderer = $renderer->init();
$output = $renderer->render('form/widget.html', $data);
$output = do_shortcode($output);
try {
$output = $renderer->render('form/widget.html', $data);
$output = do_shortcode($output);
} catch(\Exception $e) {
$output = $e->getMessage();
}
}
if($form_type === 'widget') {

47
lib/Helpscout/Beacon.php Normal file
View File

@ -0,0 +1,47 @@
<?php
namespace MailPoet\Helpscout;
use MailPoet\Models\Subscriber;
use MailPoet\Models\Setting;
if(!defined('ABSPATH')) exit;
class Beacon {
static function getData() {
global $wpdb;
$db_version = $wpdb->get_var('SELECT @@VERSION');
$mta = Setting::getValue('mta');
$current_theme = wp_get_theme();
$current_user = wp_get_current_user();
return array(
'name' => $current_user->display_name,
'email' => $current_user->user_email,
'PHP version' => PHP_VERSION,
'MailPoet version' => MAILPOET_VERSION,
'WordPress version' => get_bloginfo('version'),
'Database version' => $db_version,
'WP_MEMORY_LIMIT' => WP_MEMORY_LIMIT,
'WP_MAX_MEMORY_LIMIT' => WP_MAX_MEMORY_LIMIT,
'WP_DEBUG' => WP_DEBUG,
'PHP max_execution_time' => ini_get('max_execution_time'),
'PHP memory_limit' => ini_get('memory_limit'),
'PHP upload_max_filesize' => ini_get('upload_max_filesize'),
'PHP post_max_size' => ini_get('post_max_size'),
'WordPress language' => get_locale(),
'Multisite environment?' => (is_multisite() ? 'Yes' : 'No'),
'Current Theme' => $current_theme->get('Name').
' (version '.$current_theme->get('Version').')',
'Active Plugin names' => join(", ", get_option('active_plugins')),
'Sending Method' => $mta['method'],
'Sending Frequency' => sprintf('%d emails every %d minutes',
$mta['frequency']['emails'],
$mta['frequency']['interval']
),
'Task Scheduler method' => Setting::getValue('cron_trigger.method'),
'Default FROM address' => Setting::getValue('sender.address'),
'Default Reply-To address' => Setting::getValue('reply_to.address'),
'Bounce Email Address' => Setting::getValue('bounce.address'),
'Total number of subscribers' => Subscriber::getTotalSubscribers()
);
}
}

View File

@ -20,6 +20,15 @@ class Handler {
// constrain sort order value to either be "asc" or "desc"
$sort_order = ($sort_order === 'asc') ? 'asc' : 'desc';
// sanitize sort by
$sort_by = (!empty($data['sort_by']))
? filter_var($data['sort_by'], FILTER_SANITIZE_STRING)
: '';
if(empty($sort_by)) {
$sort_by = 'id';
}
$this->data = array(
// extra parameters
'params' => (isset($data['params']) ? $data['params'] : array()),
@ -32,7 +41,7 @@ class Handler {
// searching
'search' => (isset($data['search']) ? $data['search'] : null),
// sorting
'sort_by' => (!empty($data['sort_by']) ? $data['sort_by'] : 'id'),
'sort_by' => $sort_by,
'sort_order' => $sort_order,
// grouping
'group' => (isset($data['group']) ? $data['group'] : null),

View File

@ -17,7 +17,7 @@ class AmazonSES {
public $reply_to;
public $date;
public $date_without_time;
const SES_REGIONS = array(
private $available_regions = array(
'US East (N. Virginia)' => 'us-east-1',
'US West (Oregon)' => 'us-west-2',
'EU (Ireland)' => 'eu-west-1'
@ -26,7 +26,7 @@ class AmazonSES {
function __construct($region, $access_key, $secret_key, $sender, $reply_to) {
$this->aws_access_key = $access_key;
$this->aws_secret_key = $secret_key;
$this->aws_region = (in_array($region, self::SES_REGIONS)) ? $region : false;
$this->aws_region = (in_array($region, $this->available_regions)) ? $region : false;
if(!$this->aws_region) {
throw new \Exception(__('Unsupported Amazon SES region.', 'mailpoet'));
}
@ -42,6 +42,7 @@ class AmazonSES {
$this->date_without_time = gmdate('Ymd');
}
function send($newsletter, $subscriber) {
$result = wp_remote_post(
$this->url,

View File

@ -14,6 +14,8 @@ class Subscriber extends Model {
const STATUS_UNSUBSCRIBED = 'unsubscribed';
const STATUS_UNCONFIRMED = 'unconfirmed';
const SUBSCRIPTION_LIMIT_COOLDOWN = 60;
function __construct() {
parent::__construct();
@ -150,14 +152,49 @@ class Subscriber extends Model {
}
static function verifyToken($email, $token) {
return hash_equals(self::generateToken($email), $token);
return call_user_func('hash_equals', self::generateToken($email), $token);
}
static function subscribe($subscriber_data = array(), $segment_ids = array()) {
// filter out keys from the subscriber_data array
// that should not be editable when subscribing
$reserved_columns = array(
'id',
'wp_user_id',
'status',
'subscribed_ip',
'confirmed_ip',
'confirmed_at',
'created_at',
'updated_at',
'deleted_at'
);
$subscriber_data = array_diff_key(
$subscriber_data,
array_flip($reserved_columns)
);
$signup_confirmation_enabled = (bool)Setting::getValue(
'signup_confirmation.enabled'
);
$subscriber_data['subscribed_ip'] = (isset($_SERVER['REMOTE_ADDR']))
? $_SERVER['REMOTE_ADDR']
: null;
// make sure we don't allow too many subscriptions with the same ip address
$subscription_count = Subscriber::where(
'subscribed_ip',
$subscriber_data['subscribed_ip']
)->whereRaw(
'TIME_TO_SEC(TIMEDIFF(NOW(), created_at)) < ?',
self::SUBSCRIPTION_LIMIT_COOLDOWN
)->count();
if($subscription_count > 0) {
throw new \Exception(__('You need to wait before subscribing again.', 'mailpoet'));
}
$subscriber = self::findOne($subscriber_data['email']);
if($subscriber === false) {
@ -629,7 +666,9 @@ class Subscriber extends Model {
return self::whereIn('status', array(
self::STATUS_SUBSCRIBED,
self::STATUS_UNCONFIRMED
))->count();
))
->whereNull('deleted_at')
->count();
}
static function bulkTrash($orm) {

View File

@ -38,10 +38,11 @@ class Renderer {
function render($data, $column_count) {
$block_content = '';
array_map(function($block) use (&$block_content, &$column_content, $column_count) {
$rendered_block_element = $this->createElementFromBlockType($block, $column_count);
$_this = $this;
array_map(function($block) use (&$block_content, &$column_content, $column_count, $_this) {
$rendered_block_element = $_this->createElementFromBlockType($block, $column_count);
if(isset($block['blocks'])) {
$rendered_block_element = $this->render($block, $column_count);
$rendered_block_element = $_this->render($block, $column_count);
}
// vertical orientation denotes column container
if($block['type'] === 'container' && $block['orientation'] === 'vertical') {

View File

@ -6,6 +6,9 @@ use MailPoet\Newsletter\Renderer\StylesHelper;
class Text {
static function render($element) {
$html = $element['text'];
// replace &nbsp; with spaces
$html = str_replace('&nbsp;', ' ', $html);
$html = str_replace('\xc2\xa0', ' ', $html);
$html = self::convertBlockquotesToTables($html);
$html = self::convertParagraphsToTables($html);
$html = self::styleLists($html);

View File

@ -11,7 +11,7 @@ class Renderer {
$this->getOneColumnTemplate($styles, $class) :
$this->getMultipleColumnsTemplate($styles, $width, $alignment, $class);
$result = array_map(function($content) use ($template) {
$content = self::removePaddingFromLastElement($content);
$content = Renderer::removePaddingFromLastElement($content);
return $template['content_start'] . $content . $template['content_end'];
}, $columns_data);
$result = implode('', $result);

View File

@ -59,13 +59,14 @@ class Renderer {
? $content['blocks']
: array();
$rendered_content = array_map(function($content_block) {
$_this = $this;
$rendered_content = array_map(function($content_block) use($_this) {
$column_count = count($content_block['blocks']);
$column_data = $this->blocks_renderer->render(
$column_data = $_this->blocks_renderer->render(
$content_block,
$column_count
);
return $this->columns_renderer->render(
return $_this->columns_renderer->render(
$content_block['styles'],
$column_count,
$column_data
@ -107,6 +108,7 @@ class Renderer {
}
function renderTextVersion($template) {
$template = utf8_encode($template);
return \Html2Text\Html2Text::convert($template);
}

View File

@ -41,7 +41,7 @@ class StylesHelper {
static function getStyles($data, $type, $ignore_specific_styles = false) {
$styles = array_map(function($attribute, $style) use ($ignore_specific_styles) {
if(!$ignore_specific_styles || !in_array($attribute, $ignore_specific_styles)) {
return self::translateCSSAttribute($attribute) . ': ' . $style . ' !important;';
return StylesHelper::translateCSSAttribute($attribute) . ': ' . $style . ' !important;';
}
}, array_keys($data[$type]), $data[$type]);
return implode('', $styles);

View File

@ -14,4 +14,4 @@ class Date {
);
return (isset($actions[$action])) ? $actions[$action] : false;
}
}
}

View File

@ -125,4 +125,4 @@ class Link {
private static function getShortcode($action) {
return sprintf('[link:%s]', $action);
}
}
}

View File

@ -1,10 +1,10 @@
<?php
namespace MailPoet\Newsletter\Shortcodes\Categories;
use MailPoet\Models\SendingQueue;
use MailPoet\Newsletter\Shortcodes\ShortcodesHelper;
use MailPoet\Models\Newsletter as NewsletterModel;
if(!defined('ABSPATH')) exit;
require_once( ABSPATH . "wp-includes/pluggable.php" );
require_once(ABSPATH . "wp-includes/pluggable.php");
class Newsletter {
static function process($action,
@ -16,7 +16,7 @@ class Newsletter {
) {
switch($action) {
case 'subject':
return ($newsletter) ? $newsletter['subject'] : false;
return ($newsletter) ? $newsletter->subject : false;
case 'total':
return substr_count($content, 'data-post-id');
@ -28,10 +28,10 @@ class Newsletter {
return ($latest_post) ? $latest_post['post_title'] : false;
case 'number':
if($newsletter['type'] !== 'notification') return false;
if($newsletter->type !== NewsletterModel::TYPE_NOTIFICATION_HISTORY) return false;
$sent_newsletters =
SendingQueue::where('newsletter_id', $newsletter['id'])
->where('status', 'completed')
NewsletterModel::where('parent_id', $newsletter->parent_id)
->where('status', NewsletterModel::STATUS_SENT)
->count();
return ++$sent_newsletters;

View File

@ -1,5 +1,6 @@
<?php
namespace MailPoet\Newsletter\Shortcodes\Categories;
use MailPoet\Models\Subscriber as SubscriberModel;
use MailPoet\Models\SubscriberCustomField;
@ -15,14 +16,14 @@ class Subscriber {
) {
switch($action) {
case 'firstname':
return ($subscriber) ? $subscriber['first_name'] : $default_value;
return ($subscriber) ? $subscriber->first_name : $default_value;
case 'lastname':
return ($subscriber) ? $subscriber['last_name'] : $default_value;
return ($subscriber) ? $subscriber->last_name : $default_value;
case 'email':
return ($subscriber) ? $subscriber['email'] : false;
return ($subscriber) ? $subscriber->email : false;
case 'displayname':
if($subscriber && $subscriber['wp_user_id']) {
$wp_user = get_userdata($subscriber['wp_user_id']);
if($subscriber && $subscriber->wp_user_id) {
$wp_user = get_userdata($subscriber->wp_user_id);
return $wp_user->user_login;
}
return $default_value;
@ -31,10 +32,10 @@ class Subscriber {
->count();
default:
if(preg_match('/cf_(\d+)/', $action, $custom_field) &&
!empty($subscriber['id'])
!empty($subscriber->id)
) {
$custom_field = SubscriberCustomField
::where('subscriber_id', $subscriber['id'])
::where('subscriber_id', $subscriber->id)
->where('custom_field_id', $custom_field[1])
->findOne();
return ($custom_field) ? $custom_field->value : false;

View File

@ -12,15 +12,9 @@ class Shortcodes {
$subscriber = false,
$queue = false
) {
$this->newsletter = (is_object($newsletter)) ?
$newsletter->asArray() :
$newsletter;
$this->subscriber = (is_object($subscriber)) ?
$subscriber->asArray() :
$subscriber;
$this->queue = (is_object($queue)) ?
$queue->asArray() :
$queue;
$this->newsletter = $newsletter;
$this->subscriber = $subscriber;
$this->queue = $queue;
}
function extract($content, $categories = false) {
@ -48,9 +42,10 @@ class Shortcodes {
}
function process($shortcodes, $content = false) {
$_this = $this;
$processed_shortcodes = array_map(
function($shortcode) use ($content) {
$shortcode_details = $this->match($shortcode);
function($shortcode) use ($content, $_this) {
$shortcode_details = $_this->match($shortcode);
$shortcode_category = !empty($shortcode_details['category']) ?
ucfirst($shortcode_details['category']) :
false;
@ -58,7 +53,7 @@ class Shortcodes {
$shortcode_details['action'] :
false;
$shortcode_class =
self::SHORTCODE_CATEGORY_NAMESPACE . $shortcode_category;
Shortcodes::SHORTCODE_CATEGORY_NAMESPACE . $shortcode_category;
$shortcode_default_value = !empty($shortcode_details['default']) ?
$shortcode_details['default'] :
false;
@ -66,9 +61,9 @@ class Shortcodes {
$custom_shortcode = apply_filters(
'mailpoet_newsletter_shortcode',
$shortcode,
$this->newsletter,
$this->subscriber,
$this->queue,
$_this->newsletter,
$_this->subscriber,
$_this->queue,
$content
);
return ($custom_shortcode === $shortcode) ?
@ -78,9 +73,9 @@ class Shortcodes {
return $shortcode_class::process(
$shortcode_action,
$shortcode_default_value,
$this->newsletter,
$this->subscriber,
$this->queue,
$_this->newsletter,
$_this->subscriber,
$_this->queue,
$content
);
}, $shortcodes);

View File

@ -1,8 +1,6 @@
<?php
namespace MailPoet\Settings;
use MailPoet\Mailer\Methods\AmazonSES;
class Hosts {
private static $_smtp = array(
'AmazonSES' => array(
@ -14,7 +12,11 @@ class Hosts {
'access_key',
'secret_key'
),
'regions' => AmazonSES::SES_REGIONS
'regions' => array(
'US East (N. Virginia)' => 'us-east-1',
'US West (Oregon)' => 'us-west-2',
'EU (Ireland)' => 'eu-west-1'
)
),
'SendGrid' => array(
'name' => 'SendGrid',

View File

@ -83,10 +83,8 @@ class MailChimp {
}
if(!isset($header_hash)) {
$header_hash = md5(implode(',', $header));
} else {
if(md5(implode(',', $header) !== $header_hash)) {
return $this->throwException('headers');
}
} elseif(md5(implode(',', $header) !== $header_hash)) {
return $this->throwException('headers');
}
} else {
$subscribers[] = $obj;
@ -147,4 +145,4 @@ class MailChimp {
}
throw new \Exception($errorMessage);
}
}
}

View File

@ -7,18 +7,23 @@ class Manage {
static function onSave() {
$action = (isset($_POST['action']) ? $_POST['action'] : null);
$token = (isset($_POST['token']) ? $_POST['token'] : null);
if($action !== 'mailpoet_subscription_update') {
Url::redirectBack();
}
$reserved_keywords = array('action', 'mailpoet_redirect');
$reserved_keywords = array('action', 'token', 'mailpoet_redirect');
$subscriber_data = array_diff_key(
$_POST,
array_flip($reserved_keywords)
);
if(isset($subscriber_data['email'])) {
if(
isset($subscriber_data['email'])
&&
Subscriber::verifyToken($subscriber_data['email'], $token)
) {
if($subscriber_data['email'] !== Pages::DEMO_EMAIL) {
$subscriber = Subscriber::createOrUpdate($subscriber_data);
$errors = $subscriber->getErrors();

View File

@ -59,6 +59,8 @@ class Pages {
function confirm() {
if($this->subscriber !== false) {
$this->subscriber->status = Subscriber::STATUS_SUBSCRIBED;
$this->subscriber->confirmed_ip = $_SERVER['REMOTE_ADDR'];
$this->subscriber->setExpr('confirmed_at', 'NOW()');
$this->subscriber->save();
}
}
@ -324,7 +326,12 @@ class Pages {
$form_html .= '<input type="hidden" name="segments" value="" />';
$form_html .= '<input type="hidden" name="mailpoet_redirect" '.
'value="'.Url::getCurrentUrl().'" />';
$form_html .= '<input type="hidden" name="email" value="'.$subscriber->email.'" />';
$form_html .= '<input type="hidden" name="email" value="'.
$subscriber->email.
'" />';
$form_html .= '<input type="hidden" name="token" value="'.
Subscriber::generateToken($subscriber->email).
'" />';
$form_html .= '<p class="mailpoet_paragraph">';
$form_html .= '<label>Email *<br /><strong>'.$subscriber->email.'</strong></label>';

21
lib/Twig/Helpscout.php Normal file
View File

@ -0,0 +1,21 @@
<?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(
'get_helpscout_data',
'\MailPoet\Helpscout\Beacon::getData',
array('is_safe' => array('all'))
)
);
}
}

View File

@ -21,16 +21,15 @@ class I18n extends \Twig_Extension {
$twig_functions = array();
// list of WP functions to map
$functions = array(
'localize',
'__',
'_n',
'date',
'date_format'
'localize' => 'localize',
'__' => 'translate',
'_n' => 'pluralize',
'date' => 'date'
);
foreach($functions as $function) {
foreach($functions as $twig_function => $function) {
$twig_functions[] = new \Twig_SimpleFunction(
$function,
$twig_function,
array($this, $function),
array('is_safe' => array('all'))
);
@ -52,13 +51,13 @@ class I18n extends \Twig_Extension {
return join("\n", $output);
}
function __() {
function translate() {
$args = func_get_args();
return call_user_func_array('__', $this->setTextDomain($args));
}
function _n() {
function pluralize() {
$args = func_get_args();
return call_user_func_array('_n', $this->setTextDomain($args));

View File

@ -185,15 +185,8 @@ class CSS {
* If you pass $contents then the original HTML is not downloaded and $contents is used instead.
* $url is mandatory as it is used to resolve the links to the stylesheets found in the HTML.
*/
function inlineCSS($url, $contents=null)
{
// Download the HTML if it was not provided
if($contents === null) {
$html = HtmlDomParser::file_get_html($url, false, null, -1, -1, true, true, DEFAULT_TARGET_CHARSET, false, DEFAULT_BR_TEXT, DEFAULT_SPAN_TEXT);
} else {
// use the data provided!
$html = HtmlDomParser::str_get_html($contents, true, true, DEFAULT_TARGET_CHARSET, false, DEFAULT_BR_TEXT, DEFAULT_SPAN_TEXT);
}
function inlineCSS($url, $contents=null) {
$html = \pQuery::parseStr($contents);
if(!is_object($html)) {
return false;
@ -202,13 +195,13 @@ class CSS {
$css_blocks = '';
// Find all <style> blocks and cut styles from them (leaving media queries)
foreach($html->find('style') as $style) {
list($_css_to_parse, $_css_to_keep) = self::splitMediaQueries($style->innertext());
foreach($html->query('style') as $style) {
list($_css_to_parse, $_css_to_keep) = self::splitMediaQueries($style->getInnerText());
$css_blocks .= $_css_to_parse;
if(!empty($_css_to_keep)) {
$style->innertext = $_css_to_keep;
$style->setInnerText($_css_to_keep);
} else {
$style->outertext = '';
$style->setOuterText('');
}
}
@ -225,7 +218,7 @@ class CSS {
// We loop over each rule by increasing order of specificity, find the nodes matching the selector
// and apply the CSS properties
foreach ($rules as $rule) {
foreach($html->find($rule['selector']) as $node) {
foreach($html->query($rule['selector']) as $node) {
// I'm leaving this for debug purposes, it has proved useful.
/*
if($node->already_styled === 'yes')

View File

@ -0,0 +1,19 @@
<?php
namespace MailPoet\Util\License\Features;
use MailPoet\Models\Subscriber as SubscriberModel;
use MailPoet\Util\License\License;
class Subscribers {
public $license;
const SUBSCRIBERS_LIMIT = 2000;
function __construct($license = false) {
$this->license = ($license) ? $license : License::getLicense();
}
function check($subscribers_limit = self::SUBSCRIBERS_LIMIT) {
if($this->license) return false;
return SubscriberModel::getTotalSubscribers() > $subscribers_limit;
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace MailPoet\Util\License;
class License {
static function getLicense($license = false) {
if(!$license) {
$license = defined('MAILPOET_PREMIUM_LICENSE') ?
MAILPOET_PREMIUM_LICENSE :
false;
}
return $license;
}
}

View File

@ -11,7 +11,7 @@ class Notice {
private $type;
private $message;
protected function __construct($type, $message) {
function __construct($type, $message) {
$this->type = $type;
$this->message = $message;
}

View File

@ -4,9 +4,9 @@ if(!defined('ABSPATH')) exit;
use \MailPoet\Config\Initializer;
/*
* Plugin Name: MailPoet
* Version: 0.0.50
* Version: 3.0.0-beta.4
* Plugin URI: http://www.mailpoet.com
* Description: MailPoet Newsletters.
* Description: Create and send beautiful email newsletters, autoresponders, and post notifications without leaving WordPress. This is a beta version of our brand new plugin!
* Author: MailPoet
* Author URI: http://www.mailpoet.com
* Requires at least: 4.0
@ -22,7 +22,7 @@ use \MailPoet\Config\Initializer;
require 'vendor/autoload.php';
define('MAILPOET_VERSION', '0.0.50');
define('MAILPOET_VERSION', '3.0.0-beta.4');
$initializer = new Initializer(array(
'file' => __FILE__,

View File

@ -12,10 +12,8 @@
"backbone.marionette": "2.4.7",
"backbone.radio": "1.0.5",
"backbone.supermodel": "1.2.0",
"c3": "~0.4.10",
"classnames": "^2.1.3",
"codemirror": "^5.8.0",
"d3": "~3.5.5",
"handlebars": "3.0.3",
"history": "1.13.1",
"html2canvas": "0.5.0-alpha2",
@ -26,17 +24,13 @@
"parsleyjs": "^2.1.2",
"react": "latest",
"react-dom": "latest",
"react-infinity": "latest",
"react-prefixr": "latest",
"react-router": "latest",
"react-string-replace": "^0.3.2",
"react-waypoint": "latest",
"select2": "^4.0.0",
"spectrum-colorpicker": "^1.6.2",
"tinymce": "4.3.12",
"underscore": "1.8.3",
"velocity-animate": "1.2.3",
"xss": "^0.2.10"
"velocity-animate": "1.2.3"
},
"devDependencies": {
"expose-loader": "latest",
@ -55,7 +49,6 @@
"sinon": "1.14.1",
"sinon-chai": "2.7.0",
"stylus": "latest",
"swag": "~0.7.0",
"webpack": "1.11.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -2,8 +2,8 @@
Contributors: mailpoet
Tags: newsletter, email, welcome email, post notification, autoresponder, mailchimp, signup, smtp
Requires at least: 4.6
Tested up to: 4.6
Stable tag: 3.0.0
Tested up to: 4.6.1
Stable tag: 3.0.0-beta.4
Create and send beautiful emails and newsletters from WordPress.
== Description ==
@ -83,7 +83,35 @@ Our [support site](https://docs.mailpoet.com/) has plenty of articles. You can w
== Changelog ==
= 3.0.0 - 2016-09 =
= 3.0.0-beta.4 - 2016-11 =
* Hello world.
* Updated HelpScout beacon to provide support articles;
* Fixed handling of URLs containing shortcodes in newsletter editor;
* Security fixes;
* Fixed subscriber count to not count trashed subscribers;
* Fixed template renderer to gracefully display an error when template caching issues arise;
* Added security measures to prevent mass subscriptions.
= 3.0.0-beta.3 - 2016-11 =
* Improved compatibility with PHP 7;
* Fixed showing current newsletter status in newsletter listings when there are no subscribers to send to;
* Removed obsolete libraries;
* Fixed security issues;
* Fixed html form embed code to use correct paths;
* Updated settings documentation URL;
* Improved text fitting in newsletter type/template selection boxes;
* Fixed Populator compatibility with earlier PHP versions;
* Fixed newsletter number shortcode for notification newsletters;
* Enhanced HelpScout support beacon report with extra support data;
* Fixed email renderer to not throw entity warnings on earlier PHP versions;
* Fixed newsletter preview incompatibility errors for earlier PHP versions;
= 3.0.0-beta.2 - 2016-10 =
* Fixed compatibility issues with PHP versions earlier than PHP 5.6;
* Renamed 'Emails' email type to 'Newsletters';
= 3.0.0-beta.1 - 2016-10 =
* Initial public beta release.

View File

@ -15,7 +15,7 @@
<!-- All parameters in function signature should be used within the function -->
<!--<rule ref="Generic.CodeAnalysis.UnusedFunctionParameter"/>-->
<!-- Don't use methods that extend and only call the parent method -->
<rule ref="Generic.CodeAnalysis.UselessOverridingMethod"/>
<!--<rule ref="Generic.CodeAnalysis.UselessOverridingMethod"/>-->
<!-- Disallow usage of BOMs -->
<rule ref="Generic.Files.ByteOrderMark"/>
@ -120,4 +120,7 @@
<!-- Remove space between if/for/while and opening parenthesis -->
<rule ref="MailPoet.ControlStructures.ControlSignature"/>
<!-- Run against the PHPCompatibility ruleset -->
<rule ref="PHPCompatibility" />
<config name="testVersion" value="5.3-7.0"/>
</ruleset>

View File

@ -4,6 +4,7 @@ use \MailPoet\API\Endpoints\Subscribers;
use \MailPoet\API\Response as APIResponse;
use \MailPoet\Models\Subscriber;
use \MailPoet\Models\Segment;
use \MailPoet\Models\Setting;
class SubscribersTest extends MailPoetTest {
function _before() {
@ -26,6 +27,12 @@ class SubscribersTest extends MailPoetTest {
$this->segment_2->id
)
));
// setup mailer
Setting::setValue('sender', array(
'address' => 'sender@mailpoet.com',
'name' => 'Sender'
));
}
function testItCanGetASubscriber() {
@ -354,6 +361,46 @@ class SubscribersTest extends MailPoetTest {
expect($response->errors[0]['message'])->contains('has no method');
}
function testItCannotSubscribeWithoutSegments() {
$router = new Subscribers();
$response = $router->subscribe(array(
'email' => 'toto@mailpoet.com'
// no segments specified
));
expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST);
expect($response->errors[0]['message'])->equals('Please select a list.');
}
function testItCanSubscribe() {
$router = new Subscribers();
$response = $router->subscribe(array(
'email' => 'toto@mailpoet.com',
'segments' => array($this->segment_1->id, $this->segment_2->id)
));
expect($response->status)->equals(APIResponse::STATUS_OK);
}
function testItCannotMassSubscribe() {
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
$router = new Subscribers();
$response = $router->subscribe(array(
'email' => 'toto@mailpoet.com',
'segments' => array($this->segment_1->id, $this->segment_2->id)
));
try {
$response = $router->subscribe(array(
'email' => 'tata@mailpoet.com',
'segments' => array($this->segment_1->id, $this->segment_2->id)
));
$this->fail('It should not be possible to subscribe a second time so soon');
} catch(\Exception $e) {
expect($e->getMessage())->equals('You need to wait before subscribing again.');
}
}
function _after() {
Segment::deleteMany();
Subscriber::deleteMany();

View File

@ -1,9 +1,10 @@
<?php
use Codeception\Util\Stub;
use \MailPoet\Config\Renderer;
class RendererTest extends MailPoetTest {
function _before() {
$this->renderer = new Renderer();
$this->renderer = new Renderer($caching = false, $debugging = false);
}
function testItWillNotEnableCacheWhenWpDebugIsOn() {
@ -11,6 +12,47 @@ class RendererTest extends MailPoetTest {
expect($result)->equals(false);
}
function testItDelegatesRenderingToTwig() {
$renderer = Stub::construct(
$this->renderer,
array(),
array(
'renderer' => Stub::makeEmpty('Twig_Environment',
array(
'render' => Stub::atLeastOnce(function() { return 'test render'; }),
)
),
)
);
expect($renderer->render('non-existing-template.html', array('somekey' => 'someval')))->equals('test render');
}
function testItRethrowsTwigCacheExceptions() {
$exception_message = 'this is a test error';
$renderer = Stub::construct(
$this->renderer,
array(true, false),
array(
'renderer' => Stub::makeEmpty('Twig_Environment',
array(
'render' => Stub::atLeastOnce(function() use ($exception_message) {
throw new \RuntimeException($exception_message);
}),
)
),
)
);
try {
$renderer->render('non-existing-template.html', array('somekey' => 'someval'));
self::fail('Twig exception was not rethrown');
} catch(\Exception $e) {
expect($e->getMessage())->contains($exception_message);
expect($e->getMessage())->notEquals($exception_message);
}
}
function _after() {
}
}

View File

@ -7,11 +7,10 @@ if(!defined('ABSPATH')) exit;
class ShortcodesTaskTest extends MailPoetTest {
function testItCanReplaceShortcodes() {
$queue = $newsletter = array(
$queue = $newsletter = (object)array(
'id' => 1
);
$subscriber = array(
$subscriber = (object)array(
'email' => 'test@xample. com',
'first_name' => 'John',
'last_name' => 'Doe'

View File

@ -0,0 +1,107 @@
<?php
use \MailPoet\Helpscout\Beacon;
use \MailPoet\Models\Setting;
use \MailPoet\Models\Subscriber;
class BeaconTest extends MailPoetTest {
function _before() {
// create 3 users (1 confirmed, 1 subscribed, 1 unsubscribed)
Subscriber::createOrUpdate(array(
'email' => 'user1@mailpoet.com',
'status' => Subscriber::STATUS_SUBSCRIBED
));
Subscriber::createOrUpdate(array(
'email' => 'user2@mailpoet.com',
'status' => Subscriber::STATUS_UNCONFIRMED
));
Subscriber::createOrUpdate(array(
'email' => 'user3@mailpoet.com',
'status' => Subscriber::STATUS_UNSUBSCRIBED
));
$this->beacon_data = Beacon::getData();
}
function testItReturnsPhpVersion() {
expect($this->beacon_data['PHP version'])->equals(PHP_VERSION);
}
function testItReturnsMailpoetVersion() {
expect($this->beacon_data['MailPoet version'])->equals(MAILPOET_VERSION);
}
function testItReturnsWordpressVersion() {
expect($this->beacon_data['WordPress version'])->equals(get_bloginfo('version'));
}
function testItReturnsDatabaseVersion() {
global $wpdb;
$db_version = $wpdb->get_var('SELECT @@VERSION');
expect($this->beacon_data['Database version'])->equals($db_version);
}
function testItReturnsWpMemoryLimit() {
expect($this->beacon_data['WP_MEMORY_LIMIT'])->equals(WP_MEMORY_LIMIT);
}
function testItReturnsWpMaxMemoryLimit() {
expect($this->beacon_data['WP_MAX_MEMORY_LIMIT'])->equals(WP_MAX_MEMORY_LIMIT);
}
function testItReturnsWpDebugValue() {
expect($this->beacon_data['WP_DEBUG'])->equals(WP_DEBUG);
}
function testItReturnsPhpMaxExecutionTime() {
expect($this->beacon_data['PHP max_execution_time'])->equals(ini_get('max_execution_time'));
}
function testItReturnsPhpMemoryLimit() {
expect($this->beacon_data['PHP memory_limit'])->equals(ini_get('memory_limit'));
}
function testItReturnsPhpUploadMaxFilesize() {
expect($this->beacon_data['PHP upload_max_filesize'])->equals(ini_get('upload_max_filesize'));
}
function testItReturnsPhpPostMaxSize() {
expect($this->beacon_data['PHP post_max_size'])->equals(ini_get('post_max_size'));
}
function testItReturnsWpLanguage() {
expect($this->beacon_data['WordPress language'])->equals(get_locale());
}
function testItReturnsIfWpIsMultisite() {
expect($this->beacon_data['Multisite environment?'])->equals(is_multisite() ? 'Yes' : 'No');
}
function testItReturnsCurrentThemeNameAndVersion() {
$current_theme = wp_get_theme();
expect($this->beacon_data['Current Theme'])->contains($current_theme->get('Name'));
expect($this->beacon_data['Current Theme'])->contains($current_theme->get('Version'));
}
function testItReturnsActivePlugins() {
expect($this->beacon_data['Active Plugin names'])->equals(join(", ", get_option('active_plugins')));
}
function testItReturnsSendingMethodDetails() {
$mta = Setting::getValue('mta');
expect($this->beacon_data['Sending Method'])->equals($mta['method']);
expect($this->beacon_data['Sending Frequency'])->contains($mta['frequency']['emails'].' emails');
expect($this->beacon_data['Sending Frequency'])->contains($mta['frequency']['interval'].' minutes');
}
function testItReturnsSomeSettings() {
expect($this->beacon_data['Task Scheduler method'])->equals(Setting::getValue('cron_trigger.method'));
expect($this->beacon_data['Default FROM address'])->equals(Setting::getValue('sender.address'));
expect($this->beacon_data['Default Reply-To address'])->equals(Setting::getValue('reply_to.address'));
expect($this->beacon_data['Bounce Email Address'])->equals(Setting::getValue('bounce.address'));
}
function testItReturnsTotalNumberOfSubscribers() {
// unsubscribed users are not taken into account
expect($this->beacon_data['Total number of subscribers'])->equals(2);
}
}

View File

@ -314,6 +314,42 @@ class SubscriberTest extends MailPoetTest {
expect($subscriber->deleted_at)->equals(null);
}
function testItCannotSubscribeWithReservedColumns() {
$segment = Segment::create();
$segment->hydrate(array('name' => 'List #1'));
$segment->save();
$subscriber = Subscriber::subscribe(
array(
'email' => 'donald@mailpoet.com',
'first_name' => 'Donald',
'last_name' => 'Trump',
// the fields below should NOT be taken into account
'id' => 1337,
'wp_user_id' => 7331,
'status' => Subscriber::STATUS_SUBSCRIBED,
'created_at' => '1984-03-09 00:00:01',
'updated_at' => '1984-03-09 00:00:02',
'deleted_at' => '1984-03-09 00:00:03'
),
array($segment->id())
);
expect($subscriber->id > 0)->equals(true);
expect($subscriber->id)->notEquals(1337);
expect($subscriber->segments()->count())->equals(1);
expect($subscriber->email)->equals('donald@mailpoet.com');
expect($subscriber->first_name)->equals('Donald');
expect($subscriber->last_name)->equals('Trump');
expect($subscriber->wp_user_id)->equals(null);
expect($subscriber->status)->equals(Subscriber::STATUS_UNCONFIRMED);
expect($subscriber->created_at)->notEquals('1984-03-09 00:00:01');
expect($subscriber->updated_at)->notEquals('1984-03-09 00:00:02');
expect($subscriber->created_at)->equals($subscriber->updated_at);
expect($subscriber->deleted_at)->equals(null);
}
function testItCanBeUpdatedByEmail() {
$subscriber_updated = Subscriber::createOrUpdate(array(
'email' => $this->data['email'],
@ -465,6 +501,12 @@ class SubscriberTest extends MailPoetTest {
'status' => Subscriber::STATUS_UNSUBSCRIBED
));
$subscriber_4 = Subscriber::createOrUpdate(array(
'email' => 'subscriber_4@mailpoet.com',
'status' => Subscriber::STATUS_SUBSCRIBED,
'deleted_at' => Carbon::now()->toDateTimeString()
));
// counts only subscribed & unconfirmed users
$total = Subscriber::getTotalSubscribers();
expect($total)->equals(2);

View File

@ -2,6 +2,7 @@
use MailPoet\Config\Populator;
use MailPoet\Models\CustomField;
use MailPoet\Models\Newsletter;
use MailPoet\Models\SendingQueue;
use MailPoet\Models\Setting;
use MailPoet\Models\Subscriber;
@ -22,11 +23,7 @@ class ShortcodesTest extends MailPoetTest {
$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->newsletter = $this->_createNewsletter();
$this->shortcodes_object = new MailPoet\Newsletter\Shortcodes\Shortcodes(
$this->newsletter,
$this->subscriber
@ -72,7 +69,7 @@ class ShortcodesTest extends MailPoetTest {
$shortcode = array('[some:shortcode]');
$result = $shortcodes_object->process($shortcode);
expect($result[0])->false();
add_filter('mailpoet_newsletter_shortcode', function (
add_filter('mailpoet_newsletter_shortcode', function(
$shortcode, $newsletter, $subscriber, $queue, $content) {
if($shortcode === '[some:shortcode]') return 'success';
}, 10, 5);
@ -98,7 +95,7 @@ class ShortcodesTest extends MailPoetTest {
'<a href="#">not post</a>';
$result =
$shortcodes_object->process(array('[newsletter:subject]'));
expect($result[0])->equals($this->newsletter['subject']);
expect($result[0])->equals($this->newsletter->subject);
$result =
$shortcodes_object->process(array('[newsletter:total]'), $content);
expect($result[0])->equals(2);
@ -106,12 +103,32 @@ class ShortcodesTest extends MailPoetTest {
$shortcodes_object->process(array('[newsletter:post_title]'));
$wp_post = get_post($this->WP_post);
expect($result['0'])->equals($wp_post->post_title);
$result =
$shortcodes_object->process(array('[newsletter:number]'));
}
function itCanProcessPostNotificationNewsletterNumberShortcode() {
// create first post notification
$post_notification_history = $this->_createNewsletter(
$parent_id = $this->newsletter_id,
$type = Newsletter::TYPE_NOTIFICATION_HISTORY
);
$shortcodes_object = new MailPoet\Newsletter\Shortcodes\Shortcodes(
$post_notification_history,
$this->subscriber
);
$result = $shortcodes_object->process(array('[newsletter:number]'));
expect($result['0'])->equals(1);
$queue = $this->_createQueue();
$result =
$shortcodes_object->process(array('[newsletter:number]'));
// create another post notification
$post_notification_history = $this->_createNewsletter(
$parent_id = $this->newsletter_id,
$type = Newsletter::TYPE_NOTIFICATION_HISTORY
);
$shortcodes_object = new MailPoet\Newsletter\Shortcodes\Shortcodes(
$post_notification_history,
$this->subscriber
);
$result = $shortcodes_object->process(array('[newsletter:number]'));
expect($result['0'])->equals(2);
}
@ -228,7 +245,7 @@ class ShortcodesTest extends MailPoetTest {
$shortcode = '[link:shortcode]';
$result = $shortcodes_object->process(array($shortcode));
expect($result[0])->false();
add_filter('mailpoet_newsletter_shortcode_link', function (
add_filter('mailpoet_newsletter_shortcode_link', function(
$shortcode, $newsletter, $subscriber, $queue) {
if($shortcode === '[link:shortcode]') return 'success';
}, 10, 4);
@ -271,15 +288,30 @@ class ShortcodesTest extends MailPoetTest {
return Subscriber::findOne($subscriber->id);
}
function _createNewsletter($parent_id = null, $type = Newsletter::TYPE_NOTIFICATION) {
$newsletter = Newsletter::create();
$newsletter->hydrate(
array(
'subject' => 'some subject',
'type' => $type,
'status' => Newsletter::STATUS_SENT,
'parent_id' => $parent_id,
)
);
$newsletter->save();
return Newsletter::findOne($newsletter->id);
}
function _createQueue() {
$queue = SendingQueue::create();
$queue->newsletter_id = $this->newsletter['id'];
$queue->status = 'completed';
$queue->save();
return $queue;
return SendingQueue::findOne($queue->id);
}
function _after() {
ORM::raw_execute('TRUNCATE ' . Newsletter::$_table);
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
ORM::raw_execute('TRUNCATE ' . SendingQueue::$_table);
ORM::raw_execute('TRUNCATE ' . CustomField::$_table);

View File

@ -0,0 +1,34 @@
<?php
use Codeception\Util\Fixtures;
use Codeception\Util\Stub;
use MailPoet\Models\Subscriber;
use MailPoet\Util\License\Features\Subscribers as SubscribersFeature;
class SubscribersFeaturesTest extends MailPoetTest {
function testChecksIfSubscribersWithinLimitWhenPremiumLicenseDoesNotExist() {
$subscribers_feature = new SubscribersFeature();
expect($subscribers_feature->check(0))->false();
$subscriber = Subscriber::create();
$subscriber->hydrate(Fixtures::get('subscriber_template'));
$subscriber->save();
expect($subscribers_feature->check(0))->true();
}
function testChecksIfSubscribersWithinLimitWhenPremiumLicenseExists() {
$subscribers_feature = Stub::construct(
new SubscribersFeature(),
array(
'license' => true
)
);
$subscriber = Subscriber::create();
$subscriber->hydrate(Fixtures::get('subscriber_template'));
$subscriber->save();
expect($subscribers_feature->check(0))->false();
}
function _after() {
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
}
}

View File

@ -0,0 +1,10 @@
<?php
use MailPoet\Util\License\License;
class LicenseTest extends MailPoetTest {
function testItGetsLicense() {
expect(License::getLicense())->false();
expect(License::getLicense('valid'))->equals('valid');
}
}

View File

@ -57,10 +57,18 @@ jQuery('.toplevel_page_mailpoet-newsletters.menu-top-last')
<script type="text/javascript">
if(window['HS'] !== undefined) {
// HelpScout Beacon: Configuration
HS.beacon.config({
icon: 'message',
zIndex: 50000,
instructions: '<%= __('Want to give feedback to the MailPoet team? Contact us here. Please provide as much information as possible!') %>',
instructions: "<%= __('Want to give feedback to the MailPoet team? Contact us here. Please provide as much information as possible!') %>"
});
// HelpScout Beacon: Custom information
HS.beacon.ready(function() {
HS.beacon.identify(
<%= json_encode(get_helpscout_data()) %>
);
});
}
</script>

View File

@ -322,8 +322,8 @@
'failedToFetchAvailablePosts': __('Failed to fetch available posts'),
'failedToFetchRenderedPosts': __('Failed to fetch rendered posts'),
'shortcodesWindowTitle': __('Select a shortcode'),
'unsubscribeLinkMissing': __('All newsletters must include an "Unsubscribe" link. Add a footer widget to your newsletter to continue'),
'newsletterPreviewEmailMissing': __('Enter an email address to send the preview newsletter to'),
'unsubscribeLinkMissing': __('All emails must include an "Unsubscribe" link. Add a footer widget to your email to continue.'),
'newsletterPreviewEmailMissing': __('Enter an email address to send the preview newsletter to.'),
'newsletterPreviewSent': __('Your test email has been sent!'),
'templateNameMissing': __('Please add a template name'),
'templateDescriptionMissing': __('Please add a template description'),
@ -1185,7 +1185,7 @@
validateUnsubscribeLinkPresent: true, // TODO: Add validation based on whether Mailpoet MTA is used or not
},
urls: {
send: '<%= admin_url('admin.php?page=mailpoet-newsletters#/send/' ~ params('id')) %>',
send: '<%= admin_url('admin.php?page=mailpoet-newsletters#/send/' ~ (params('id') | number_format)) %>',
imageMissing: '<%= image_url(
"newsletter_editor/image-missing.svg"
) %>',
@ -1196,7 +1196,7 @@
endpoint: 'newsletters',
action: 'get',
data: {
id: <%= params('id') %>
id: "<%= params('id') | number_format %>",
}
}).always(function() {
MailPoet.Modal.loading(false);

View File

@ -1,2 +1,2 @@
<div class="mailpoet_container_empty">{{#ifCond emptyContainerMessage '!==' ''}}{{emptyContainerMessage}}{{else}}{{#if isRoot}}<%= __('Drop layout here!') %>{{else}}<%= __('Drop content here!') %>{{/if}}{{/ifCond}}</div>
<div class="mailpoet_container_empty">{{#ifCond emptyContainerMessage '!==' ''}}{{emptyContainerMessage}}{{else}}{{#if isRoot}}<%= __('Add a column block here.') %>{{else}}<%= __('Add a content block here.') %>{{/if}}{{/ifCond}}</div>
{{debug}}

View File

@ -1,4 +1,4 @@
<h3><%= __('Layout') %></h3>
<h3><%= __('Columns') %></h3>
<div class="mailpoet_form_field">
<label>
<div class="mailpoet_form_field_input_option">

View File

@ -1,4 +1,4 @@
<div class="handlediv" title="Click to toggle"><br></div>
<h3><%= __('Layout') %></h3>
<h3><%= __('Columns') %></h3>
<div class="mailpoet_region_content clearfix">
</div>

View File

@ -20,7 +20,7 @@
<% block translations %>
<%= localize({
'pageTitle': __('Newsletters'),
'pageTitle': __('Emails'),
'tabStandardTitle': __('Newsletters'),
'tabWelcomeTitle': __('Welcome Emails'),
@ -75,7 +75,7 @@
'trash': __('Trash'),
'edit': __('Edit'),
'duplicate': __('Duplicate'),
'newsletterDuplicated': __('Newsletter "%$1s" has been duplicated'),
'newsletterDuplicated': __('Email "%$1s" has been duplicated.'),
'notSentYet': __('Not sent yet'),
'scheduledFor': __('Scheduled for'),
'scheduleIt': __('Schedule it'),
@ -97,18 +97,18 @@
'delete': __('Delete'),
'select': __('Select'),
'preview': __('Preview'),
'selectTemplateTitle': __('Select a template'),
'selectTemplateTitle': __('Select a responsive template'),
'draftNewsletterTitle': __('Subject'),
'pickCampaignType': __('Pick a type of campaign'),
'pickCampaignType': __('Select type of email'),
'regularNewsletterTypeTitle': __('Newsletter'),
'regularNewsletterTypeDescription': __('Send a newsletter with images, buttons, dividers, and social bookmarks. Or, just send a basic text email.'),
'create': __('Create'),
'welcomeNewsletterTypeTitle': __('Welcome Email'),
'welcomeNewsletterTypeDescription': __('Automatically send an email (or series of emails) to new subscribers or WordPress users. Send a day, a week, or a month after they sign up.'),
'setUp': __('Set up'),
'postNotificationNewsletterTypeTitle': __('Post Notifications'),
'postNotificationsNewsletterTypeDescription': __('Automatically send posts immediately, daily, weekly or monthly. Filter by categories, if you like.'),
'postNotificationNewsletterTypeTitle': __('Latest Post Notifications'),
'postNotificationsNewsletterTypeDescription': __('Let MailPoet email your subscribers with your latest content. You can send daily, weekly, monthly, or even immediately after publication.'),
'selectFrequency': __('Select a frequency'),
'postNotificationSubjectLineTip': __("Insert [newsletter:total] to show number of posts, [newsletter:post_title] to show the latest post's title & [newsletter:number] to display the issue number."),
'activate': __('Activate'),
@ -146,7 +146,7 @@
'subjectLineTip': __("Be creative! It's the first thing that your subscribers see. Tempt them to open your email."),
'emptySubjectLineError': __('Please specify a subject'),
'segments': __('Lists'),
'segmentsTip': __('Your email newsletter(s) will be sent to this list.'),
'segmentsTip': __('This subscriber segment will be used for this email.'),
'selectSegmentPlaceholder': __('Select a list'),
'noSegmentsSelectedError': __('Please select a list'),
'sender': __('Sender'),
@ -160,7 +160,7 @@
'newsletterUpdated': __('Newsletter was updated successfully!'),
'newsletterAdded': __('Newsletter was added successfully!'),
'newsletterSendingError': __('An error occurred while trying to send. <a href="%$1s">Please check your settings</a>'),
'finalNewsletterStep': __('Final step: last details'),
'finalNewsletterStep': __('Final Step: Last Details'),
'saveDraftAndClose': __('Save as draft and close'),
'orSimply': __('or simply'),
'goBackToDesign': __('go back to the Design page'),
@ -231,6 +231,7 @@
'sendingToSegmentsNotSpecified': __('You need to select a list to send to.'),
'backToPostNotifications': __('Back to Post notifications'),
'sentOn': __('Sent on')
'sentOn': __('Sent on'),
'noSubscribers': __('No subscribers!')
}) %>
<% endblock %>

View File

@ -25,7 +25,7 @@
<tr>
<th scope="row">
<label>
<%= __('Newsletter task scheduler') %>
<%= __('Newsletter task scheduler (cron)') %>
</label>
<p class="description">
<%= __('Select what will activate your newsletter queue.') %>

View File

@ -148,7 +148,7 @@
<%= __('Subscribe in registration form') %>
</label>
<p class="description">
<%= __('Allow users who register as a WordPress user on your website to subscribe to a MailPoet list (in addition to the "WordPress Users" list') %>
<%= __('Allow users who register as a WordPress user on your website to subscribe to a MailPoet list (in addition to the "WordPress Users" list)') %>
</p>
</th>
<td>
@ -203,7 +203,7 @@
</div>
<% else %>
<p>
<em><%= __('Registration is disabled on this site') %></em>
<em><%= __('Registration is disabled on this site.') %></em>
</p>
<% endif %>
</td>
@ -270,9 +270,9 @@
<%= __('Unsubscribe page') %>
</label>
<p class="description">
<%= __('When your subscribers click the "Unsubscribe" link, they will be directed to this page') %>
<%= __('When your subscribers click the "Unsubscribe" link, they will be directed to this page.') %>
<br />
<%= __('Use this shortcode on your website\'s WordPress pages: [mailpoet_manage text="Manage your subscription"]') %>
<%= __('If you want to use a custom Unsubscribe page, simply paste this shortcode on to a WordPress page: [mailpoet_manage_text="Manage your subscription"]') %>
</p>
</th>
<td>
@ -340,7 +340,7 @@
<tr>
<th scope="row">
<label>
<%= __('Shortcode to Display Total Number of Subscribers') %>
<%= __('Shortcode to display total number of subscribers') %>
</label>
<p class="description">
<%= __('Paste this shortcode on a post or page to display the total number of confirmed subscribers') %>

View File

@ -109,7 +109,7 @@
<br />
<%= __('Send with an external email provider. This is usually not free.') %>
<a
href="http://docs.mailpoet.com/article/53-send-with-smtp-when-using-a-professional-sending-provider"
href="http://docs.mailpoet.com/article/154-why-use-an-email-service-provider"
target="_blank"
><%= __('Read more.') %></a>
</p>

View File

@ -194,7 +194,7 @@
if(~~($(this).val()) === 1) {
result = confirm("<%= __('Subscribers will need to activate their subscription via email in order to receive your newsletters. This is highly recommended!') %>");
} else {
result = confirm("<%= __('Unconfirmed subscribers will receive your newsletters from without needing to activate their subscriptions. This is not recommended!') %>");
result = confirm("<%= __('New subscribers will be automatically confirmed, without having to confirm their subscription. This is not recommended!') %>");
}
// if the user confirmed changing the signup confirmation (yes/no)
if(result === true) {

View File

@ -52,7 +52,7 @@
'userColumns': __('User fields'),
'selectedValueAlreadyMatched': __('The selected value is already matched to another field'),
'confirmCorrespondingColumn': __('Confirm that this field corresponds to the selected field'),
'columnContainInvalidElement': __('One of the fields contains an invalid email. Please fix it before continuing'),
'columnContainInvalidElement': __('One of the fields contains an invalid email. Please fix it before continuing.'),
'january': __('January'),
'february': __('February'),
'march': __('March'),
@ -65,15 +65,15 @@
'october': __('October'),
'november': __('November'),
'december': __('December'),
'noDateFieldMatch': __("Do not match as a 'date field' if most of the rows for that field return the same error"),
'emptyFirstRowDate': __('First row date cannot be empty'),
'noDateFieldMatch': __("Do not match as a 'date field' if most of the rows for that field return the same error."),
'emptyFirstRowDate': __('First row date cannot be empty.'),
'verifyDateMatch': __('Verify that the date in blue matches the original date'),
'pm': __('PM'),
'am': __('AM'),
'dateMatchError': __('Error matching date'),
'columnContainsInvalidDate': __('One of the fields contains an invalid date. Please fix it before continuing'),
'columnContainsInvalidDate': __('One of the fields contains an invalid date. Please fix before continuing.'),
'listCreateError': __('Error adding a new list:'),
'columnContainsInvalidElement': __('One of the fields contains an invalid email. Please fix before continuing'),
'columnContainsInvalidElement': __('One of the fields contains an invalid email. Please fix before continuing.'),
'customFieldCreateError': __('Custom field could not be created'),
'subscribersCreated': __('%1$s subscribers added to %2$s.'),
'subscribersUpdated': __('%1$s existing subscribers were updated and added to %2$s')

View File

@ -17,7 +17,7 @@
'pageTitle': __('Subscribers'),
'searchLabel': __('Search'),
'loadingItems': __('Loading subscribers...'),
'noItemsFound': __('No subscribers were found'),
'noItemsFound': __('No subscribers were found.'),
'selectAllLabel': __('All subscribers on this page are selected.'),
'selectedAllLabel': __('All %d subscribers are selected'),
'selectAllLink': __('Select all subscribers on all pages.'),

View File

@ -17,40 +17,39 @@
<div style="position: absolute; top: .2em; right: 0;"><img src="<%= image_url('welcome_template/mailpoet-logo.png') %>" alt="MailPoet Logo" /></div>
<h2 class="nav-tab-wrapper wp-clearfix">
<a href="admin.php?page=mailpoet-welcome" class="nav-tab"><%= __('Whats New') %></a>
<a href="admin.php?page=mailpoet-update" class="nav-tab nav-tab-active"><%= __('Changelog') %></a>
<a href="admin.php?page=mailpoet-welcome" class="nav-tab"><%= __('Welcome') %></a>
<a href="admin.php?page=mailpoet-update" class="nav-tab nav-tab-active"><%= __("What's New") %></a>
</h2>
<div id="mailpoet-changelog" clas="feature-section one-col">
<h2><%= __("List of Changes") %></h2>
<h3>0.0.50 - 2016-10-25</h3>
<h3>3.0.0-beta.4 - 2016-11-15</h3>
<ul>
<li>Renamed "LICENSE" to "license.txt" in preparation for WP plugin repo;</li>
<li>Updated "readme.txt" with newly prepared README text;</li>
<li>Updated "View All Changes" button on plugin update page to link to MailPoet plugin repo page;</li>
<li>Fixed date formatting to allow using escaped symbols;</li>
<li>Fixed saving existing newsletters in newsletter editor and last newsletter creation step;</li>
<li>Changed "Newsletter not found" error on newsletter editor page to be displayed permanently;</li>
<li>Changed "newsletters.save" endpoint to require segment objects when saving newsletters;</li>
<li>Fixed security issue with public token reuse on admin panel;</li>
<li>Added endpoint specific access limits;</li>
<li>Increased subscriber export filename length and complexity to make it more difficult to guess file names;</li>
<li>Fixed sending queue to not send newsletters to trashed subscribers;</li>
<li>Fixed post notifications to work properly with multiple notification newsletters sent at the same time;</li>
<li>Fixed post notification newsletters to correctly set newsletter status once sending is completed;</li>
<li>Fixed post notification newsletters to not send newsletters without any ALC posts;</li>
<li>Fixed selecting multiple data fields in subscriber export.</li>
<li>Updated HelpScout beacon to provide support articles;</li>
<li>Fixed handling of URLs containing shortcodes in newsletter editor;</li>
<li>Security fixes;</li>
<li>Fixed subscriber count to not count trashed subscribers;</li>
<li>Fixed template renderer to gracefully display an error when template caching issues arise;</li>
<li>Added security measures to prevent mass subscriptions.</li>
</ul>
<br>
<h3>0.0.49 - 2016-10-18</h3>
<h3>3.0.0-beta.3 - 2016-11-08</h3>
<ul>
<li>Fixed security issues in Front Router, subscriber import, newsletter preview, admin listings, Idiorm demo code and subscriber verification;</li>
<li>Added unit tests for newsletter scheduler;</li>
<li>Added "Read more" documentation URL describing "WordPress Users" list in admin listings.</li>
<li>Improved compatibility with PHP 7;</li>
<li>Fixed showing current newsletter status in newsletter listings when there are no subscribers to send to;</li>
<li>Removed obsolete libraries;</li>
<li>Fixed security issues;</li>
<li>Fixed html form embed code to use correct paths;</li>
<li>Updated settings documentation URL;</li>
<li>Improved text fitting in newsletter type/template selection boxes;</li>
<li>Fixed Populator compatibility with earlier PHP versions;</li>
<li>Fixed newsletter number shortcode for notification newsletters;</li>
<li>Enhanced HelpScout support beacon report with extra support data;</li>
<li>Fixed email renderer to not throw entity warnings on earlier PHP versions;</li>
<li>Fixed newsletter preview incompatibility errors for earlier PHP versions.</li>
</ul>
<br>
</div>
<hr>

View File

@ -26,8 +26,8 @@
<div style="position: absolute; top: .2em; right: 0;"><img src="<%= image_url('welcome_template/mailpoet-logo.png') %>" alt="<%= __('MailPoet Logo') %>" /></div>
<h2 class="nav-tab-wrapper wp-clearfix">
<a href="admin.php?page=mailpoet-welcome" class="nav-tab nav-tab-active"><%= __('Whats New') %></a>
<a href="admin.php?page=mailpoet-update" class="nav-tab"><%= __('Changelog') %></a>
<a href="admin.php?page=mailpoet-welcome" class="nav-tab nav-tab-active"><%= __('Welcome') %></a>
<a href="admin.php?page=mailpoet-update" class="nav-tab"><%= __("What's new") %></a>
</h2>
<div class="headline-feature feature-video">

View File

@ -150,6 +150,7 @@ config.push(_.extend({}, baseConfig, {
'newsletter_editor/behaviors/ResizableBehavior.js',
'newsletter_editor/behaviors/SortableBehavior.js',
'newsletter_editor/behaviors/ShowSettingsBehavior.js',
'newsletter_editor/behaviors/TextEditorBehavior.js',
'newsletter_editor/blocks/base.js',
'newsletter_editor/blocks/container.js',
'newsletter_editor/blocks/button.js',
@ -227,6 +228,7 @@ config.push(_.extend({}, baseConfig, {
'newsletter_editor/behaviors/ResizableBehavior.js',
'newsletter_editor/behaviors/SortableBehavior.js',
'newsletter_editor/behaviors/ShowSettingsBehavior.js',
'newsletter_editor/behaviors/TextEditorBehavior.js',
'newsletter_editor/blocks/base.js',
'newsletter_editor/blocks/container.js',
'newsletter_editor/blocks/button.js',