Compare commits
126 Commits
Author | SHA1 | Date | |
---|---|---|---|
5019131b21 | |||
da483fb88f | |||
788bed4622 | |||
3fbe5423d0 | |||
8357295be2 | |||
8072b162d4 | |||
3f2f0ec1a9 | |||
5a5a777b7d | |||
6cac7f3652 | |||
6a9313107c | |||
72c9d301b7 | |||
ad925de801 | |||
1da28b7299 | |||
e837ad7014 | |||
daec56191f | |||
7bd25660df | |||
3b9821fbe1 | |||
cabe2d61b7 | |||
a6d802e2fa | |||
1732c4f634 | |||
bb77134224 | |||
f1cb64b240 | |||
3689545589 | |||
9b67c56281 | |||
dc38b19667 | |||
a574733217 | |||
b90aaa629e | |||
8de186c0e6 | |||
e3719967f9 | |||
138a631ed7 | |||
07b7636a72 | |||
a63ce3cdac | |||
f5c7bb87af | |||
2c8d925971 | |||
0c5beb2511 | |||
9c0316a87d | |||
46c1b682fa | |||
7954346a3f | |||
d87ff67f50 | |||
6642bb3bfa | |||
2cb32e7a78 | |||
fcea9adbd9 | |||
bbdd0dbb6e | |||
1b2cf7bd16 | |||
b7cfa549d5 | |||
ffc1d0a61c | |||
d1b160def7 | |||
493fd01754 | |||
9ced4b1757 | |||
17010e5ba9 | |||
42ad7584d4 | |||
dbc0f9b238 | |||
e62e9a5892 | |||
bc25fa61b4 | |||
2590967183 | |||
86eafd3c17 | |||
90a6f160c2 | |||
c774aec6a2 | |||
8f2fd1d76e | |||
4df11163a1 | |||
82a736ffbb | |||
87052986e8 | |||
0c73c0fadc | |||
5c7e11076d | |||
d1df94c759 | |||
53cc39c6f5 | |||
4955c72ee1 | |||
16661af8c3 | |||
bc80f69e41 | |||
0192934e65 | |||
2793e74858 | |||
5996696cc9 | |||
7f6cf5bbf3 | |||
c0ef2254cd | |||
0dbe04c3f8 | |||
ef1805d9b5 | |||
514f539e83 | |||
50f072705e | |||
f8f7bc3d3d | |||
f1bf2bb097 | |||
bbe2f69a7f | |||
c844488b0b | |||
112fe0cd6e | |||
c9e6dce785 | |||
d1c09c015a | |||
8d61866b77 | |||
0831c748b1 | |||
b2a0bc3860 | |||
1f99345e7b | |||
89782bc94b | |||
155ff09280 | |||
132e6d3342 | |||
f02699158f | |||
be3462925d | |||
3d82230d10 | |||
c20c46fd86 | |||
6e63c72aa5 | |||
e059eec5ea | |||
a2d38c9076 | |||
8d507b2ee0 | |||
5e2979c283 | |||
84ec0de3cd | |||
ee07780833 | |||
ed104156a9 | |||
90f2e9ff9d | |||
98fb7aa65e | |||
a51eb59cf8 | |||
270023b89c | |||
7d77e075e9 | |||
9bbe36b3cb | |||
7a904ed093 | |||
e3c065b353 | |||
4ca2872e0e | |||
ce338f7fe2 | |||
fa28b0a955 | |||
a298650187 | |||
95772ef68a | |||
e1c94db516 | |||
7be1a11d1e | |||
c04b95c09a | |||
cdfeb8d512 | |||
3ef8067968 | |||
9fb04bc3c0 | |||
25727ea0ba | |||
4c8ac369b7 | |||
268dabdc9f |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,7 +1,7 @@
|
||||
.DS_Store
|
||||
TODO
|
||||
composer.phar
|
||||
vendor
|
||||
/vendor
|
||||
tests/_output/*
|
||||
tests/acceptance.suite.yml
|
||||
tests/_support/_generated/*
|
||||
|
11
README.md
11
README.md
@ -8,7 +8,6 @@ MailPoet done the right way.
|
||||
```
|
||||
php
|
||||
nodejs
|
||||
phantomjs
|
||||
wordpress
|
||||
```
|
||||
|
||||
@ -47,16 +46,6 @@ $ ./do compile:all
|
||||
$ ./do test:unit
|
||||
```
|
||||
|
||||
- Acceptance tests:
|
||||
```sh
|
||||
$ ./do test:acceptance
|
||||
```
|
||||
|
||||
- Run all tests:
|
||||
```sh
|
||||
$ ./do test:all
|
||||
```
|
||||
|
||||
- Debug tests:
|
||||
```sh
|
||||
$ ./do test:debug
|
||||
|
@ -5,13 +5,15 @@
|
||||
@require 'common'
|
||||
@require 'modal'
|
||||
@require 'notice'
|
||||
@require 'parsley'
|
||||
|
||||
@require 'form_editor'
|
||||
@require 'listing'
|
||||
@require 'box'
|
||||
@require 'breadcrumb'
|
||||
|
||||
@require 'form'
|
||||
@require 'parsley'
|
||||
@require 'form_validation'
|
||||
|
||||
@require 'settings'
|
||||
@require 'progress_bar'
|
||||
@require 'progress_bar'
|
||||
|
File diff suppressed because one or more lines are too long
@ -19,6 +19,8 @@ a:focus
|
||||
|
||||
// select 2
|
||||
.select2-container
|
||||
width: 25em !important
|
||||
|
||||
// textareas
|
||||
textarea.regular-text
|
||||
width: 25em !important
|
||||
|
@ -4,6 +4,9 @@
|
||||
icons = '../img/form_editor_icons.png'
|
||||
handle_icon = '../img/handle.png'
|
||||
|
||||
#mailpoet_form_name
|
||||
font-size: 23px
|
||||
|
||||
#mailpoet_form_history
|
||||
display: none
|
||||
|
||||
@ -99,6 +102,7 @@ handle_icon = '../img/handle.png'
|
||||
/* MailPoet Form wrapper */
|
||||
#mailpoet_form_wrapper
|
||||
position: relative
|
||||
margin: 20px 0 0 0
|
||||
|
||||
/* MailPoet Form container */
|
||||
#mailpoet_form_container
|
||||
@ -121,6 +125,7 @@ handle_icon = '../img/handle.png'
|
||||
float: none
|
||||
|
||||
#mailpoet_form_toolbar
|
||||
z-index: 999
|
||||
position: absolute
|
||||
width: 400px
|
||||
|
||||
|
6
assets/css/src/form_validation.styl
Normal file
6
assets/css/src/form_validation.styl
Normal file
@ -0,0 +1,6 @@
|
||||
.parsley-errors-list
|
||||
margin-top: 8px
|
||||
|
||||
.parsley-required
|
||||
.parsley-custom-error-message
|
||||
color: #b94a48
|
@ -90,7 +90,7 @@ body.mailpoet_modal_opened
|
||||
padding: 0
|
||||
margin: 0
|
||||
width: 100%
|
||||
transition: margin 0.3s ease-out
|
||||
transition: margin 350ms ease-out
|
||||
|
||||
.mailpoet_panel_wrapper
|
||||
background-color: #f1f1f1
|
||||
@ -200,4 +200,4 @@ body.mailpoet_modal_opened
|
||||
0%
|
||||
50%
|
||||
background-color: #064E6D
|
||||
100%
|
||||
100%
|
||||
|
@ -7,7 +7,6 @@ $tool-active-secondary-color = #ffffff
|
||||
|
||||
$tool-width = 20px
|
||||
$master-column-tool-width = 24px
|
||||
$layer-selector-width = 30px
|
||||
|
||||
.mailpoet_tools
|
||||
position: absolute
|
||||
@ -33,10 +32,35 @@ $layer-selector-width = 30px
|
||||
width: $master-column-tool-width
|
||||
height: $master-column-tool-width
|
||||
|
||||
|
||||
.mailpoet_delete_block_activate
|
||||
max-width: 100%
|
||||
max-height: $master-column-tool-width
|
||||
opacity: 1
|
||||
display: block
|
||||
|
||||
.mailpoet_delete_block_confirm,
|
||||
.mailpoet_delete_block_cancel
|
||||
max-width: 100%
|
||||
max-height: 0
|
||||
opacity: 0
|
||||
overflow: hidden
|
||||
display: block
|
||||
|
||||
.mailpoet_delete_block_activated
|
||||
width: auto
|
||||
height: auto
|
||||
|
||||
.mailpoet_delete_block_activate
|
||||
overflow: hidden
|
||||
max-height: 0
|
||||
opacity: 0
|
||||
|
||||
.mailpoet_delete_block_confirm,
|
||||
.mailpoet_delete_block_cancel
|
||||
max-height: $master-column-tool-width*2
|
||||
opacity: 1
|
||||
|
||||
.mailpoet_tool
|
||||
display: inline-block
|
||||
width: $tool-width
|
||||
@ -82,7 +106,7 @@ $layer-selector-width = 30px
|
||||
padding: 0
|
||||
|
||||
.mailpoet_delete_block_activate
|
||||
max-width: 100%
|
||||
max-width: $tool-width
|
||||
display: inline-block
|
||||
opacity: 1
|
||||
animation-fade-in-and-scale-horizontally()
|
||||
@ -96,12 +120,12 @@ $layer-selector-width = 30px
|
||||
animation-fade-in-and-scale-horizontally()
|
||||
|
||||
.mailpoet_delete_block_activated
|
||||
height: auto
|
||||
width: auto
|
||||
border-radius(3px)
|
||||
background-color: $warning-background-color
|
||||
padding: 3px 5px
|
||||
line-height: 1.2em
|
||||
height: auto
|
||||
|
||||
.mailpoet_delete_block_activate
|
||||
overflow: hidden
|
||||
@ -113,6 +137,9 @@ $layer-selector-width = 30px
|
||||
max-width: 100%
|
||||
opacity: 1
|
||||
|
||||
.mailpoet_delete_block_cancel
|
||||
margin-left: 3px
|
||||
|
||||
.mailpoet_delete_block_confirm
|
||||
color: $warning-text-color
|
||||
|
||||
|
@ -52,7 +52,7 @@ $draggable-widget-z-index = 2
|
||||
padding: 0
|
||||
margin: 0
|
||||
z-index: $draggable-widget-z-index
|
||||
animation-fade-in-and-scale-up()
|
||||
animation-fade-in()
|
||||
|
||||
.mailpoet_widget_icon
|
||||
padding: 0
|
||||
|
@ -48,7 +48,7 @@
|
||||
.mailpoet_save_as_template_container,
|
||||
.mailpoet_export_template_container
|
||||
border-radius(3px)
|
||||
float: left
|
||||
display: inline-block
|
||||
clear: both
|
||||
|
||||
margin-top: 5px
|
||||
|
@ -26,13 +26,9 @@ $widget-icon-width = 30px
|
||||
border-right: 0
|
||||
|
||||
&.closed .mailpoet_region_content
|
||||
max-height: 0px
|
||||
overflow: hidden
|
||||
margin-top: 0
|
||||
display: none
|
||||
|
||||
.mailpoet_region_content
|
||||
max-height: 2000px
|
||||
transition: max-height 300ms ease
|
||||
padding: 0 20px
|
||||
margin-top: 12px
|
||||
|
||||
|
@ -30,8 +30,3 @@ $block-hover-highlight-color = $primary-active-color
|
||||
|
||||
.mailpoet_content
|
||||
position: relative
|
||||
|
||||
.mailpoet_block_transition_in
|
||||
animation-fade-in-and-scale-up()
|
||||
.mailpoet_block_transition_out
|
||||
animation-fade-out-and-scale-down()
|
||||
|
@ -129,3 +129,7 @@ body
|
||||
|
||||
#mailpoet_modal_close
|
||||
display: none
|
||||
|
||||
.wrap > .mailpoet_notice,
|
||||
.update-nag
|
||||
margin-left: 2px + 15px !important
|
||||
|
@ -1,5 +1,5 @@
|
||||
animation-slide-open-downwards()
|
||||
transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000) /* ease-in-out */
|
||||
transition: all 250ms cubic-bezier(0.420, 0.000, 0.580, 1.000) /* ease-in-out */
|
||||
max-height: 2000px
|
||||
opacity: 1
|
||||
|
||||
@ -9,45 +9,23 @@ animation-slide-open-downwards()
|
||||
overflow-y: hidden
|
||||
|
||||
animation-background-color()
|
||||
transition: background 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000) /* ease-in-out */
|
||||
transition: background 250ms cubic-bezier(0.420, 0.000, 0.580, 1.000) /* ease-in-out */
|
||||
|
||||
animation-fade-in-and-scale-up()
|
||||
animation-name: fadeInAndScaleUp
|
||||
animation-duration: 500ms
|
||||
animation-fill-mode: forwards
|
||||
|
||||
animation-fade-out-and-scale-down()
|
||||
animation-name: fadeOutAndScaleDown
|
||||
animation-duration: 500ms
|
||||
animation-fade-in()
|
||||
animation-name: fadeIn
|
||||
animation-duration: 300ms
|
||||
animation-fill-mode: forwards
|
||||
animation-timing-function: ease-in
|
||||
|
||||
animation-fade-in-and-scale-horizontally()
|
||||
transition: all 300ms cubic-bezier(0.420, 0.000, 0.580, 1.000) /* ease-in-out */
|
||||
transition: all 250ms cubic-bezier(0.420, 0.000, 0.580, 1.000) /* ease-in-out */
|
||||
|
||||
@keyframes fadeInAndScaleUp {
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0.3
|
||||
max-height: 0
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1
|
||||
max-height: 5000px
|
||||
overflow: hidden
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeOutAndScaleDown {
|
||||
0% {
|
||||
opacity: 1
|
||||
max-height: 5000px
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0.3
|
||||
max-height: 0
|
||||
overflow: hidden
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
@import 'nib'
|
||||
|
||||
@require 'parsley'
|
||||
@require 'form_validation'
|
||||
|
BIN
assets/img/post_notifications_template/ALC-widget-icon.png
Executable file
BIN
assets/img/post_notifications_template/ALC-widget-icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
BIN
assets/img/post_notifications_template/settings-icon-highlight.png
Executable file
BIN
assets/img/post_notifications_template/settings-icon-highlight.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 7.2 KiB |
BIN
assets/img/welcome_template/logo-header.gif
Executable file
BIN
assets/img/welcome_template/logo-header.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
@ -1,98 +1,106 @@
|
||||
define(
|
||||
[
|
||||
'react',
|
||||
'react-dom',
|
||||
'mailpoet'
|
||||
],
|
||||
function (
|
||||
React,
|
||||
ReactDOM,
|
||||
MailPoet
|
||||
) {
|
||||
var CronControl = React.createClass({
|
||||
getInitialState: function () {
|
||||
return (cronDaemon) ? cronDaemon : null;
|
||||
},
|
||||
getDaemonData: function () {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'cron',
|
||||
action: 'getDaemonStatus'
|
||||
}).done(function (response) {
|
||||
jQuery('.button-primary').removeClass('disabled');
|
||||
if (!response) {
|
||||
this.replaceState();
|
||||
} else {
|
||||
this.setState(response);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
componentDidMount: function componentDidMount() {
|
||||
if (this.isMounted()) {
|
||||
this.getDaemonData;
|
||||
setInterval(this.getDaemonData, 5000);
|
||||
}
|
||||
},
|
||||
controlDaemon: function (action) {
|
||||
jQuery('.button-primary').addClass('disabled');
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'cron',
|
||||
action: 'controlDaemon',
|
||||
data: {'action': action}
|
||||
}).done(function (response) {
|
||||
if (!response) {
|
||||
this.replaceState();
|
||||
} else {
|
||||
this.setState(response);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
render: function () {
|
||||
if (!this.state) {
|
||||
return
|
||||
<div>
|
||||
Woops, daemon is not running ;\
|
||||
</div>
|
||||
}
|
||||
switch (this.state.status) {
|
||||
case 'started':
|
||||
return (
|
||||
[
|
||||
'react',
|
||||
'react-dom',
|
||||
'mailpoet'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
ReactDOM,
|
||||
MailPoet
|
||||
) {
|
||||
var CronControl = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
status: 'loading'
|
||||
};
|
||||
},
|
||||
getCronData: function() {
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'cron',
|
||||
action: 'getStatus'
|
||||
})
|
||||
.done(function(response) {
|
||||
jQuery('.button-primary')
|
||||
.removeClass('disabled');
|
||||
if(response.status !== undefined) {
|
||||
this.setState(response);
|
||||
} else {
|
||||
this.replaceState();
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
componentDidMount: function() {
|
||||
if(this.isMounted()) {
|
||||
this.getCronData();
|
||||
setInterval(this.getCronData, 5000);
|
||||
}
|
||||
},
|
||||
controlCron: function(action) {
|
||||
if(jQuery('.button-primary').hasClass('disabled')) {
|
||||
return;
|
||||
}
|
||||
jQuery('.button-primary')
|
||||
.addClass('disabled');
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'cron',
|
||||
action: action,
|
||||
})
|
||||
.done(function(response) {
|
||||
if(!response.result) {
|
||||
MailPoet.Notice.error(MailPoetI18n.daemonControlError);
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
render: function() {
|
||||
if(this.state.status === 'loading') {
|
||||
return(<div>Loading daemon status...</div>);
|
||||
}
|
||||
switch(this.state.status) {
|
||||
case 'started':
|
||||
return(
|
||||
<div>
|
||||
<div>
|
||||
Cron daemon is running.
|
||||
<br/>
|
||||
<br/>
|
||||
It was started
|
||||
<strong> {this.state.timeSinceStart} </strong> and last executed
|
||||
<strong> {this.state.timeSinceUpdate} </strong> for a total of
|
||||
<strong> {this.state.counter} </strong> times (once every 30 seconds, unless it was interrupted and restarted).
|
||||
<br />
|
||||
<br />
|
||||
<a href="#" className="button-primary" onClick={this.controlDaemon.bind(null, 'stop')}>Stop</a>
|
||||
<a href="#" className="button-primary" onClick={this.controlDaemon.bind(null, 'pause')}>Pause</a>
|
||||
</div>
|
||||
Cron daemon is running.
|
||||
<br/>
|
||||
<br/>
|
||||
It was started
|
||||
<strong> {this.state.timeSinceStart} </strong> and last executed
|
||||
<strong> {this.state.timeSinceUpdate} </strong> for a total of
|
||||
<strong> {this.state.counter} </strong> times (once every 30 seconds, unless it was interrupted and restarted).
|
||||
<br />
|
||||
<br />
|
||||
<a href="#" className="button-primary" onClick={this.controlCron.bind(null, 'stop')}>Stop</a>
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
case 'paused':
|
||||
case 'stopped':
|
||||
return (
|
||||
);
|
||||
break;
|
||||
case 'starting':
|
||||
case 'stopping':
|
||||
return(
|
||||
<div>
|
||||
Daemon is {this.state.status}
|
||||
</div>
|
||||
);
|
||||
break;
|
||||
case 'stopped':
|
||||
return(
|
||||
<div>
|
||||
Daemon is {this.state.status}
|
||||
<br />
|
||||
<br />
|
||||
<a href="#" className="button-primary" onClick={this.controlDaemon.bind(null, 'start')}>Start</a>
|
||||
<a href="#" className="button-primary" onClick={this.controlCron.bind(null, 'start')}>Start</a>
|
||||
</div>
|
||||
)
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
let container = document.getElementById('cron_container');
|
||||
if (container) {
|
||||
ReactDOM.render(
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const container = document.getElementById('cron_container');
|
||||
|
||||
if(container) {
|
||||
ReactDOM.render(
|
||||
<CronControl />,
|
||||
document.getElementById('cron_status')
|
||||
)
|
||||
}
|
||||
}
|
||||
);
|
||||
container
|
||||
);
|
||||
}
|
||||
});
|
@ -1,31 +1,31 @@
|
||||
define([
|
||||
'react',
|
||||
'react-checkbox-group'
|
||||
'react'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
CheckboxGroup
|
||||
React
|
||||
) {
|
||||
var FormFieldCheckbox = React.createClass({
|
||||
const FormFieldCheckbox = React.createClass({
|
||||
onValueChange: function(e) {
|
||||
e.target.value = this.refs.checkbox.checked ? '1' : '';
|
||||
return this.props.onValueChange(e);
|
||||
},
|
||||
render: function() {
|
||||
var selected_values = this.props.item[this.props.field.name] || '';
|
||||
if(
|
||||
selected_values !== undefined
|
||||
&& selected_values.constructor !== Array
|
||||
) {
|
||||
selected_values = selected_values.split(';').map(function(value) {
|
||||
return value.trim();
|
||||
});
|
||||
}
|
||||
var count = Object.keys(this.props.field.values).length;
|
||||
const isChecked = !!(this.props.item[this.props.field.name]);
|
||||
|
||||
var options = Object.keys(this.props.field.values).map(
|
||||
const options = Object.keys(this.props.field.values).map(
|
||||
function(value, index) {
|
||||
return (
|
||||
<p key={ 'checkbox-' + index }>
|
||||
<label>
|
||||
<input type="checkbox" value={ value } />
|
||||
{ this.props.field.values[value] }
|
||||
<input
|
||||
ref="checkbox"
|
||||
type="checkbox"
|
||||
value="1"
|
||||
checked={ isChecked }
|
||||
onChange={ this.onValueChange }
|
||||
name={ this.props.field.name }
|
||||
/>
|
||||
{ this.props.field.values[value] }
|
||||
</label>
|
||||
</p>
|
||||
);
|
||||
@ -33,30 +33,10 @@ function(
|
||||
);
|
||||
|
||||
return (
|
||||
<CheckboxGroup
|
||||
name={ this.props.field.name }
|
||||
value={ selected_values }
|
||||
ref={ this.props.field.name }
|
||||
onChange={ this.handleValueChange }>
|
||||
<div>
|
||||
{ options }
|
||||
</CheckboxGroup>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
handleValueChange: function() {
|
||||
var field = this.props.field.name;
|
||||
var group = this.refs[field];
|
||||
var selected_values = [];
|
||||
|
||||
if(group !== undefined) {
|
||||
selected_values = group.getCheckedValues();
|
||||
}
|
||||
|
||||
return this.props.onValueChange({
|
||||
target: {
|
||||
name: field,
|
||||
value: selected_values.join(';')
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
196
assets/js/src/form/fields/date.jsx
Normal file
196
assets/js/src/form/fields/date.jsx
Normal file
@ -0,0 +1,196 @@
|
||||
define([
|
||||
'react',
|
||||
'moment',
|
||||
], function(
|
||||
React,
|
||||
Moment
|
||||
) {
|
||||
class FormFieldDateYear extends React.Component {
|
||||
render() {
|
||||
const yearsRange = 100;
|
||||
const years = [];
|
||||
const currentYear = Moment().year();
|
||||
for (let i = currentYear; i >= currentYear - yearsRange; i--) {
|
||||
years.push((
|
||||
<option
|
||||
key={ i }
|
||||
value={ i }
|
||||
>{ i }</option>
|
||||
));
|
||||
}
|
||||
return (
|
||||
<select
|
||||
name={ this.props.name + '[year]' }
|
||||
value={ this.props.year }
|
||||
onChange={ this.props.onValueChange }
|
||||
>
|
||||
{ years }
|
||||
</select>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FormFieldDateMonth extends React.Component {
|
||||
render() {
|
||||
const months = [];
|
||||
for (let i = 1; i <= 12; i++) {
|
||||
months.push((
|
||||
<option
|
||||
key={ i }
|
||||
value={ i }
|
||||
>{ this.props.monthNames[i - 1] }</option>
|
||||
));
|
||||
}
|
||||
return (
|
||||
<select
|
||||
name={ this.props.name + '[month]' }
|
||||
value={ this.props.month }
|
||||
onChange={ this.props.onValueChange }
|
||||
>
|
||||
{ months }
|
||||
</select>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FormFieldDateDay extends React.Component {
|
||||
render() {
|
||||
const days = [];
|
||||
for (let i = 1; i <= 31; i++) {
|
||||
days.push((
|
||||
<option
|
||||
key={ i }
|
||||
value={ i }
|
||||
>{ i }</option>
|
||||
));
|
||||
}
|
||||
|
||||
return (
|
||||
<select
|
||||
name={ this.props.name + '[day]' }
|
||||
value={ this.props.day }
|
||||
onChange={ this.props.onValueChange }
|
||||
>
|
||||
{ days }
|
||||
</select>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FormFieldDate extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
year: Moment().year(),
|
||||
month: 1,
|
||||
day: 1
|
||||
}
|
||||
}
|
||||
componentDidMount() {
|
||||
}
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (
|
||||
(this.props.item !== undefined && prevProps.item !== undefined)
|
||||
&& (this.props.item.id !== prevProps.item.id)
|
||||
) {
|
||||
this.extractTimeStamp();
|
||||
}
|
||||
}
|
||||
extractTimeStamp() {
|
||||
const timeStamp = parseInt(this.props.item[this.props.field.name], 10);
|
||||
|
||||
this.setState({
|
||||
year: Moment.unix(timeStamp).year(),
|
||||
// Moment returns the month as [0..11]
|
||||
// We increment it to match PHP's mktime() which expects [1..12]
|
||||
month: Moment.unix(timeStamp).month() + 1,
|
||||
day: Moment.unix(timeStamp).date()
|
||||
});
|
||||
}
|
||||
updateTimeStamp(field) {
|
||||
let newTimeStamp = Moment(
|
||||
`${this.state.month}/${this.state.day}/${this.state.year}`,
|
||||
'M/D/YYYY'
|
||||
).valueOf();
|
||||
if (!isNaN(newTimeStamp) && parseInt(newTimeStamp, 10) > 0) {
|
||||
// convert milliseconds to seconds
|
||||
newTimeStamp /= 1000;
|
||||
return this.props.onValueChange({
|
||||
target: {
|
||||
name: field,
|
||||
value: newTimeStamp
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
onValueChange(e) {
|
||||
// extract property from name
|
||||
const matches = e.target.name.match(/(.*?)\[(.*?)\]/);
|
||||
let field = null;
|
||||
let property = null;
|
||||
|
||||
if (matches !== null && matches.length === 3) {
|
||||
field = matches[1];
|
||||
property = matches[2];
|
||||
|
||||
let value = parseInt(e.target.value, 10);
|
||||
|
||||
this.setState({
|
||||
[`${property}`]: value
|
||||
}, () => {
|
||||
this.updateTimeStamp(field);
|
||||
});
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const monthNames = window.mailpoet_month_names || [];
|
||||
|
||||
const dateType = this.props.field.params.date_type;
|
||||
|
||||
const dateSelects = dateType.split('_');
|
||||
|
||||
const fields = dateSelects.map(type => {
|
||||
switch(type) {
|
||||
case 'year':
|
||||
return (<FormFieldDateYear
|
||||
onValueChange={ this.onValueChange.bind(this) }
|
||||
ref={ 'year' }
|
||||
key={ 'year' }
|
||||
name={ this.props.field.name }
|
||||
year={ this.state.year }
|
||||
/>);
|
||||
break;
|
||||
|
||||
case 'month':
|
||||
return (<FormFieldDateMonth
|
||||
onValueChange={ this.onValueChange.bind(this) }
|
||||
ref={ 'month' }
|
||||
key={ 'month' }
|
||||
name={ this.props.field.name }
|
||||
month={ this.state.month }
|
||||
monthNames={ monthNames }
|
||||
/>);
|
||||
break;
|
||||
|
||||
case 'day':
|
||||
return (<FormFieldDateDay
|
||||
onValueChange={ this.onValueChange.bind(this) }
|
||||
ref={ 'day' }
|
||||
key={ 'day' }
|
||||
name={ this.props.field.name }
|
||||
day={ this.state.day }
|
||||
/>);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
{fields}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return FormFieldDate;
|
||||
});
|
@ -5,7 +5,8 @@ define([
|
||||
'form/fields/select.jsx',
|
||||
'form/fields/radio.jsx',
|
||||
'form/fields/checkbox.jsx',
|
||||
'form/fields/selection.jsx'
|
||||
'form/fields/selection.jsx',
|
||||
'form/fields/date.jsx',
|
||||
],
|
||||
function(
|
||||
React,
|
||||
@ -14,7 +15,8 @@ function(
|
||||
FormFieldSelect,
|
||||
FormFieldRadio,
|
||||
FormFieldCheckbox,
|
||||
FormFieldSelection
|
||||
FormFieldSelection,
|
||||
FormFieldDate
|
||||
) {
|
||||
var FormField = React.createClass({
|
||||
renderField: function(data, inline = false) {
|
||||
@ -55,6 +57,10 @@ function(
|
||||
case 'selection':
|
||||
field = (<FormFieldSelection {...data} />);
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
field = (<FormFieldDate {...data} />);
|
||||
break;
|
||||
}
|
||||
|
||||
if(inline === true) {
|
||||
@ -66,10 +72,10 @@ function(
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<p key={ 'field-' + (data.index || 0) }>
|
||||
<div key={ 'field-' + (data.index || 0) }>
|
||||
{ field }
|
||||
{ description }
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -7,7 +7,6 @@ function(
|
||||
var FormFieldRadio = React.createClass({
|
||||
render: function() {
|
||||
var selected_value = this.props.item[this.props.field.name];
|
||||
var count = Object.keys(this.props.field.values).length;
|
||||
|
||||
var options = Object.keys(this.props.field.values).map(
|
||||
function(value, index) {
|
||||
@ -20,7 +19,7 @@ function(
|
||||
value={ value }
|
||||
onChange={ this.props.onValueChange }
|
||||
name={ this.props.field.name } />
|
||||
{ this.props.field.values[value] }
|
||||
{ this.props.field.values[value] }
|
||||
</label>
|
||||
</p>
|
||||
);
|
||||
|
@ -231,7 +231,7 @@ var WysijaHistory = {
|
||||
|
||||
/* MailPoet Form */
|
||||
var WysijaForm = {
|
||||
version: '0.6',
|
||||
version: '0.7',
|
||||
options: {
|
||||
container: 'mailpoet_form_container',
|
||||
editor: 'mailpoet_form_editor',
|
||||
@ -317,6 +317,7 @@ var WysijaForm = {
|
||||
save: function() {
|
||||
var position = 1,
|
||||
data = {
|
||||
'name': $F('mailpoet_form_name'),
|
||||
'settings': $('mailpoet_form_settings').serialize(true),
|
||||
'body': [],
|
||||
'styles': (MailPoet.CodeEditor !== undefined) ? MailPoet.CodeEditor.getValue() : null
|
||||
@ -616,6 +617,28 @@ var WysijaForm = {
|
||||
// this is a url, so do not encode the protocol
|
||||
return encodeURI(str).replace(/[!'()*]/g, escape);
|
||||
}
|
||||
},
|
||||
updateBlock: function(field) {
|
||||
var hasUpdated = false;
|
||||
WysijaForm.getBlocks().each(function(b) {
|
||||
if(b.block.getData().id === field.id) {
|
||||
hasUpdated = true;
|
||||
b.block.redraw(field);
|
||||
}
|
||||
});
|
||||
|
||||
return hasUpdated;
|
||||
},
|
||||
removeBlock: function(field, callback) {
|
||||
var hasRemoved = false;
|
||||
WysijaForm.getBlocks().each(function(b) {
|
||||
if(b.block.getData().id === field.id) {
|
||||
hasRemoved = true;
|
||||
b.block.removeBlock(callback);
|
||||
}
|
||||
});
|
||||
|
||||
return hasRemoved;
|
||||
}
|
||||
};
|
||||
|
||||
@ -824,10 +847,6 @@ WysijaForm.Block = Class.create({
|
||||
Effect.Fade(this.element.identify(), {
|
||||
duration: 0.2,
|
||||
afterFinish: function(effect) {
|
||||
if(effect.element.next('.mailpoet_form_block') !== undefined && callback !== false) {
|
||||
// show controls of next block to allow mass delete
|
||||
WysijaForm.get(effect.element.next('.mailpoet_form_block')).block.showControls();
|
||||
}
|
||||
// remove placeholder
|
||||
if(effect.element.previous('.block_placeholder') !== undefined) {
|
||||
effect.element.previous('.block_placeholder').remove();
|
||||
|
@ -47,7 +47,6 @@ define([
|
||||
autoScroll: true,
|
||||
|
||||
onstart: function(event) {
|
||||
console.log('Drag start', event, this);
|
||||
|
||||
if (that.options.cloneOriginal === true) {
|
||||
// Use substitution instead of a clone
|
||||
|
@ -11,10 +11,10 @@ define([
|
||||
'newsletter_editor/blocks/base',
|
||||
'newsletter_editor/blocks/button',
|
||||
'newsletter_editor/blocks/divider',
|
||||
'newsletter_editor/components/wordpress',
|
||||
'newsletter_editor/components/communication',
|
||||
'underscore',
|
||||
'jquery'
|
||||
], function(App, BaseBlock, ButtonBlock, DividerBlock, WordpressComponent, _, jQuery) {
|
||||
], function(App, BaseBlock, ButtonBlock, DividerBlock, CommunicationComponent, _, jQuery) {
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -69,9 +69,9 @@ define([
|
||||
},
|
||||
fetchPosts: function() {
|
||||
var that = this;
|
||||
WordpressComponent.getTransformedPosts(this.toJSON()).done(function(content) {
|
||||
console.log('ALC fetched', arguments);
|
||||
CommunicationComponent.getTransformedPosts(this.toJSON()).done(function(content) {
|
||||
that.get('_container').get('blocks').reset(content, {parse: true});
|
||||
that.trigger('postsChanged');
|
||||
}).fail(function(error) {
|
||||
console.log('ALC fetchPosts error', arguments);
|
||||
});
|
||||
@ -100,6 +100,11 @@ define([
|
||||
toolsRegion: '.mailpoet_tools',
|
||||
postsRegion: '.mailpoet_automated_latest_content_block_posts',
|
||||
},
|
||||
modelEvents: _.extend(
|
||||
_.omit(base.BlockView.prototype.modelEvents, 'change'),
|
||||
{
|
||||
'postsChanged': 'render',
|
||||
}),
|
||||
events: _.extend(base.BlockView.prototype.events, {
|
||||
'click .mailpoet_automated_latest_content_block_overlay': 'showSettings',
|
||||
}),
|
||||
@ -161,7 +166,7 @@ define([
|
||||
var that = this;
|
||||
|
||||
// Dynamically update available post types
|
||||
WordpressComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
|
||||
CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
|
||||
|
||||
this.$('.mailpoet_automated_latest_content_categories_and_tags').select2({
|
||||
multiple: true,
|
||||
@ -174,10 +179,10 @@ define([
|
||||
},
|
||||
transport: function(options, success, failure) {
|
||||
var taxonomies,
|
||||
promise = WordpressComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
promise = CommunicationComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
taxonomies = tax;
|
||||
// Fetch available terms based on the list of taxonomies already fetched
|
||||
var promise = WordpressComponent.getTerms({
|
||||
var promise = CommunicationComponent.getTerms({
|
||||
search: options.data.term,
|
||||
taxonomies: _.keys(taxonomies)
|
||||
}).then(function(terms) {
|
||||
|
@ -117,12 +117,9 @@ define([
|
||||
* Defines drop behavior of BlockView instance
|
||||
*/
|
||||
getDropFunc: function() {
|
||||
var that = this;
|
||||
return function() {
|
||||
var newModel = that.model.clone();
|
||||
//that.model.destroy();
|
||||
return newModel;
|
||||
};
|
||||
return this.model.clone();
|
||||
}.bind(this);
|
||||
},
|
||||
showBlock: function() {
|
||||
if (this._isFirstRender) {
|
||||
@ -131,25 +128,37 @@ define([
|
||||
}
|
||||
},
|
||||
deleteBlock: function() {
|
||||
this.transitionOut().done(function() {
|
||||
this.transitionOut().then(function() {
|
||||
this.model.destroy();
|
||||
}.bind(this));
|
||||
},
|
||||
transitionIn: function() {
|
||||
return this._transition('mailpoet_block_transition_in');
|
||||
return this._transition('slideDown', 'fadeIn', 'easeOut');
|
||||
},
|
||||
transitionOut: function() {
|
||||
return this._transition('mailpoet_block_transition_out');
|
||||
return this._transition('slideUp', 'fadeOut', 'easeIn');
|
||||
},
|
||||
_transition: function(className) {
|
||||
var that = this,
|
||||
promise = jQuery.Deferred();
|
||||
_transition: function(slideDirection, fadeDirection, easing) {
|
||||
var promise = jQuery.Deferred();
|
||||
|
||||
this.$el.velocity(
|
||||
slideDirection,
|
||||
{
|
||||
duration: 250,
|
||||
easing: easing,
|
||||
complete: function() {
|
||||
promise.resolve();
|
||||
}.bind(this),
|
||||
}
|
||||
).velocity(
|
||||
fadeDirection,
|
||||
{
|
||||
duration: 250,
|
||||
easing: easing,
|
||||
queue: false, // Do not enqueue, trigger animation in parallel
|
||||
}
|
||||
);
|
||||
|
||||
this.$el.addClass(className);
|
||||
this.$el.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd animationend', function() {
|
||||
that.$el.removeClass('mailpoet_block_transition_out');
|
||||
promise.resolve();
|
||||
});
|
||||
return promise;
|
||||
},
|
||||
});
|
||||
@ -207,16 +216,14 @@ define([
|
||||
Module.BlockSettingsView = Marionette.LayoutView.extend({
|
||||
className: 'mailpoet_editor_settings',
|
||||
initialize: function() {
|
||||
var that = this;
|
||||
|
||||
MailPoet.Modal.panel({
|
||||
element: this.$el,
|
||||
template: '',
|
||||
position: 'right',
|
||||
width: App.getConfig().get('sidepanelWidth'),
|
||||
onCancel: function() {
|
||||
that.destroy();
|
||||
},
|
||||
this.destroy();
|
||||
}.bind(this),
|
||||
});
|
||||
},
|
||||
close: function(event) {
|
||||
|
@ -232,12 +232,9 @@ define([
|
||||
_.extend(this, this._buildRegions(this.regions));
|
||||
},
|
||||
getDropFunc: function() {
|
||||
var that = this;
|
||||
return function() {
|
||||
var newModel = that.model.clone();
|
||||
that.model.destroy();
|
||||
return newModel;
|
||||
};
|
||||
return this.model.clone();
|
||||
}.bind(this);
|
||||
},
|
||||
showBlock: function() {
|
||||
if (this._isFirstRender) {
|
||||
@ -251,20 +248,32 @@ define([
|
||||
}.bind(this));
|
||||
},
|
||||
transitionIn: function() {
|
||||
return this._transition('mailpoet_block_transition_in');
|
||||
return this._transition('slideDown', 'fadeIn', 'easeIn');
|
||||
},
|
||||
transitionOut: function() {
|
||||
return this._transition('mailpoet_block_transition_out');
|
||||
return this._transition('slideUp', 'fadeOut', 'easeOut');
|
||||
},
|
||||
_transition: function(className) {
|
||||
var that = this,
|
||||
promise = jQuery.Deferred();
|
||||
_transition: function(slideDirection, fadeDirection, easing) {
|
||||
var promise = jQuery.Deferred();
|
||||
|
||||
this.$el.velocity(
|
||||
slideDirection,
|
||||
{
|
||||
duration: 250,
|
||||
easing: easing,
|
||||
complete: function() {
|
||||
promise.resolve();
|
||||
}.bind(this),
|
||||
}
|
||||
).velocity(
|
||||
fadeDirection,
|
||||
{
|
||||
duration: 250,
|
||||
easing: easing,
|
||||
queue: false, // Do not enqueue, trigger animation in parallel
|
||||
}
|
||||
);
|
||||
|
||||
this.$el.addClass(className);
|
||||
this.$el.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd animationend', function() {
|
||||
that.$el.removeClass('mailpoet_block_transition_out');
|
||||
promise.resolve();
|
||||
});
|
||||
return promise;
|
||||
},
|
||||
});
|
||||
|
@ -57,11 +57,9 @@ define([
|
||||
this.listenTo(this.model, 'change:styles.block.padding', this.changePadding);
|
||||
},
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
viewCid: this.cid,
|
||||
return _.extend({
|
||||
totalHeight: parseInt(this.model.get('styles.block.padding'), 10)*2 + parseInt(this.model.get('styles.block.borderWidth')) + 'px',
|
||||
};
|
||||
}, base.BlockView.prototype.templateHelpers.apply(this));
|
||||
},
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.DividerBlockToolsView({ model: this.model });
|
||||
|
@ -39,9 +39,9 @@ define([
|
||||
Module.FooterBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_footer_block mailpoet_droppable_block",
|
||||
getTemplate: function() { return templates.footerBlock; },
|
||||
modelEvents: {
|
||||
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',
|
||||
},
|
||||
}, base.BlockView.prototype.modelEvents),
|
||||
onDragSubstituteBy: function() { return Module.FooterWidgetView; },
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.FooterBlockToolsView({ model: this.model });
|
||||
|
@ -39,9 +39,9 @@ define([
|
||||
Module.HeaderBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_header_block mailpoet_droppable_block",
|
||||
getTemplate: function() { return templates.headerBlock; },
|
||||
modelEvents: {
|
||||
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',
|
||||
},
|
||||
}, base.BlockView.prototype.modelEvents),
|
||||
onDragSubstituteBy: function() { return Module.HeaderWidgetView; },
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.HeaderBlockToolsView({ model: this.model });
|
||||
|
@ -37,11 +37,9 @@ define([
|
||||
getTemplate: function() { return templates.imageBlock; },
|
||||
onDragSubstituteBy: function() { return Module.ImageWidgetView; },
|
||||
templateHelpers: function() {
|
||||
return {
|
||||
model: this.model.toJSON(),
|
||||
viewCid: this.cid,
|
||||
return _.extend({
|
||||
imageMissingSrc: App.getConfig().get('urls.imageMissing'),
|
||||
};
|
||||
}, base.BlockView.prototype.templateHelpers.apply(this));
|
||||
},
|
||||
onRender: function() {
|
||||
this.toolsView = new Module.ImageBlockToolsView({ model: this.model });
|
||||
|
@ -18,12 +18,12 @@ define([
|
||||
'jquery',
|
||||
'mailpoet',
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/components/wordpress',
|
||||
'newsletter_editor/components/communication',
|
||||
'newsletter_editor/blocks/base',
|
||||
'newsletter_editor/blocks/button',
|
||||
'newsletter_editor/blocks/divider',
|
||||
'select2'
|
||||
], function(Backbone, Marionette, Radio, _, jQuery, MailPoet, App, WordpressComponent, BaseBlock, ButtonBlock, DividerBlock) {
|
||||
], function(Backbone, Marionette, Radio, _, jQuery, MailPoet, App, CommunicationComponent, BaseBlock, ButtonBlock, DividerBlock) {
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -96,8 +96,7 @@ define([
|
||||
},
|
||||
fetchAvailablePosts: function() {
|
||||
var that = this;
|
||||
WordpressComponent.getPosts(this.toJSON()).done(function(posts) {
|
||||
console.log('Posts fetched', arguments);
|
||||
CommunicationComponent.getPosts(this.toJSON()).done(function(posts) {
|
||||
that.get('_availablePosts').reset(posts);
|
||||
that.get('_selectedPosts').reset(); // Empty out the collection
|
||||
that.trigger('change:_availablePosts');
|
||||
@ -116,8 +115,7 @@ define([
|
||||
return;
|
||||
}
|
||||
|
||||
WordpressComponent.getTransformedPosts(data).done(function(posts) {
|
||||
console.log('Transformed posts fetched', arguments);
|
||||
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
|
||||
that.get('_transformedPosts').get('blocks').reset(posts, {parse: true});
|
||||
}).fail(function() {
|
||||
console.log('Posts _refreshTransformedPosts error', arguments);
|
||||
@ -133,8 +131,7 @@ define([
|
||||
|
||||
if (data.posts.length === 0) return;
|
||||
|
||||
WordpressComponent.getTransformedPosts(data).done(function(posts) {
|
||||
console.log('Available posts fetched', arguments);
|
||||
CommunicationComponent.getTransformedPosts(data).done(function(posts) {
|
||||
collection.add(posts, { at: index });
|
||||
}).fail(function() {
|
||||
console.log('Posts fetchPosts error', arguments);
|
||||
@ -145,13 +142,14 @@ define([
|
||||
Module.PostsBlockView = base.BlockView.extend({
|
||||
className: "mailpoet_block mailpoet_posts_block mailpoet_droppable_block",
|
||||
getTemplate: function() { return templates.postsBlock; },
|
||||
modelEvents: {},
|
||||
modelEvents: {}, // Forcefully disable all events
|
||||
regions: _.extend({
|
||||
postsRegion: '.mailpoet_posts_block_posts',
|
||||
}, base.BlockView.prototype.regions),
|
||||
onDragSubstituteBy: function() { return Module.PostsWidgetView; },
|
||||
initialize: function() {
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
|
||||
this.toolsView = new Module.PostsBlockToolsView({ model: this.model });
|
||||
this.model.reply('blockView', this.notifyAboutSelf, this);
|
||||
},
|
||||
@ -271,7 +269,7 @@ define([
|
||||
var that = this;
|
||||
|
||||
// Dynamically update available post types
|
||||
WordpressComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
|
||||
CommunicationComponent.getPostTypes().done(_.bind(this._updateContentTypes, this));
|
||||
|
||||
this.$('.mailpoet_posts_categories_and_tags').select2({
|
||||
multiple: true,
|
||||
@ -284,10 +282,10 @@ define([
|
||||
},
|
||||
transport: function(options, success, failure) {
|
||||
var taxonomies,
|
||||
promise = WordpressComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
promise = CommunicationComponent.getTaxonomies(that.model.get('contentType')).then(function(tax) {
|
||||
taxonomies = tax;
|
||||
// Fetch available terms based on the list of taxonomies already fetched
|
||||
var promise = WordpressComponent.getTerms({
|
||||
var promise = CommunicationComponent.getTerms({
|
||||
search: options.data.term,
|
||||
taxonomies: _.keys(taxonomies)
|
||||
}).then(function(terms) {
|
||||
|
@ -175,12 +175,9 @@ define([
|
||||
_event.stopPropagation();
|
||||
},
|
||||
getDropFunc: function() {
|
||||
var that = this;
|
||||
return function() {
|
||||
var newModel = that.model.clone();
|
||||
//that.model.destroy();
|
||||
return newModel;
|
||||
};
|
||||
return this.model.clone();
|
||||
}.bind(this);
|
||||
},
|
||||
_buildRegions: function(regions) {
|
||||
var that = this;
|
||||
@ -211,20 +208,32 @@ define([
|
||||
}.bind(this));
|
||||
},
|
||||
transitionIn: function() {
|
||||
return this._transition('mailpoet_block_transition_in');
|
||||
return this._transition('slideDown', 'fadeIn', 'easeIn');
|
||||
},
|
||||
transitionOut: function() {
|
||||
return this._transition('mailpoet_block_transition_out');
|
||||
return this._transition('slideUp', 'fadeOut', 'easeOut');
|
||||
},
|
||||
_transition: function(className) {
|
||||
var that = this,
|
||||
promise = jQuery.Deferred();
|
||||
_transition: function(slideDirection, fadeDirection, easing) {
|
||||
var promise = jQuery.Deferred();
|
||||
|
||||
this.$el.velocity(
|
||||
slideDirection,
|
||||
{
|
||||
duration: 250,
|
||||
easing: easing,
|
||||
complete: function() {
|
||||
promise.resolve();
|
||||
}.bind(this),
|
||||
}
|
||||
).velocity(
|
||||
fadeDirection,
|
||||
{
|
||||
duration: 250,
|
||||
easing: easing,
|
||||
queue: false, // Do not enqueue, trigger animation in parallel
|
||||
}
|
||||
);
|
||||
|
||||
this.$el.addClass(className);
|
||||
this.$el.one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd animationend', function() {
|
||||
that.$el.removeClass('mailpoet_block_transition_out');
|
||||
promise.resolve();
|
||||
});
|
||||
return promise;
|
||||
},
|
||||
});
|
||||
|
@ -26,6 +26,8 @@ define([
|
||||
getTemplate: function() { return templates.textBlock; },
|
||||
modelEvents: _.omit(base.BlockView.prototype.modelEvents, 'change'), // Prevent rerendering on model change due to text editor redrawing
|
||||
initialize: function(options) {
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
|
||||
this.renderOptions = _.defaults(options.renderOptions || {}, {
|
||||
disableTextEditor: false,
|
||||
});
|
||||
|
@ -63,16 +63,18 @@ define([
|
||||
};
|
||||
|
||||
Module.saveNewsletter = function(options) {
|
||||
return Module._query({
|
||||
return MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
action: 'save',
|
||||
options: options,
|
||||
data: options || {},
|
||||
});
|
||||
};
|
||||
|
||||
Module.previewNewsletter = function(options) {
|
||||
return Module._query({
|
||||
action: 'preview',
|
||||
options: options,
|
||||
return MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
action: 'sendPreview',
|
||||
data: options || {},
|
||||
});
|
||||
};
|
||||
|
@ -44,10 +44,10 @@ define([
|
||||
};
|
||||
|
||||
Module.getBody = function() {
|
||||
return JSON.stringify({
|
||||
return {
|
||||
content: App._contentContainer.toJSON(),
|
||||
globalStyles: App.getGlobalStyles().toJSON(),
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Module.toJSON = function() {
|
||||
@ -73,8 +73,7 @@ define([
|
||||
});
|
||||
|
||||
App.on('start', function(options) {
|
||||
// TODO: Other newsletter information will be needed as well.
|
||||
var body = JSON.parse(options.newsletter.body);
|
||||
var body = options.newsletter.body;
|
||||
App._contentContainer = new (App.getBlockTypeModel('container'))(body.content, {parse: true});
|
||||
App._contentContainerView = new (App.getBlockTypeView('container'))({
|
||||
model: App._contentContainer,
|
||||
|
@ -1,5 +1,6 @@
|
||||
define([
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/components/communication',
|
||||
'mailpoet',
|
||||
'notice',
|
||||
'backbone',
|
||||
@ -8,7 +9,18 @@ define([
|
||||
'blob',
|
||||
'filesaver',
|
||||
'html2canvas'
|
||||
], function(App, MailPoet, Notice, Backbone, Marionette, jQuery, Blob, FileSaver, html2canvas) {
|
||||
], function(
|
||||
App,
|
||||
CommunicationComponent,
|
||||
MailPoet,
|
||||
Notice,
|
||||
Backbone,
|
||||
Marionette,
|
||||
jQuery,
|
||||
Blob,
|
||||
FileSaver,
|
||||
html2canvas
|
||||
) {
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -17,26 +29,33 @@ define([
|
||||
|
||||
// Save editor contents to server
|
||||
Module.save = function() {
|
||||
App.getChannel().trigger('beforeEditorSave');
|
||||
|
||||
var json = App.toJSON();
|
||||
|
||||
// Stringify to enable transmission of primitive non-string value types
|
||||
if (!_.isUndefined(json.body)) {
|
||||
json.body = JSON.stringify(json.body);
|
||||
}
|
||||
|
||||
App.getChannel().trigger('beforeEditorSave', json);
|
||||
|
||||
// save newsletter
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
action: 'save',
|
||||
data: json,
|
||||
}).done(function(response) {
|
||||
CommunicationComponent.saveNewsletter(json).done(function(response) {
|
||||
if(response.success !== undefined && response.success === true) {
|
||||
// TODO: Handle translations
|
||||
//MailPoet.Notice.success("<?php _e('Newsletter has been saved.'); ?>");
|
||||
} else if(response.error !== undefined) {
|
||||
if(response.error.length === 0) {
|
||||
// TODO: Handle translations
|
||||
MailPoet.Notice.error("<?php _e('An unknown error occurred, please check your settings.'); ?>");
|
||||
MailPoet.Notice.error(
|
||||
"An unknown error occurred, please check your settings.",
|
||||
{
|
||||
scroll: true,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
$(response.error).each(function(i, error) {
|
||||
MailPoet.Notice.error(error);
|
||||
MailPoet.Notice.error(error, { scroll: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -58,7 +77,7 @@ define([
|
||||
promise.then(function(thumbnail) {
|
||||
var data = _.extend(options || {}, {
|
||||
thumbnail: thumbnail.toDataURL('image/jpeg'),
|
||||
body: App.getBody(),
|
||||
body: JSON.stringify(App.getBody()),
|
||||
});
|
||||
|
||||
return MailPoet.Ajax.post({
|
||||
@ -146,20 +165,52 @@ define([
|
||||
},
|
||||
saveAsTemplate: function() {
|
||||
var templateName = this.$('.mailpoet_save_as_template_name').val(),
|
||||
templateDescription = this.$('.mailpoet_save_as_template_description').val();
|
||||
templateDescription = this.$('.mailpoet_save_as_template_description').val(),
|
||||
that = this;
|
||||
|
||||
console.log('Saving template with ', templateName, templateDescription);
|
||||
Module.saveTemplate({
|
||||
name: templateName,
|
||||
description: templateDescription,
|
||||
}).done(function() {
|
||||
console.log('Template saved', arguments);
|
||||
}).fail(function() {
|
||||
// TODO: Handle error messages
|
||||
console.log('Template save failed', arguments);
|
||||
});
|
||||
if (templateName === '') {
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateNameMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
}
|
||||
);
|
||||
} else if (templateDescription === '') {
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateDescriptionMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
console.log('Saving template with ', templateName, templateDescription);
|
||||
Module.saveTemplate({
|
||||
name: templateName,
|
||||
description: templateDescription,
|
||||
}).done(function() {
|
||||
console.log('Template saved', arguments);
|
||||
MailPoet.Notice.success(
|
||||
App.getConfig().get('translations.templateSaved'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
}
|
||||
);
|
||||
}).fail(function() {
|
||||
console.log('Template save failed', arguments);
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateSaveFailed'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
this.hideOptionContents();
|
||||
}
|
||||
|
||||
this.hideOptionContents();
|
||||
},
|
||||
toggleExportTemplate: function() {
|
||||
this.$('.mailpoet_export_template_container').toggleClass('mailpoet_hidden');
|
||||
@ -170,12 +221,25 @@ define([
|
||||
},
|
||||
exportTemplate: function() {
|
||||
var templateName = this.$('.mailpoet_export_template_name').val(),
|
||||
templateDescription = this.$('.mailpoet_export_template_description').val();
|
||||
templateDescription = this.$('.mailpoet_export_template_description').val(),
|
||||
that = this;
|
||||
|
||||
if (templateName === '') {
|
||||
MailPoet.Notice.error(App.getConfig().get('translations.templateNameMissing'));
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateNameMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
}
|
||||
);
|
||||
} else if (templateDescription === '') {
|
||||
MailPoet.Notice.error(App.getConfig().get('translations.templateDescriptionMissing'));
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.templateDescriptionMissing'),
|
||||
{
|
||||
positionAfter: that.$el,
|
||||
scroll: true,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
console.log('Exporting template with ', templateName, templateDescription);
|
||||
Module.exportTemplate({
|
||||
|
@ -1,12 +1,13 @@
|
||||
define([
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/components/communication',
|
||||
'backbone',
|
||||
'backbone.marionette',
|
||||
'backbone.supermodel',
|
||||
'underscore',
|
||||
'jquery',
|
||||
'sticky-kit'
|
||||
], function(App, Backbone, Marionette, SuperModel, _, jQuery, StickyKit) {
|
||||
], function(App, CommunicationComponent, Backbone, Marionette, SuperModel, _, jQuery, StickyKit) {
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -50,8 +51,33 @@ define([
|
||||
},
|
||||
events: {
|
||||
'click .mailpoet_sidebar_region h3, .mailpoet_sidebar_region .handlediv': function(event) {
|
||||
this.$el.find('.mailpoet_sidebar_region').addClass('closed');
|
||||
this.$el.find(event.target).parent().parent().removeClass('closed');
|
||||
var $openRegion = this.$el.find('.mailpoet_sidebar_region:not(.closed)'),
|
||||
$targetRegion = this.$el.find(event.target).closest('.mailpoet_sidebar_region');
|
||||
|
||||
if ($openRegion.get(0) === $targetRegion.get(0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$openRegion.find('.mailpoet_region_content').velocity(
|
||||
'slideUp',
|
||||
{
|
||||
duration: 250,
|
||||
easing: "easeOut",
|
||||
complete: function() {
|
||||
$openRegion.addClass('closed');
|
||||
}.bind(this)
|
||||
}
|
||||
);
|
||||
$targetRegion.find('.mailpoet_region_content').velocity(
|
||||
'slideDown',
|
||||
{
|
||||
duration: 250,
|
||||
easing: "easeIn",
|
||||
complete: function() {
|
||||
$targetRegion.removeClass('closed');
|
||||
},
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
initialize: function(options) {
|
||||
@ -90,7 +116,6 @@ define([
|
||||
});
|
||||
},
|
||||
onDomRefresh: function() {
|
||||
var that = this;
|
||||
this.$el.parent().stick_in_parent({
|
||||
offset_top: 32,
|
||||
});
|
||||
@ -169,10 +194,8 @@ define([
|
||||
},
|
||||
initialize: function(options) {
|
||||
this.availableStyles = options.availableStyles;
|
||||
var that = this;
|
||||
},
|
||||
onRender: function() {
|
||||
var that = this;
|
||||
this.$('.mailpoet_color').spectrum({
|
||||
clickoutFiresChange: true,
|
||||
showInput: true,
|
||||
@ -219,26 +242,29 @@ define([
|
||||
console.log('trying to send a preview');
|
||||
// get form data
|
||||
var data = {
|
||||
from_name: this.$('#mailpoet_preview_from_name').val(),
|
||||
from_email: this.$('#mailpoet_preview_from_email').val(),
|
||||
to_email: this.$('#mailpoet_preview_to_email').val(),
|
||||
newsletter: App.newsletterId,
|
||||
subscriber: this.$('#mailpoet_preview_to_email').val(),
|
||||
id: App.getNewsletter().get('id'),
|
||||
};
|
||||
|
||||
// send test email
|
||||
MailPoet.Modal.loading(true);
|
||||
|
||||
// TODO: Migrate logic to new AJAX format
|
||||
Wordpress.previewNewsletter(data).done(function(response) {
|
||||
if(response.success !== undefined && response.success === true) {
|
||||
MailPoet.Notice.success(App.getConfig().get('translations.testEmailSent'));
|
||||
} else if(response.error !== undefined) {
|
||||
if(response.error.length === 0) {
|
||||
MailPoet.Notice.error(App.getConfig().get('translations.unknownErrorOccurred'));
|
||||
} else {
|
||||
$(response.error).each(function(i, error) {
|
||||
MailPoet.Notice.error(error);
|
||||
CommunicationComponent.previewNewsletter(data).done(function(response) {
|
||||
if(response.result !== undefined && response.result === true) {
|
||||
MailPoet.Notice.success(App.getConfig().get('translations.newsletterPreviewSent'), { scroll: true });
|
||||
} else {
|
||||
if (_.isArray(response.errors)) {
|
||||
response.errors.map(function(error) {
|
||||
MailPoet.Notice.error(error, { scroll: true });
|
||||
});
|
||||
} else {
|
||||
MailPoet.Notice.error(
|
||||
App.getConfig().get('translations.newsletterPreviewFailedToSend'),
|
||||
{
|
||||
scroll: true,
|
||||
static: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
MailPoet.Modal.loading(false);
|
||||
|
@ -17,7 +17,7 @@ define([
|
||||
},
|
||||
h1: {
|
||||
fontColor: '#111111',
|
||||
fontFamily: 'Arial Black',
|
||||
fontFamily: 'Arial',
|
||||
fontSize: '40px'
|
||||
},
|
||||
h2: {
|
||||
@ -72,7 +72,7 @@ define([
|
||||
|
||||
App.getAvailableStyles = Module.getAvailableStyles;
|
||||
|
||||
var body = JSON.parse(options.newsletter.body);
|
||||
var body = options.newsletter.body;
|
||||
this.setGlobalStyles(body.globalStyles);
|
||||
});
|
||||
|
||||
|
@ -16,7 +16,7 @@ define(
|
||||
Breadcrumb
|
||||
) {
|
||||
|
||||
var settings = window.mailpoet_settings || {};
|
||||
var settings = window.mailpoet_settings || {};
|
||||
|
||||
var fields = [
|
||||
{
|
||||
@ -24,14 +24,17 @@ define(
|
||||
label: 'Subject line',
|
||||
tip: "Be creative! It's the first thing your subscribers see."+
|
||||
"Tempt them to open your email.",
|
||||
type: 'text'
|
||||
type: 'text',
|
||||
validation: {
|
||||
'data-parsley-required': true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
tip: "The subscriber list that will be used for this campaign.",
|
||||
label: 'Segments',
|
||||
tip: "The subscriber segment that will be used for this campaign.",
|
||||
type: 'selection',
|
||||
placeholder: "Select a list",
|
||||
placeholder: "Select a segment",
|
||||
id: "mailpoet_segments",
|
||||
endpoint: "segments",
|
||||
multiple: true,
|
||||
@ -111,12 +114,19 @@ define(
|
||||
action: 'add',
|
||||
data: {
|
||||
newsletter_id: this.props.params.id,
|
||||
segments: jQuery('#mailpoet_segments').val()
|
||||
segments: jQuery('#mailpoet_segments').val(),
|
||||
sender: {
|
||||
'name': jQuery('#mailpoet_newsletter [name="sender_name"]').val(),
|
||||
'address': jQuery('#mailpoet_newsletter [name="sender_address"]').val()
|
||||
},
|
||||
reply_to: {
|
||||
'name': jQuery('#mailpoet_newsletter [name="reply_to_name"]').val(),
|
||||
'address': jQuery('#mailpoet_newsletter [name="reply_to_address"]').val()
|
||||
}
|
||||
}
|
||||
}).done(function(response) {
|
||||
if(response.result === true) {
|
||||
this.history.pushState(null, '/');
|
||||
|
||||
MailPoet.Notice.success(
|
||||
'The newsletter is being sent...'
|
||||
);
|
||||
|
@ -18,6 +18,12 @@ define(
|
||||
|
||||
var ImportTemplate = React.createClass({
|
||||
saveTemplate: function(template) {
|
||||
|
||||
// Stringify to enable transmission of primitive non-string value types
|
||||
if (!_.isUndefined(template.body)) {
|
||||
template.body = JSON.stringify(template.body);
|
||||
}
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletterTemplates',
|
||||
action: 'save',
|
||||
@ -111,12 +117,19 @@ define(
|
||||
}.bind(this));
|
||||
},
|
||||
handleSelectTemplate: function(template) {
|
||||
var body = template.body;
|
||||
|
||||
// Stringify to enable transmission of primitive non-string value types
|
||||
if (!_.isUndefined(body)) {
|
||||
body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
MailPoet.Ajax.post({
|
||||
endpoint: 'newsletters',
|
||||
action: 'save',
|
||||
data: {
|
||||
id: this.props.params.id,
|
||||
body: template.body
|
||||
body: body
|
||||
}
|
||||
}).done(function(response) {
|
||||
if(response.result === true) {
|
||||
@ -153,7 +166,7 @@ define(
|
||||
handleShowTemplate: function(template) {
|
||||
MailPoet.Modal.popup({
|
||||
title: template.name,
|
||||
template: '<img src="{{ thumbnail }}" />',
|
||||
template: '<div class="mailpoet_boxes_preview" style="background-color: {{ body.globalStyles.body.backgroundColor }}"><img src="{{ thumbnail }}" /></div>',
|
||||
data: template,
|
||||
});
|
||||
},
|
||||
|
@ -26,6 +26,7 @@ define(
|
||||
action: 'create',
|
||||
data: {
|
||||
type: type,
|
||||
subject: 'Draft newsletter',
|
||||
}
|
||||
}).done(function(response) {
|
||||
if(response.id !== undefined) {
|
||||
|
@ -1,203 +1,212 @@
|
||||
define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
"use strict";
|
||||
/*==================================================================================================
|
||||
|
||||
MailPoet Notice:
|
||||
|
||||
description: Handles notices
|
||||
version: 0.2
|
||||
author: Jonathan Labreuille
|
||||
company: Wysija
|
||||
dependencies: jQuery
|
||||
|
||||
Usage:
|
||||
|
||||
// success message (static: false)
|
||||
MailPoet.Notice.success('Yatta!');
|
||||
|
||||
// error message (static: false)
|
||||
MailPoet.Notice.error('Boo!');
|
||||
|
||||
// system message (static: true)
|
||||
MailPoet.Notice.system('You need to updated ASAP!');
|
||||
|
||||
Examples:
|
||||
|
||||
MailPoet.Notice.success('- success #1 -');
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.success('- success #2 -');
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.error('- error -');
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.system('- system -');
|
||||
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.hide();
|
||||
}, 2500);
|
||||
}, 300);
|
||||
}, 400);
|
||||
}, 500);
|
||||
|
||||
==================================================================================================*/
|
||||
|
||||
MailPoet.Notice = {
|
||||
version: 0.2,
|
||||
// default options
|
||||
defaults: {
|
||||
type: 'success',
|
||||
message: '',
|
||||
static: false,
|
||||
hideClose: false,
|
||||
id: null,
|
||||
scroll: false,
|
||||
timeout: 2000,
|
||||
onOpen: null,
|
||||
onClose: null
|
||||
},
|
||||
options: {},
|
||||
init: function(options) {
|
||||
// set options
|
||||
this.options = jQuery.extend({}, this.defaults, options);
|
||||
|
||||
// clone element
|
||||
this.element = jQuery('#mailpoet_notice_'+this.options.type).clone();
|
||||
|
||||
// add data-id to the element
|
||||
if (this.options.id) this.element.attr('data-id', 'notice_' + this.options.id);
|
||||
|
||||
// remove id from clone
|
||||
this.element.removeAttr('id');
|
||||
|
||||
// insert notice after its parent
|
||||
jQuery('#mailpoet_notice_'+this.options.type).after(this.element);
|
||||
|
||||
// setup onClose callback
|
||||
var onClose = null;
|
||||
if(this.options.onClose !== null) {
|
||||
onClose = this.options.onClose;
|
||||
}
|
||||
|
||||
// listen to remove event
|
||||
jQuery(this.element).on('close', function() {
|
||||
jQuery(this).fadeOut(200, function() {
|
||||
// on close callback
|
||||
if(onClose !== null) {
|
||||
onClose();
|
||||
}
|
||||
// remove notice
|
||||
jQuery(this).remove();
|
||||
});
|
||||
}.bind(this.element));
|
||||
|
||||
// listen to message event
|
||||
jQuery(this.element).on('message', function(e, message) {
|
||||
MailPoet.Notice.setMessage(message);
|
||||
}.bind(this.element));
|
||||
|
||||
return this;
|
||||
},
|
||||
isHTML: function(str) {
|
||||
var a = document.createElement('div');
|
||||
a.innerHTML = str;
|
||||
for(var c = a.childNodes, i = c.length; i--;) {
|
||||
if(c[i].nodeType == 1) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
setMessage: function(message) {
|
||||
// if it's not an html message, let's sugar coat the message with a fancy <p>
|
||||
if(this.isHTML(message) === false) {
|
||||
message = '<p>'+message+'</p>';
|
||||
}
|
||||
// set message
|
||||
return this.element.html(message);
|
||||
},
|
||||
show: function(options) {
|
||||
// initialize
|
||||
this.init(options);
|
||||
|
||||
// show notice
|
||||
this.showNotice();
|
||||
|
||||
// return this;
|
||||
},
|
||||
showNotice: function() {
|
||||
// set message
|
||||
this.setMessage(this.options.message);
|
||||
|
||||
// position notice
|
||||
this.element.insertAfter(jQuery('h2.title'));
|
||||
|
||||
// set class name
|
||||
switch(this.options.type) {
|
||||
case 'success':
|
||||
this.element.addClass('updated');
|
||||
break;
|
||||
case 'system':
|
||||
this.element.addClass('update-nag');
|
||||
break;
|
||||
case 'error':
|
||||
this.element.addClass('error');
|
||||
break;
|
||||
}
|
||||
|
||||
// make the notice appear
|
||||
this.element.fadeIn(200);
|
||||
|
||||
// if scroll option is enabled, scroll to the notice
|
||||
if(this.options.scroll === true) {
|
||||
this.element.get(0).scrollIntoView(false);
|
||||
}
|
||||
|
||||
// if the notice is not static, it has to disappear after a timeout
|
||||
if(this.options.static === false) {
|
||||
this.element.delay(this.options.timeout).trigger('close');
|
||||
} else if (this.options.hideClose === false) {
|
||||
this.element.append('<a href="javascript:;" class="mailpoet_notice_close"><span class="dashicons dashicons-dismiss"></span></a>');
|
||||
this.element.find('.mailpoet_notice_close').on('click', function() {
|
||||
jQuery(this).trigger('close');
|
||||
});
|
||||
}
|
||||
|
||||
// call onOpen callback
|
||||
if(this.options.onOpen !== null) {
|
||||
this.options.onOpen(this.element);
|
||||
}
|
||||
},
|
||||
hide: function(all) {
|
||||
if(all !== undefined && all === true) {
|
||||
jQuery('.mailpoet_notice:not([id])').trigger('close');
|
||||
} else if (all !== undefined && jQuery.isArray(all)) {
|
||||
for (var id in all) {
|
||||
jQuery('[data-id="notice_' + all[id] + '"]')
|
||||
.trigger('close');
|
||||
}
|
||||
} if (all !== undefined) {
|
||||
jQuery('[data-id="notice_' + all + '"]')
|
||||
.trigger('close');
|
||||
} else {
|
||||
jQuery('.mailpoet_notice.updated:not([id]), .mailpoet_notice.error:not([id])')
|
||||
.trigger('close');
|
||||
}
|
||||
},
|
||||
error: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'error',
|
||||
message: '<p>'+message+'</p>'
|
||||
}, options));
|
||||
},
|
||||
success: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'success',
|
||||
message: '<p>'+message+'</p>'
|
||||
}, options));
|
||||
},
|
||||
system: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'system',
|
||||
static: true,
|
||||
message: message
|
||||
}, options));
|
||||
}
|
||||
};
|
||||
define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
||||
"use strict";
|
||||
/*==================================================================================================
|
||||
|
||||
MailPoet Notice:
|
||||
|
||||
description: Handles notices
|
||||
version: 0.2
|
||||
author: Jonathan Labreuille
|
||||
company: Wysija
|
||||
dependencies: jQuery
|
||||
|
||||
Usage:
|
||||
|
||||
// success message (static: false)
|
||||
MailPoet.Notice.success('Yatta!');
|
||||
|
||||
// error message (static: false)
|
||||
MailPoet.Notice.error('Boo!');
|
||||
|
||||
// system message (static: true)
|
||||
MailPoet.Notice.system('You need to updated ASAP!');
|
||||
|
||||
Examples:
|
||||
|
||||
MailPoet.Notice.success('- success #1 -');
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.success('- success #2 -');
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.error('- error -');
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.system('- system -');
|
||||
|
||||
setTimeout(function() {
|
||||
MailPoet.Notice.hide();
|
||||
}, 2500);
|
||||
}, 300);
|
||||
}, 400);
|
||||
}, 500);
|
||||
|
||||
==================================================================================================*/
|
||||
|
||||
MailPoet.Notice = {
|
||||
version: 0.2,
|
||||
// default options
|
||||
defaults: {
|
||||
type: 'success',
|
||||
message: '',
|
||||
static: false,
|
||||
hideClose: false,
|
||||
id: null,
|
||||
positionAfter: false,
|
||||
scroll: false,
|
||||
timeout: 2000,
|
||||
onOpen: null,
|
||||
onClose: null
|
||||
},
|
||||
options: {},
|
||||
init: function(options) {
|
||||
// set options
|
||||
this.options = jQuery.extend({}, this.defaults, options);
|
||||
|
||||
// clone element
|
||||
this.element = jQuery('#mailpoet_notice_'+this.options.type).clone();
|
||||
|
||||
// add data-id to the element
|
||||
if (this.options.id) this.element.attr('data-id', 'notice_' + this.options.id);
|
||||
|
||||
// remove id from clone
|
||||
this.element.removeAttr('id');
|
||||
|
||||
// insert notice after its parent
|
||||
var positionAfter;
|
||||
if (typeof this.options.positionAfter === 'object') {
|
||||
positionAfter = this.options.positionAfter;
|
||||
} else if (typeof this.options.positionAfter === 'string') {
|
||||
positionAfter = jQuery(this.options.positionAfter);
|
||||
} else {
|
||||
positionAfter = jQuery('#mailpoet_notice_'+this.options.type);
|
||||
}
|
||||
positionAfter.after(this.element);
|
||||
|
||||
// setup onClose callback
|
||||
var onClose = null;
|
||||
if(this.options.onClose !== null) {
|
||||
onClose = this.options.onClose;
|
||||
}
|
||||
|
||||
// listen to remove event
|
||||
jQuery(this.element).on('close', function() {
|
||||
jQuery(this).fadeOut(200, function() {
|
||||
// on close callback
|
||||
if(onClose !== null) {
|
||||
onClose();
|
||||
}
|
||||
// remove notice
|
||||
jQuery(this).remove();
|
||||
});
|
||||
}.bind(this.element));
|
||||
|
||||
// listen to message event
|
||||
jQuery(this.element).on('message', function(e, message) {
|
||||
MailPoet.Notice.setMessage(message);
|
||||
}.bind(this.element));
|
||||
|
||||
return this;
|
||||
},
|
||||
isHTML: function(str) {
|
||||
var a = document.createElement('div');
|
||||
a.innerHTML = str;
|
||||
for(var c = a.childNodes, i = c.length; i--;) {
|
||||
if(c[i].nodeType == 1) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
setMessage: function(message) {
|
||||
// if it's not an html message, let's sugar coat the message with a fancy <p>
|
||||
if(this.isHTML(message) === false) {
|
||||
message = '<p>'+message+'</p>';
|
||||
}
|
||||
// set message
|
||||
return this.element.html(message);
|
||||
},
|
||||
show: function(options) {
|
||||
// initialize
|
||||
this.init(options);
|
||||
|
||||
// show notice
|
||||
this.showNotice();
|
||||
|
||||
// return this;
|
||||
},
|
||||
showNotice: function() {
|
||||
// set message
|
||||
this.setMessage(this.options.message);
|
||||
|
||||
// position notice
|
||||
this.element.insertAfter(jQuery('h2.title'));
|
||||
|
||||
// set class name
|
||||
switch(this.options.type) {
|
||||
case 'success':
|
||||
this.element.addClass('updated');
|
||||
break;
|
||||
case 'system':
|
||||
this.element.addClass('update-nag');
|
||||
break;
|
||||
case 'error':
|
||||
this.element.addClass('error');
|
||||
break;
|
||||
}
|
||||
|
||||
// make the notice appear
|
||||
this.element.fadeIn(200);
|
||||
|
||||
// if scroll option is enabled, scroll to the notice
|
||||
if(this.options.scroll === true) {
|
||||
this.element.get(0).scrollIntoView(false);
|
||||
}
|
||||
|
||||
// if the notice is not static, it has to disappear after a timeout
|
||||
if(this.options.static === false) {
|
||||
this.element.delay(this.options.timeout).trigger('close');
|
||||
} else if (this.options.hideClose === false) {
|
||||
this.element.append('<a href="javascript:;" class="mailpoet_notice_close"><span class="dashicons dashicons-dismiss"></span></a>');
|
||||
this.element.find('.mailpoet_notice_close').on('click', function() {
|
||||
jQuery(this).trigger('close');
|
||||
});
|
||||
}
|
||||
|
||||
// call onOpen callback
|
||||
if(this.options.onOpen !== null) {
|
||||
this.options.onOpen(this.element);
|
||||
}
|
||||
},
|
||||
hide: function(all) {
|
||||
if(all !== undefined && all === true) {
|
||||
jQuery('.mailpoet_notice:not([id])').trigger('close');
|
||||
} else if (all !== undefined && jQuery.isArray(all)) {
|
||||
for (var id in all) {
|
||||
jQuery('[data-id="notice_' + all[id] + '"]')
|
||||
.trigger('close');
|
||||
}
|
||||
} if (all !== undefined) {
|
||||
jQuery('[data-id="notice_' + all + '"]')
|
||||
.trigger('close');
|
||||
} else {
|
||||
jQuery('.mailpoet_notice.updated:not([id]), .mailpoet_notice.error:not([id])')
|
||||
.trigger('close');
|
||||
}
|
||||
},
|
||||
error: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'error',
|
||||
message: '<p>'+message+'</p>'
|
||||
}, options));
|
||||
},
|
||||
success: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'success',
|
||||
message: '<p>'+message+'</p>'
|
||||
}, options));
|
||||
},
|
||||
system: function(message, options) {
|
||||
this.show(jQuery.extend({}, {
|
||||
type: 'system',
|
||||
static: true,
|
||||
message: message
|
||||
}, options));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -42,11 +42,7 @@ define(
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Segment <a
|
||||
href="javascript:;"
|
||||
className="add-new-h2"
|
||||
onClick={ this.history.goBack }
|
||||
>Back to list</a>
|
||||
Segment
|
||||
</h2>
|
||||
|
||||
<Form
|
||||
|
@ -51,6 +51,28 @@ define(
|
||||
}
|
||||
];
|
||||
|
||||
var custom_fields = window.mailpoet_custom_fields || [];
|
||||
custom_fields.map(custom_field => {
|
||||
if(custom_field.type === 'input') {
|
||||
custom_field.type = 'text';
|
||||
}
|
||||
|
||||
let field = {
|
||||
name: 'cf_' + custom_field.id,
|
||||
label: custom_field.name,
|
||||
type: custom_field.type
|
||||
};
|
||||
if(custom_field.params) {
|
||||
field.params = custom_field.params;
|
||||
}
|
||||
|
||||
if(custom_field.params.values) {
|
||||
field.values = custom_field.params.values;
|
||||
}
|
||||
|
||||
fields.push(field);
|
||||
});
|
||||
|
||||
var messages = {
|
||||
onUpdate: function() {
|
||||
MailPoet.Notice.success('Subscriber successfully updated!');
|
||||
@ -70,11 +92,7 @@ define(
|
||||
return (
|
||||
<div>
|
||||
<h2 className="title">
|
||||
Subscriber <a
|
||||
href="javascript:;"
|
||||
className="add-new-h2"
|
||||
onClick={ this.history.goBack }
|
||||
>Back to list</a>
|
||||
Subscriber
|
||||
</h2>
|
||||
|
||||
<Form
|
||||
|
@ -62,7 +62,7 @@ define(
|
||||
if (_.contains(fieldsToExclude, selectedOptionId)) {
|
||||
selectEvent.preventDefault();
|
||||
if (selectedOptionId === 'deselect') {
|
||||
jQuery(selectElement).select2('val', '');
|
||||
jQuery(selectElement).val('').trigger('change');
|
||||
} else {
|
||||
var allOptions = [];
|
||||
_.each(container.find('option'), function (field) {
|
||||
@ -70,7 +70,7 @@ define(
|
||||
allOptions.push(field.value);
|
||||
}
|
||||
});
|
||||
jQuery(selectElement).select2('val', allOptions);
|
||||
jQuery(selectElement).val(allOptions).trigger('change');
|
||||
}
|
||||
jQuery(selectElement).select2('close');
|
||||
}
|
||||
@ -138,11 +138,11 @@ define(
|
||||
endpoint: 'ImportExport',
|
||||
action: 'processExport',
|
||||
data: JSON.stringify({
|
||||
'exportConfirmedOption': exportData.exportConfirmedOption,
|
||||
'exportFormatOption': jQuery(':radio[name="option_format"]:checked').val(),
|
||||
'groupBySegmentOption': (groupBySegmentOptionElement.is(":visible")) ? groupBySegmentOptionElement.prop('checked') : false,
|
||||
'export_confirmed_option': exportData.exportConfirmedOption,
|
||||
'export_format_option': jQuery(':radio[name="option_format"]:checked').val(),
|
||||
'group_by_segment_option': (groupBySegmentOptionElement.is(":visible")) ? groupBySegmentOptionElement.prop('checked') : false,
|
||||
'segments': (exportData.segments) ? segmentsContainerElement.val() : false,
|
||||
'subscriberFields': subscriberFieldsContainerElement.val()
|
||||
'subscriber_fields': subscriberFieldsContainerElement.val()
|
||||
})
|
||||
})
|
||||
.done(function (response) {
|
||||
|
File diff suppressed because it is too large
Load Diff
39
build
39
build
@ -1,39 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Remove previous build.
|
||||
rm wysija-newsletters.zip;
|
||||
|
||||
# Create temp dir.
|
||||
mkdir wysija-newsletters;
|
||||
|
||||
# Production assets.
|
||||
npm install;
|
||||
./do compile:all;
|
||||
|
||||
# Production libraries.
|
||||
./composer.phar install --no-dev;
|
||||
|
||||
# Copy release folders.
|
||||
cp -Rf lang wysija-newsletters;
|
||||
cp -RfL assets wysija-newsletters;
|
||||
cp -Rf lib wysija-newsletters;
|
||||
cp -Rf vendor wysija-newsletters;
|
||||
cp -Rf views wysija-newsletters;
|
||||
rm -Rf wysija-newsletters/assets/css/src;
|
||||
rm -Rf wysija-newsletters/assets/js/src;
|
||||
|
||||
# Copy release files.
|
||||
cp LICENSE wysija-newsletters;
|
||||
cp index.php wysija-newsletters;
|
||||
cp mailpoet.php wysija-newsletters;
|
||||
cp readme.txt wysija-newsletters;
|
||||
cp uninstall.php wysija-newsletters;
|
||||
|
||||
# Zip final release.
|
||||
zip -r wysija-newsletters.zip wysija-newsletters;
|
||||
|
||||
# Remove temp dir.
|
||||
rm -rf wysija-newsletters;
|
||||
|
||||
# Reinstall dev dependencies.
|
||||
./composer.phar install;
|
42
build.sh
Executable file
42
build.sh
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
|
||||
plugin_name='mailpoet'
|
||||
|
||||
# Remove previous build.
|
||||
rm $plugin_name.zip
|
||||
|
||||
# Create temp dir.
|
||||
mkdir $plugin_name
|
||||
|
||||
# Production assets.
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
./do compile:all
|
||||
|
||||
# Production libraries.
|
||||
./composer.phar install --no-dev
|
||||
|
||||
# Copy release folders.
|
||||
cp -Rf lang $plugin_name
|
||||
cp -RfL assets $plugin_name
|
||||
cp -Rf lib $plugin_name
|
||||
cp -Rf vendor $plugin_name
|
||||
cp -Rf views $plugin_name
|
||||
rm -Rf $plugin_name/assets/css/src
|
||||
rm -Rf $plugin_name/assets/js/src
|
||||
|
||||
# Copy release files.
|
||||
cp LICENSE $plugin_name
|
||||
cp index.php $plugin_name
|
||||
cp $plugin_name.php $plugin_name
|
||||
cp readme.txt $plugin_name
|
||||
cp uninstall.php $plugin_name
|
||||
|
||||
# Zip final release.
|
||||
zip -r $plugin_name.zip $plugin_name
|
||||
|
||||
# Remove temp dir.
|
||||
rm -rf $plugin_name
|
||||
|
||||
# Reinstall dev dependencies.
|
||||
./composer.phar install
|
608
composer.lock
generated
608
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -23,4 +23,9 @@ class Activator {
|
||||
$populator = new Populator();
|
||||
$populator->up();
|
||||
}
|
||||
|
||||
function deactivate() {
|
||||
$migrator = new Migrator();
|
||||
$migrator->down();
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,8 @@ class Analytics {
|
||||
}
|
||||
|
||||
function init() {
|
||||
add_action('admin_enqueue_scripts', array($this, 'setupAdminDependencies'));
|
||||
// review: this creates a fatal error when mailpoet tables are dropped.
|
||||
//add_action('admin_enqueue_scripts', array($this, 'setupAdminDependencies'));
|
||||
}
|
||||
|
||||
function setupAdminDependencies() {
|
||||
|
@ -6,15 +6,14 @@ if(!defined('ABSPATH')) exit;
|
||||
class Env {
|
||||
static $version;
|
||||
static $plugin_name;
|
||||
static $plugin_url;
|
||||
static $plugin_path;
|
||||
static $file;
|
||||
static $path;
|
||||
static $views_path;
|
||||
static $assets_path;
|
||||
static $assets_url;
|
||||
static $temp_name;
|
||||
static $temp_path;
|
||||
static $temp_URL;
|
||||
static $languages_path;
|
||||
static $lib_path;
|
||||
static $plugin_prefix;
|
||||
@ -34,12 +33,11 @@ class Env {
|
||||
self::$file = $file;
|
||||
self::$path = dirname(self::$file);
|
||||
self::$plugin_name = 'mailpoet';
|
||||
self::$plugin_url = plugin_dir_url(__FILE__);
|
||||
self::$views_path = self::$path . '/views';
|
||||
self::$assets_path = self::$path . '/assets';
|
||||
self::$assets_url = plugins_url('/assets', $file);
|
||||
self::$temp_name = 'temp';
|
||||
self::$temp_path = self::$path . '/' . self::$temp_name;
|
||||
self::$temp_path = wp_upload_dir()['path'];
|
||||
self::$temp_URL = wp_upload_dir()['url'];
|
||||
self::$languages_path = self::$path . '/lang';
|
||||
self::$lib_path = self::$path . '/lib';
|
||||
self::$plugin_prefix = 'mailpoet_';
|
||||
|
@ -1,11 +1,61 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
use \MailPoet\Models\Setting;
|
||||
|
||||
class Hooks {
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
function init() {
|
||||
// Subscribe in comments
|
||||
if((bool)Setting::getValue('subscribe.on_comment.enabled')) {
|
||||
add_action(
|
||||
'comment_form_after_fields',
|
||||
'\MailPoet\Subscription\Comment::extendForm'
|
||||
);
|
||||
|
||||
add_action(
|
||||
'comment_post',
|
||||
'\MailPoet\Subscription\Comment::onSubmit',
|
||||
60,
|
||||
2
|
||||
);
|
||||
|
||||
add_action(
|
||||
'wp_set_comment_status',
|
||||
'\MailPoet\Subscription\Comment::onStatusUpdate',
|
||||
60,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
// Subscribe in registration form
|
||||
if((bool)Setting::getValue('subscribe.on_register.enabled')) {
|
||||
if(is_multisite()) {
|
||||
add_action(
|
||||
'signup_extra_fields',
|
||||
'\MailPoet\Subscription\Registration::extendForm'
|
||||
);
|
||||
add_action(
|
||||
'wpmu_validate_user_signup',
|
||||
'\MailPoet\Subscription\Registration::onMultiSiteRegister',
|
||||
60,
|
||||
1
|
||||
);
|
||||
} else {
|
||||
add_action(
|
||||
'register_form',
|
||||
'\MailPoet\Subscription\Registration::extendForm'
|
||||
);
|
||||
add_action(
|
||||
'register_post',
|
||||
'\MailPoet\Subscription\Registration::onRegister',
|
||||
60,
|
||||
3
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// WP Users synchronization
|
||||
add_action(
|
||||
'user_register',
|
||||
|
@ -4,6 +4,8 @@ namespace MailPoet\Config;
|
||||
use MailPoet\Models;
|
||||
use MailPoet\Cron\Supervisor;
|
||||
use MailPoet\Router;
|
||||
use MailPoet\Models\Setting;
|
||||
use MailPoet\Settings\Pages;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
@ -28,7 +30,9 @@ class Initializer {
|
||||
$this->setupChangelog();
|
||||
$this->setupPublicAPI();
|
||||
$this->runQueueSupervisor();
|
||||
$this->setupShortcodes();
|
||||
$this->setupHooks();
|
||||
$this->setupPages();
|
||||
$this->setupImages();
|
||||
}
|
||||
|
||||
@ -73,7 +77,7 @@ class Initializer {
|
||||
define('MP_SUBSCRIBER_CUSTOM_FIELD_TABLE', $subscriber_custom_field);
|
||||
define('MP_NEWSLETTER_OPTION_FIELDS_TABLE', $newsletter_option_fields);
|
||||
define('MP_NEWSLETTER_OPTION_TABLE', $newsletter_option);
|
||||
define('MP_SENDING_QUEUE_TABLE', $sending_queues);
|
||||
define('MP_SENDING_QUEUES_TABLE', $sending_queues);
|
||||
define('MP_NEWSLETTER_STATISTICS_TABLE', $newsletter_statistics);
|
||||
}
|
||||
|
||||
@ -125,6 +129,15 @@ class Initializer {
|
||||
$changelog->init();
|
||||
}
|
||||
|
||||
function setupPages() {
|
||||
$pages = new Pages();
|
||||
$pages->init();
|
||||
}
|
||||
|
||||
function setupShortcodes() {
|
||||
$shortcodes = new Shortcodes();
|
||||
$shortcodes->init();
|
||||
}
|
||||
function setupHooks() {
|
||||
$hooks = new Hooks();
|
||||
$hooks->init();
|
||||
@ -136,13 +149,15 @@ class Initializer {
|
||||
}
|
||||
|
||||
function runQueueSupervisor() {
|
||||
if(php_sapi_name() === 'cli') return;
|
||||
try {
|
||||
$supervisor = new Supervisor();
|
||||
$supervisor->checkDaemon();
|
||||
} catch (\Exception $e) {}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
function setupImages() {
|
||||
add_image_size('mailpoet_newsletter_max', 1320);
|
||||
}
|
||||
}
|
||||
}
|
@ -190,6 +190,8 @@ class Menu {
|
||||
}
|
||||
|
||||
function welcome() {
|
||||
if((bool)(defined('DOING_AJAX') && DOING_AJAX)) return;
|
||||
|
||||
global $wp;
|
||||
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
||||
$redirect_url =
|
||||
@ -240,6 +242,7 @@ class Menu {
|
||||
|
||||
function settings() {
|
||||
$settings = Setting::getAll();
|
||||
$flags = $this->_getFlags();
|
||||
|
||||
// dkim: check if public/private keys have been generated
|
||||
if(
|
||||
@ -258,10 +261,9 @@ class Menu {
|
||||
|
||||
$data = array(
|
||||
'settings' => $settings,
|
||||
'segments' => Segment::getPublished()
|
||||
->findArray(),
|
||||
'segments' => Segment::getPublic()->findArray(),
|
||||
'pages' => Pages::getAll(),
|
||||
'flags' => $this->_getFlags(),
|
||||
'flags' => $flags,
|
||||
'charsets' => Charsets::getAll(),
|
||||
'current_user' => wp_get_current_user(),
|
||||
'permissions' => Permissions::getAll(),
|
||||
@ -294,7 +296,7 @@ class Menu {
|
||||
} else {
|
||||
// check if users can register
|
||||
$flags['registration_enabled'] =
|
||||
(bool) get_option('users_can_register', false);
|
||||
(bool)get_option('users_can_register', false);
|
||||
}
|
||||
|
||||
return $flags;
|
||||
@ -305,6 +307,23 @@ class Menu {
|
||||
|
||||
$data['segments'] = Segment::findArray();
|
||||
|
||||
$data['custom_fields'] = array_map(function($field) {
|
||||
$field['params'] = unserialize($field['params']);
|
||||
|
||||
if(!empty($field['params']['values'])) {
|
||||
$values = array();
|
||||
|
||||
foreach($field['params']['values'] as $value) {
|
||||
$values[$value['value']] = $value['value'];
|
||||
}
|
||||
$field['params']['values'] = $values;
|
||||
}
|
||||
return $field;
|
||||
}, CustomField::findArray());
|
||||
|
||||
$data['date_formats'] = Block\Date::getDateFormats();
|
||||
$data['month_names'] = Block\Date::getMonthNames();
|
||||
|
||||
echo $this->renderer->render('subscribers/subscribers.html', $data);
|
||||
}
|
||||
|
||||
@ -374,15 +393,14 @@ class Menu {
|
||||
->findArray(),
|
||||
'styles' => FormRenderer::getStyles($form),
|
||||
'date_types' => Block\Date::getDateTypes(),
|
||||
'date_formats' => Block\Date::getDateFormats()
|
||||
'date_formats' => Block\Date::getDateFormats(),
|
||||
'month_names' => Block\Date::getMonthNames()
|
||||
);
|
||||
|
||||
echo $this->renderer->render('form/editor.html', $data);
|
||||
}
|
||||
|
||||
function cron() {
|
||||
$daemon = new \MailPoet\Cron\BootStrapMenu();
|
||||
$data['daemon'] = json_encode($daemon->bootstrap());
|
||||
echo $this->renderer->render('cron.html', $data);
|
||||
echo $this->renderer->render('cron.html');
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class Migrator {
|
||||
function down() {
|
||||
global $wpdb;
|
||||
|
||||
$drop_table = function($model) {
|
||||
$drop_table = function($model) use($wpdb) {
|
||||
$table = $this->prefix . $model;
|
||||
$wpdb->query("DROP TABLE {$table}");
|
||||
};
|
||||
@ -105,7 +105,7 @@ class Migrator {
|
||||
'description varchar(250) NOT NULL,',
|
||||
'body LONGTEXT,',
|
||||
'thumbnail LONGTEXT,',
|
||||
'readonly TINYINT(1) DEFAULT 0',
|
||||
'readonly TINYINT(1) DEFAULT 0,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'PRIMARY KEY (id)'
|
||||
|
@ -3,8 +3,12 @@ namespace MailPoet\Config;
|
||||
|
||||
use MailPoet\Config\PopulatorData\Templates\FranksRoastHouseTemplate;
|
||||
use MailPoet\Config\PopulatorData\Templates\BlankTemplate;
|
||||
use MailPoet\Config\PopulatorData\Templates\WelcomeTemplate;
|
||||
use MailPoet\Config\PopulatorData\Templates\PostNotificationsBlankTemplate;
|
||||
use \MailPoet\Models\Segment;
|
||||
use \MailPoet\Segments\WP;
|
||||
use \MailPoet\Models\Setting;
|
||||
use \MailPoet\Settings\Pages;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
@ -44,6 +48,57 @@ class Populator {
|
||||
array_map(array($this, 'populate'), $this->models);
|
||||
|
||||
$this->createDefaultSegments();
|
||||
$this->createDefaultSettings();
|
||||
$this->createMailPoetPage();
|
||||
}
|
||||
|
||||
private function createMailPoetPage() {
|
||||
$pages = get_posts(array(
|
||||
'posts_per_page' => 1,
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'post_type' => 'mailpoet_page'
|
||||
));
|
||||
|
||||
$page = null;
|
||||
if(!empty($pages)) {
|
||||
$page = array_shift($pages);
|
||||
if(strpos($page->post_content, '[mailpoet_page]') === false) {
|
||||
$page = null;
|
||||
}
|
||||
}
|
||||
|
||||
if($page === null) {
|
||||
$mailpoet_page_id = Pages::createMailPoetPage();
|
||||
Setting::setValue('subscription.page', $mailpoet_page_id);
|
||||
}
|
||||
}
|
||||
|
||||
private function createDefaultSettings() {
|
||||
$current_user = wp_get_current_user();
|
||||
|
||||
// user name
|
||||
$user_name = '';
|
||||
if($current_user->user_firstname) {
|
||||
$user_name = $current_user->user_firstname;
|
||||
}
|
||||
if($current_user->user_lastname) {
|
||||
if($user_name) {
|
||||
$user_name .= ' '.$current_user->user_lastname;
|
||||
}
|
||||
}
|
||||
if(!$user_name) {
|
||||
$user_name = $current_user->display_name;
|
||||
}
|
||||
|
||||
// default from name & address
|
||||
Setting::setValue('sender', array(
|
||||
'name' => $user_name,
|
||||
'address' => $current_user->user_email
|
||||
));
|
||||
|
||||
// enable signup confirmation by default
|
||||
Setting::setValue('signup_confirmation.enabled', true);
|
||||
}
|
||||
|
||||
private function createDefaultSegments() {
|
||||
@ -127,6 +182,8 @@ class Populator {
|
||||
return array(
|
||||
(new FranksRoastHouseTemplate(Env::$assets_url))->get(),
|
||||
(new BlankTemplate(Env::$assets_url))->get(),
|
||||
(new WelcomeTemplate(Env::$assets_url))->get(),
|
||||
(new PostNotificationsBlankTemplate(Env::$assets_url))->get(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,6 @@ class BlankTemplate {
|
||||
|
||||
function __construct($assets_url) {
|
||||
$this->assets_url = $assets_url;
|
||||
$this->template_image_url = $this->assets_url . '/img/sample_template';
|
||||
$this->social_icon_url = $this->assets_url . '/img/newsletter_editor/social-icons';
|
||||
}
|
||||
|
||||
function get() {
|
||||
@ -181,7 +179,7 @@ class BlankTemplate {
|
||||
),
|
||||
"h1" => array(
|
||||
"fontColor" => "#111111",
|
||||
"fontFamily" => "Arial Black",
|
||||
"fontFamily" => "Arial",
|
||||
"fontSize" => "24px"
|
||||
),
|
||||
"h2" => array(
|
||||
|
File diff suppressed because one or more lines are too long
295
lib/Config/PopulatorData/Templates/WelcomeTemplate.php
Normal file
295
lib/Config/PopulatorData/Templates/WelcomeTemplate.php
Normal file
File diff suppressed because one or more lines are too long
@ -7,15 +7,20 @@ use MailPoet\Util\Helpers;
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class PublicAPI {
|
||||
public $api;
|
||||
public $section;
|
||||
public $action;
|
||||
public $request_payload;
|
||||
|
||||
function __construct() {
|
||||
# http://example.com/?mailpoet-api§ion=&action=&payload=
|
||||
# http://example.com/?mailpoet-api§ion=&action=&request_payload=
|
||||
$this->api = isset($_GET['mailpoet-api']) ? true : false;
|
||||
$this->section = isset($_GET['section']) ? $_GET['section'] : false;
|
||||
$this->action = isset($_GET['action']) ?
|
||||
Helpers::underscoreToCamelCase($_GET['action']) :
|
||||
false;
|
||||
$this->payload = isset($_GET['payload']) ?
|
||||
json_decode(urldecode($_GET['payload']), true) :
|
||||
$this->request_payload = isset($_GET['request_payload']) ?
|
||||
json_decode(urldecode($_GET['request_payload']), true) :
|
||||
false;
|
||||
}
|
||||
|
||||
@ -25,8 +30,11 @@ class PublicAPI {
|
||||
}
|
||||
|
||||
function queue() {
|
||||
$queue = new Daemon($this->payload);
|
||||
$this->_checkAndCallMethod($queue, $this->action);
|
||||
try {
|
||||
$queue = new Daemon($this->request_payload);
|
||||
$this->_checkAndCallMethod($queue, $this->action);
|
||||
} catch(\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
private function _checkAndCallMethod($class, $method, $terminate = false) {
|
||||
|
121
lib/Config/Shortcodes.php
Normal file
121
lib/Config/Shortcodes.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
use \MailPoet\Models\Newsletter;
|
||||
use \MailPoet\Models\Subscriber;
|
||||
use \MailPoet\Models\SubscriberSegment;
|
||||
|
||||
class Shortcodes {
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
function init() {
|
||||
// form widget shortcode
|
||||
add_shortcode('mailpoet_form', array($this, 'formWidget'));
|
||||
add_shortcode('wysija_form', array($this, 'formWidget'));
|
||||
|
||||
// subscribers count shortcode
|
||||
add_shortcode('mailpoet_subscribers_count', array(
|
||||
$this, 'getSubscribersCount'
|
||||
));
|
||||
add_shortcode('wysija_subscribers_count', array(
|
||||
$this, 'getSubscribersCount'
|
||||
));
|
||||
|
||||
// archives page
|
||||
add_shortcode('mailpoet_archive', array(
|
||||
$this, 'getArchive'
|
||||
));
|
||||
|
||||
add_filter('mailpoet_archive_date', array(
|
||||
$this, 'renderArchiveDate'
|
||||
), 2);
|
||||
add_filter('mailpoet_archive_subject', array(
|
||||
$this, 'renderArchiveSubject'
|
||||
), 2);
|
||||
}
|
||||
|
||||
function formWidget($params = array()) {
|
||||
// IMPORTANT: fixes conflict with MagicMember
|
||||
remove_shortcode('user_list');
|
||||
|
||||
if(isset($params['id']) && (int)$params['id'] > 0) {
|
||||
$form_widget = new \MailPoet\Form\Widget();
|
||||
return $form_widget->widget(array(
|
||||
'form' => (int)$params['id'],
|
||||
'form_type' => 'shortcode'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
function getSubscribersCount($params) {
|
||||
if(!empty($params['segments'])) {
|
||||
$segment_ids = array_map(function($segment_id) {
|
||||
return (int)trim($segment_id);
|
||||
}, explode(',', $params['segments']));
|
||||
}
|
||||
|
||||
if(empty($segment_ids)) {
|
||||
return Subscriber::filter('subscribed')->count();
|
||||
} else {
|
||||
return SubscriberSegment::whereIn('segment_id', $segment_ids)
|
||||
->select('subscriber_id')->distinct()
|
||||
->filter('subscribed')
|
||||
->findResultSet()->count();
|
||||
}
|
||||
}
|
||||
|
||||
function getArchive($params) {
|
||||
if(!empty($params['segments'])) {
|
||||
$segment_ids = array_map(function($segment_id) {
|
||||
return (int)trim($segment_id);
|
||||
}, explode(',', $params['segments']));
|
||||
}
|
||||
|
||||
$newsletters = array();
|
||||
$html = '';
|
||||
|
||||
// TODO: needs more advanced newsletters in order to finish
|
||||
$newsletters = Newsletter::limit(10)->orderByDesc('created_at')->findMany();
|
||||
|
||||
if(empty($newsletters)) {
|
||||
return apply_filters(
|
||||
'mailpoet_archive_no_newsletters',
|
||||
__('Oops! There are no newsletters to display.')
|
||||
);
|
||||
} else {
|
||||
$title = apply_filters('mailpoet_archive_title', '');
|
||||
if(!empty($title)) {
|
||||
$html .= '<h3 class="mailpoet_archive_title">'.$title.'</h3>';
|
||||
}
|
||||
|
||||
$html .= '<ul class="mailpoet_archive">';
|
||||
foreach($newsletters as $newsletter) {
|
||||
$html .= '<li>'.
|
||||
'<span class="mailpoet_archive_date">'.
|
||||
apply_filters('mailpoet_archive_date', $newsletter).
|
||||
'</span>
|
||||
<span class="mailpoet_archive_subject">'.
|
||||
apply_filters('mailpoet_archive_subject', $newsletter).
|
||||
'</span>
|
||||
</li>';
|
||||
}
|
||||
$html .= '</ul>';
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
function renderArchiveDate($newsletter) {
|
||||
return date_i18n(
|
||||
get_option('date_format'),
|
||||
strtotime($newsletter->created_at)
|
||||
);
|
||||
}
|
||||
|
||||
function renderArchiveSubject($newsletter) {
|
||||
return '<a href="TODO" target="_blank" title="'
|
||||
.esc_attr(__('Preview in new tab')).'">'
|
||||
.esc_attr($newsletter->subject).
|
||||
'</a>';
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
use \MailPoet\Models\Subscriber;
|
||||
use \MailPoet\Util\Security;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
@ -22,18 +21,6 @@ class Widget {
|
||||
|
||||
function registerWidget() {
|
||||
register_widget('\MailPoet\Form\Widget');
|
||||
|
||||
// subscribers count shortcode
|
||||
add_shortcode('mailpoet_subscribers_count', array(
|
||||
$this, 'getSubscribersCount'
|
||||
));
|
||||
add_shortcode('wysija_subscribers_count', array(
|
||||
$this, 'getSubscribersCount'
|
||||
));
|
||||
}
|
||||
|
||||
function getSubscribersCount($params) {
|
||||
return Subscriber::filter('subscribed')->count();
|
||||
}
|
||||
|
||||
function setupDependencies() {
|
||||
|
@ -10,86 +10,99 @@ require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Daemon {
|
||||
function __construct($payload = array()) {
|
||||
public $daemon;
|
||||
public $request_payload;
|
||||
public $refreshed_token;
|
||||
public $timer;
|
||||
|
||||
function __construct($request_payload = array()) {
|
||||
set_time_limit(0);
|
||||
ignore_user_abort();
|
||||
list ($this->daemon, $this->daemonData) = $this->getDaemon();
|
||||
$this->refreshedToken = $this->refreshToken();
|
||||
$this->payload = $payload;
|
||||
$this->daemon = $this->getDaemon();
|
||||
$this->refreshed_token = $this->refreshToken();
|
||||
$this->request_payload = $request_payload;
|
||||
$this->timer = microtime(true);
|
||||
}
|
||||
|
||||
function start() {
|
||||
if(!isset($this->payload['session'])) {
|
||||
$this->abortWithError('missing session ID');
|
||||
if(!isset($this->request_payload['session'])) {
|
||||
$this->abortWithError(__('Missing session ID.'));
|
||||
}
|
||||
$this->manageSession('start');
|
||||
$daemon = $this->daemon;
|
||||
$daemonData = $this->daemonData;
|
||||
if(!$daemon) {
|
||||
$daemon = Setting::create();
|
||||
$daemon->name = 'cron_daemon';
|
||||
$daemonData = array(
|
||||
'status' => null,
|
||||
'counter' => 0
|
||||
$this->saveDaemon(
|
||||
array(
|
||||
'status' => 'starting',
|
||||
'counter' => 0
|
||||
)
|
||||
);
|
||||
$daemon->value = json_encode($daemonData);
|
||||
$daemon->save();
|
||||
}
|
||||
if($daemonData['status'] !== 'started') {
|
||||
$_SESSION['cron_daemon'] = 'started';
|
||||
$daemonData['status'] = 'started';
|
||||
$daemonData['token'] = $this->refreshedToken;
|
||||
$_SESSION['cron_daemon'] = array('result' => true);
|
||||
$this->manageSession('end');
|
||||
$daemon->value = json_encode($daemonData);
|
||||
$daemon->save();
|
||||
$this->callSelf();
|
||||
} else {
|
||||
if($daemon['status'] === 'started') {
|
||||
$_SESSION['cron_daemon'] = array(
|
||||
'result' => false,
|
||||
'error' => 'already started'
|
||||
'errors' => array(__('Daemon already running.'))
|
||||
);
|
||||
}
|
||||
if($daemon['status'] === 'starting') {
|
||||
$_SESSION['cron_daemon'] = 'started';
|
||||
$_SESSION['cron_daemon'] = array('result' => true);
|
||||
$this->manageSession('end');
|
||||
$daemon['status'] = 'started';
|
||||
$daemon['token'] = $this->refreshed_token;
|
||||
$this->saveDaemon($daemon);
|
||||
$this->callSelf();
|
||||
}
|
||||
$this->manageSession('end');
|
||||
}
|
||||
|
||||
function run() {
|
||||
if(!$this->daemon || $this->daemonData['status'] !== 'started') {
|
||||
$this->abortWithError('not running');
|
||||
$allowed_statuses = array(
|
||||
'stopping',
|
||||
'starting',
|
||||
'started'
|
||||
);
|
||||
if(!$this->daemon || !in_array($this->daemon['status'], $allowed_statuses)) {
|
||||
$this->abortWithError(__('Invalid daemon status.'));
|
||||
}
|
||||
if(!isset($this->payload['token']) ||
|
||||
$this->payload['token'] !== $this->daemonData['token']
|
||||
if(!isset($this->request_payload['token']) ||
|
||||
$this->request_payload['token'] !== $this->daemon['token']
|
||||
) {
|
||||
$this->abortWithError('invalid token');
|
||||
$this->abortWithError('Invalid token.');
|
||||
}
|
||||
|
||||
try {
|
||||
$sendingQueue = new SendingQueue($this->timer);
|
||||
$sendingQueue->process();
|
||||
$sending_queue = new SendingQueue($this->timer);
|
||||
$sending_queue->process();
|
||||
} catch(Exception $e) {
|
||||
}
|
||||
|
||||
$elapsedTime = microtime(true) - $this->timer;
|
||||
if($elapsedTime < 30) {
|
||||
sleep(30 - $elapsedTime);
|
||||
$elapsed_time = microtime(true) - $this->timer;
|
||||
if($elapsed_time < 30) {
|
||||
sleep(30 - $elapsed_time);
|
||||
}
|
||||
// after each execution, read daemon in case its status was modified
|
||||
$daemon = $this->getDaemon();
|
||||
|
||||
// after each execution, read daemon in case it's status was modified
|
||||
list($daemon, $daemonData) = $this->getDaemon();
|
||||
$daemonData['counter']++;
|
||||
$daemonData['token'] = $this->refreshedToken;
|
||||
$daemon->value = json_encode($daemonData);
|
||||
$daemon->save();
|
||||
if($daemonData['status'] === 'strated') $this->callSelf();
|
||||
if($daemon['status'] === 'stopping') $daemon['status'] = 'stopped';
|
||||
if($daemon['status'] === 'starting') $daemon['status'] = 'started';
|
||||
|
||||
$daemon['token'] = $this->refreshed_token;
|
||||
$daemon['counter']++;
|
||||
|
||||
$this->saveDaemon($daemon);
|
||||
|
||||
if($daemon['status'] === 'started') $this->callSelf();
|
||||
}
|
||||
|
||||
function getDaemon() {
|
||||
$daemon = Setting::where('name', 'cron_daemon')
|
||||
->findOne();
|
||||
return array(
|
||||
($daemon) ? $daemon : null,
|
||||
($daemon) ? json_decode($daemon->value, true) : null
|
||||
return Setting::getValue('cron_daemon');
|
||||
}
|
||||
|
||||
function saveDaemon($daemon_data) {
|
||||
$daemon_data['updated_at'] = time();
|
||||
|
||||
return Setting::setValue(
|
||||
'cron_daemon',
|
||||
$daemon_data
|
||||
);
|
||||
}
|
||||
|
||||
@ -99,24 +112,23 @@ class Daemon {
|
||||
|
||||
function manageSession($action) {
|
||||
switch($action) {
|
||||
case 'start':
|
||||
if(session_id()) {
|
||||
session_write_close();
|
||||
}
|
||||
session_id($this->payload['session']);
|
||||
session_start();
|
||||
break;
|
||||
case 'end':
|
||||
case 'start':
|
||||
if(session_id()) {
|
||||
session_write_close();
|
||||
break;
|
||||
}
|
||||
session_id($this->request_payload['session']);
|
||||
session_start();
|
||||
break;
|
||||
case 'end':
|
||||
session_write_close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function callSelf() {
|
||||
$payload = json_encode(array('token' => $this->refreshedToken));
|
||||
Supervisor::getRemoteUrl(
|
||||
'/?mailpoet-api§ion=queue&action=run&payload=' . urlencode($payload)
|
||||
|
||||
$payload = json_encode(array('token' => $this->refreshed_token));
|
||||
Supervisor::accessRemoteUrl(
|
||||
'/?mailpoet-api§ion=queue&action=run&request_payload=' . urlencode($payload)
|
||||
);
|
||||
exit;
|
||||
}
|
||||
@ -125,7 +137,7 @@ class Daemon {
|
||||
wp_send_json(
|
||||
array(
|
||||
'result' => false,
|
||||
'error' => $error
|
||||
'errors' => array($error)
|
||||
));
|
||||
exit;
|
||||
}
|
||||
|
@ -1,38 +1,48 @@
|
||||
<?php
|
||||
namespace MailPoet\Cron;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use MailPoet\Config\Env;
|
||||
use MailPoet\Models\Setting;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Supervisor {
|
||||
function __construct($forceStart = false) {
|
||||
$this->forceStart = $forceStart;
|
||||
public $daemon;
|
||||
|
||||
function __construct($force_start = false) {
|
||||
$this->force_start = $force_start;
|
||||
if(!Env::isPluginActivated()) {
|
||||
throw new \Exception('Database has not been configured.');
|
||||
throw new \Exception(__('MailPoet is not activated.'));
|
||||
}
|
||||
list ($this->daemon, $this->daemonData) = $this->getDaemon();
|
||||
$this->daemon = $this->getDaemon();
|
||||
}
|
||||
|
||||
function checkDaemon() {
|
||||
if(!$this->daemon) {
|
||||
return $this->startDaemon();
|
||||
}
|
||||
if(!$this->forceStart && $this->daemonData['status'] === 'stopped') {
|
||||
return;
|
||||
if(
|
||||
!$this->force_start
|
||||
&& isset($this->daemon['status'])
|
||||
&& in_array($this->daemon['status'], array('stopped', 'stopping'))
|
||||
) {
|
||||
return $this->daemon['status'];
|
||||
}
|
||||
$currentTime = Carbon::now('UTC');
|
||||
$lastUpdateTime = Carbon::createFromFormat(
|
||||
'Y-m-d H:i:s',
|
||||
$this->daemon->updated_at, 'UTC'
|
||||
);
|
||||
$timeSinceLastStart = $currentTime->diffInSeconds($lastUpdateTime);
|
||||
if($timeSinceLastStart < 40) return;
|
||||
$this->daemonData['status'] = null;
|
||||
$this->daemon->value = json_encode($this->daemonData);
|
||||
$this->daemon->save();
|
||||
|
||||
$elapsed_time = time() - (int)$this->daemon['updated_at'];
|
||||
|
||||
if($elapsed_time < 40) {
|
||||
if(!$this->force_start) {
|
||||
return;
|
||||
}
|
||||
if($this->daemon['status'] === 'stopping' ||
|
||||
$this->daemon['status'] === 'starting'
|
||||
) {
|
||||
return $this->daemon['status'];
|
||||
}
|
||||
}
|
||||
$this->daemon['status'] = 'starting';
|
||||
$this->saveDaemon($this->daemon);
|
||||
return $this->startDaemon();
|
||||
}
|
||||
|
||||
@ -41,9 +51,10 @@ class Supervisor {
|
||||
$sessionId = session_id();
|
||||
session_write_close();
|
||||
$_SESSION['cron_daemon'] = null;
|
||||
$payload = json_encode(array('session' => $sessionId));
|
||||
self::getRemoteUrl(
|
||||
'/?mailpoet-api§ion=queue&action=start&payload=' . urlencode($payload)
|
||||
$requestPayload = json_encode(array('session' => $sessionId));
|
||||
self::accessRemoteUrl(
|
||||
'/?mailpoet-api§ion=queue&action=start&request_payload=' .
|
||||
urlencode($requestPayload)
|
||||
);
|
||||
session_start();
|
||||
$daemonStatus = $_SESSION['cron_daemon'];
|
||||
@ -53,19 +64,20 @@ class Supervisor {
|
||||
}
|
||||
|
||||
function getDaemon() {
|
||||
$daemon = Setting::where('name', 'cron_daemon')
|
||||
->findOne();
|
||||
$daemonData = ($daemon) ? json_decode($daemon->value, true) : false;
|
||||
return array(
|
||||
$daemon,
|
||||
$daemonData
|
||||
return Setting::getValue('cron_daemon');
|
||||
}
|
||||
|
||||
function saveDaemon($daemon_data) {
|
||||
return Setting::setValue(
|
||||
'cron_daemon',
|
||||
$daemon_data
|
||||
);
|
||||
}
|
||||
|
||||
static function getRemoteUrl($url) {
|
||||
static function accessRemoteUrl($url) {
|
||||
$args = array(
|
||||
'timeout' => 1,
|
||||
'user-agent' => 'MailPoet (www.mailpoet.com)'
|
||||
'user-agent' => 'MailPoet (www.mailpoet.com) Cron'
|
||||
);
|
||||
wp_remote_get(
|
||||
self::getSiteUrl() . $url,
|
||||
@ -74,11 +86,19 @@ class Supervisor {
|
||||
}
|
||||
|
||||
static function getSiteUrl() {
|
||||
if(preg_match('!:\d+/!', site_url())) return site_url();
|
||||
preg_match('!http://(?P<host>.*?):(?P<port>\d+)!', site_url(), $server);
|
||||
// additional check for some sites running on a virtual machine or behind
|
||||
// proxy where there could be different ports (e.g., host:8080 => guest:80)
|
||||
|
||||
// if the site URL does not contain a port, return the URL
|
||||
if(!preg_match('!^https?://.*?:\d+!', site_url())) return site_url();
|
||||
preg_match('!://(?P<host>.*?):(?P<port>\d+)!', site_url(), $server);
|
||||
// connect to the URL with port
|
||||
$fp = @fsockopen($server['host'], $server['port'], $errno, $errstr, 1);
|
||||
return ($fp) ?
|
||||
site_url() :
|
||||
preg_replace('/(?=:\d+):\d+/', '$1', site_url());
|
||||
if($fp) return site_url();
|
||||
// connect to the URL without port
|
||||
$fp = @fsockopen($server['host'], $server['port'], $errno, $errstr, 1);
|
||||
if($fp) return preg_replace('!(?=:\d+):\d+!', '$1', site_url());
|
||||
// throw an error if all connections fail
|
||||
throw new \Exception(__('Site URL is unreachable.'));
|
||||
}
|
||||
}
|
@ -1,114 +1,134 @@
|
||||
<?php
|
||||
namespace MailPoet\Cron\Workers;
|
||||
|
||||
use MailPoet\Mailer\Mailer;
|
||||
use MailPoet\Models\Newsletter;
|
||||
use MailPoet\Models\NewsletterStatistics;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Newsletter\Renderer\Renderer;
|
||||
use MailPoet\Router\Mailer;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SendingQueue {
|
||||
public $timer;
|
||||
|
||||
function __construct($timer = false) {
|
||||
$this->timer = ($timer) ? $timer : microtime(true);
|
||||
}
|
||||
|
||||
function process() {
|
||||
$queues =
|
||||
\MailPoet\Models\SendingQueue::orderByDesc('priority')
|
||||
->whereNull('deleted_at')
|
||||
->whereNull('status')
|
||||
->findResultSet();
|
||||
foreach($queues as $queue) {
|
||||
$newsletter = Newsletter::findOne($queue->newsletter_id);
|
||||
// TODO: implement mailer sending frequency limits
|
||||
foreach($this->getQueues() as $queue) {
|
||||
$newsletter = Newsletter::findOne($queue->newsletter_id)
|
||||
->asArray();
|
||||
if(!$newsletter) {
|
||||
continue;
|
||||
};
|
||||
$newsletter = $newsletter->asArray();
|
||||
$mailer = new Mailer($httpRequest = false);
|
||||
if(!empty($newsletter['sender_address']) &&
|
||||
!empty($newsletter['sender_name'])
|
||||
) {
|
||||
$mailer->fromName = $newsletter['sender_name'];
|
||||
$mailer->fromEmail = $newsletter['sender_address'];
|
||||
$mailer->fromNameEmail = sprintf(
|
||||
'%s <%s>',
|
||||
$mailer->fromName,
|
||||
$mailer->fromEmail
|
||||
);
|
||||
}
|
||||
if(!empty($newsletter['reply_to_address']) &&
|
||||
!empty($newsletter['reply_to_name'])
|
||||
) {
|
||||
$mailer->replyToName = $newsletter['reply_to_name'];
|
||||
$mailer->replyToEmail = $newsletter['reply_to_address'];
|
||||
$mailer->replyToNameEmail = sprintf(
|
||||
'%s <%s>',
|
||||
$mailer->replyToName,
|
||||
$mailer->replyToEmail
|
||||
);
|
||||
}
|
||||
$mailer->mailer = $mailer->buildMailer();
|
||||
$renderer = new Renderer(json_decode($newsletter['body'], true));
|
||||
$newsletter = array(
|
||||
'subject' => $newsletter['subject'],
|
||||
'id' => $newsletter['id'],
|
||||
'body' => array(
|
||||
'html' => $renderer->renderAll(),
|
||||
'text' => ''
|
||||
// TODO: add text body
|
||||
)
|
||||
);
|
||||
$mailer = $this->configureMailerForNewsletter($newsletter);
|
||||
$newsletter = $this->renderNewsletter($newsletter);
|
||||
$subscribers = json_decode($queue->subscribers, true);
|
||||
$subscribersToProcess = $subscribers['to_process'];
|
||||
if(!isset($subscribers['failed'])) $subscribers['failed'] = array();
|
||||
$subscribers_to_process = $subscribers['to_process'];
|
||||
if(!isset($subscribers['processed'])) $subscribers['processed'] = array();
|
||||
foreach(array_chunk($subscribersToProcess, 200) as $subscriberIds) {
|
||||
$dbSubscribers = Subscriber::whereIn('id', $subscriberIds)
|
||||
if(!isset($subscribers['failed'])) $subscribers['failed'] = array();
|
||||
foreach(array_chunk($subscribers_to_process, 200) as $subscriber_ids) {
|
||||
$db_subscribers = Subscriber::whereIn('id', $subscriber_ids)
|
||||
->findArray();
|
||||
foreach($dbSubscribers as $i => $dbSubscriber) {
|
||||
foreach($db_subscribers as $db_subscriber) {
|
||||
$this->checkExecutionTimer();
|
||||
// TODO: replace shortcodes in the newsletter
|
||||
$result = $mailer->mailer->send(
|
||||
$newsletter,
|
||||
$mailer->transformSubscriber($dbSubscriber)
|
||||
);
|
||||
$newsletterStatistics = NewsletterStatistics::create();
|
||||
$newsletterStatistics->subscriber_id = $dbSubscriber['id'];
|
||||
$newsletterStatistics->newsletter_id = $newsletter['id'];
|
||||
$newsletterStatistics->queue_id = $queue->id;
|
||||
$newsletterStatistics->save();
|
||||
$result = $this->sendNewsletter(
|
||||
$mailer,
|
||||
$this->processNewsletter($newsletter),
|
||||
$db_subscriber);
|
||||
if($result) {
|
||||
$subscribers['processed'][] = $dbSubscriber['id'];
|
||||
$this->updateStatistics($newsletter['id'], $db_subscriber['id'], $queue->id);
|
||||
$subscribers['processed'][] = $db_subscriber['id'];
|
||||
} else {
|
||||
$subscribers['failed'][] = $dbSubscriber['id'];
|
||||
$subscribers['failed'][] = $db_subscriber['id'];
|
||||
}
|
||||
$subscribers['to_process'] = array_values(
|
||||
array_diff(
|
||||
$subscribers['to_process'],
|
||||
array_merge($subscribers['processed'], $subscribers['failed'])
|
||||
)
|
||||
);
|
||||
$queue->count_processed =
|
||||
count($subscribers['processed']) + count($subscribers['failed']);
|
||||
$queue->count_to_process = count($subscribers['to_process']);
|
||||
$queue->count_failed = count($subscribers['failed']);
|
||||
$queue->count_total =
|
||||
$queue->count_processed + $queue->count_to_process;
|
||||
if(!$queue->count_to_process) {
|
||||
$queue->processed_at = date('Y-m-d H:i:s');
|
||||
$queue->status = 'completed';
|
||||
}
|
||||
$queue->subscribers = json_encode($subscribers);
|
||||
$queue->save();
|
||||
$this->updateQueue($queue, $subscribers);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processNewsletter($newsletter) {
|
||||
// TODO: replace shortcodes, etc..
|
||||
return $newsletter;
|
||||
}
|
||||
|
||||
function sendNewsletter($mailer, $newsletter, $subscriber) {
|
||||
return $mailer->mailer_instance->send(
|
||||
$newsletter,
|
||||
$mailer->transformSubscriber($subscriber)
|
||||
);
|
||||
}
|
||||
|
||||
function updateStatistics($newsletter_id, $subscriber_id, $queue_id) {
|
||||
$newsletter_statistic = NewsletterStatistics::create();
|
||||
$newsletter_statistic->subscriber_id = $newsletter_id;
|
||||
$newsletter_statistic->newsletter_id = $subscriber_id;
|
||||
$newsletter_statistic->queue_id = $queue_id;
|
||||
$newsletter_statistic->save();
|
||||
}
|
||||
|
||||
function updateQueue($queue, $subscribers) {
|
||||
$subscribers['to_process'] = array_values(
|
||||
array_diff(
|
||||
$subscribers['to_process'],
|
||||
array_merge($subscribers['processed'], $subscribers['failed'])
|
||||
)
|
||||
);
|
||||
$queue->count_processed =
|
||||
count($subscribers['processed']) + count($subscribers['failed']);
|
||||
$queue->count_to_process = count($subscribers['to_process']);
|
||||
$queue->count_failed = count($subscribers['failed']);
|
||||
$queue->count_total =
|
||||
$queue->count_processed + $queue->count_to_process;
|
||||
if(!$queue->count_to_process) {
|
||||
$queue->processed_at = date('Y-m-d H:i:s');
|
||||
$queue->status = 'completed';
|
||||
}
|
||||
$queue->subscribers = json_encode($subscribers);
|
||||
$queue->save();
|
||||
}
|
||||
|
||||
function configureMailerForNewsletter($newsletter) {
|
||||
if(!empty($newsletter['sender_address']) && !empty($newsletter['sender_name'])) {
|
||||
$sender = array(
|
||||
'name' => $newsletter['sender_name'],
|
||||
'address' => $newsletter['sender_address']
|
||||
);
|
||||
} else {
|
||||
$sender = false;
|
||||
}
|
||||
if(!empty($newsletter['reply_to_address']) && !empty($newsletter['reply_to_name'])) {
|
||||
$reply_to = array(
|
||||
'name' => $newsletter['reply_to_name'],
|
||||
'address' => $newsletter['reply_to_address']
|
||||
);
|
||||
} else {
|
||||
$reply_to = false;
|
||||
}
|
||||
$mailer = new Mailer($method = false, $sender, $reply_to);
|
||||
return $mailer;
|
||||
}
|
||||
|
||||
function checkExecutionTimer() {
|
||||
$elapsedTime = microtime(true) - $this->timer;
|
||||
if($elapsedTime >= 28) throw new \Exception('Maximum execution time reached.');
|
||||
$elapsed_time = microtime(true) - $this->timer;
|
||||
if($elapsed_time >= 30) throw new \Exception('Maximum execution time reached.');
|
||||
}
|
||||
|
||||
function getQueues() {
|
||||
return \MailPoet\Models\SendingQueue::orderByDesc('priority')
|
||||
->whereNull('deleted_at')
|
||||
->whereNull('status')
|
||||
->findResultSet();
|
||||
}
|
||||
|
||||
function renderNewsletter($newsletter) {
|
||||
$renderer = new Renderer(json_decode($newsletter['body'], true));
|
||||
// TODO: update once text rendering is implemented/enderer returns an array
|
||||
$newsletter['body'] = array('html' => $renderer->render(), 'text' => '');
|
||||
return $newsletter;
|
||||
}
|
||||
}
|
@ -13,7 +13,9 @@ abstract class Base {
|
||||
if($block['id'] === 'segments') {
|
||||
$rules['required'] = true;
|
||||
$rules['mincheck'] = 1;
|
||||
$rules['error-message'] = __('You need to select a list');
|
||||
$rules['group'] = $block['id'];
|
||||
$rules['errors-container'] = '.mailpoet_error_'.$block['id'];
|
||||
$rules['required-message'] = __('You need to select a list');
|
||||
}
|
||||
|
||||
if(!empty($block['params']['required'])) {
|
||||
@ -29,7 +31,13 @@ abstract class Base {
|
||||
}
|
||||
}
|
||||
|
||||
$validation = '';
|
||||
if(in_array($block['type'], array('radio', 'checkbox'))) {
|
||||
$rules['group'] = 'custom_field_'.$block['id'];
|
||||
$rules['errors-container'] = '.mailpoet_error_'.$block['id'];
|
||||
$rules['required-message'] = __('You need to select at least one option.');
|
||||
}
|
||||
|
||||
$validation = array();
|
||||
|
||||
if(!empty($rules)) {
|
||||
$rules = array_unique($rules);
|
||||
@ -37,10 +45,10 @@ abstract class Base {
|
||||
if(is_bool($value)) {
|
||||
$value = ($value) ? 'true' : 'false';
|
||||
}
|
||||
$validation .= 'data-parsley-'.$rule.'="'.$value.'"';
|
||||
$validation[] = 'data-parsley-'.$rule.'="'.$value.'"';
|
||||
}
|
||||
}
|
||||
return $validation;
|
||||
return join(' ', $validation);
|
||||
}
|
||||
|
||||
protected static function renderLabel($block) {
|
||||
@ -86,7 +94,11 @@ abstract class Base {
|
||||
|
||||
// return field name depending on block data
|
||||
protected static function getFieldName($block = array()) {
|
||||
return $block['id'];
|
||||
if((int)$block['id'] > 0) {
|
||||
return 'cf_'.$block['id'];
|
||||
} else {
|
||||
return $block['id'];
|
||||
}
|
||||
}
|
||||
|
||||
protected static function getFieldLabel($block = array()) {
|
||||
@ -98,6 +110,6 @@ abstract class Base {
|
||||
protected static function getFieldValue($block = array()) {
|
||||
return (isset($block['params']['value'])
|
||||
&& strlen(trim($block['params']['value'])) > 0)
|
||||
? trim($block['params']['value']) : '';
|
||||
? esc_attr(trim($block['params']['value'])) : '';
|
||||
}
|
||||
}
|
@ -9,15 +9,16 @@ class Checkbox extends Base {
|
||||
$field_name = static::getFieldName($block);
|
||||
$field_validation = static::getInputValidation($block);
|
||||
|
||||
// TODO: check if it still makes sense
|
||||
// create hidden default value
|
||||
// $html .= '<input type="hidden"name="'.$field_name.'" value="0" '.static::getInputValidation($block).'/>';
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= static::renderLabel($block);
|
||||
|
||||
foreach($block['params']['values'] as $option) {
|
||||
$options = (!empty($block['params']['values'])
|
||||
? $block['params']['values']
|
||||
: array()
|
||||
);
|
||||
|
||||
foreach($options as $option) {
|
||||
$html .= '<label class="mailpoet_checkbox_label">';
|
||||
|
||||
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
||||
@ -35,6 +36,8 @@ class Checkbox extends Base {
|
||||
$html .= '</label>';
|
||||
}
|
||||
|
||||
$html .= '<span class="mailpoet_error_'.$block['id'].'"></span>';
|
||||
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
|
@ -9,32 +9,35 @@ class Radio extends Base {
|
||||
$field_name = static::getFieldName($block);
|
||||
$field_validation = static::getInputValidation($block);
|
||||
|
||||
// TODO: check if it still makes sense
|
||||
// create hidden default value
|
||||
// $html .= '<input type="hidden"name="'.$field_name.'" value="0" '.static::getInputValidation($block).'/>';
|
||||
|
||||
$html .= '<p class="mailpoet_paragraph">';
|
||||
|
||||
$html .= static::renderLabel($block);
|
||||
|
||||
foreach($block['params']['values'] as $option) {
|
||||
$options = (!empty($block['params']['values'])
|
||||
? $block['params']['values']
|
||||
: array()
|
||||
);
|
||||
|
||||
foreach($options as $option) {
|
||||
$html .= '<label class="mailpoet_radio_label">';
|
||||
|
||||
$html .= '<input type="radio" class="mailpoet_radio" ';
|
||||
|
||||
$html .= 'name="'.$field_name.'" ';
|
||||
|
||||
$html .= 'value="'.$option['value'].'" ';
|
||||
$html .= 'value="'.esc_attr($option['value']).'" ';
|
||||
|
||||
$html .= (isset($option['is_checked']) && $option['is_checked'])
|
||||
? 'checked="checked"' : '';
|
||||
$html .= $field_validation;
|
||||
|
||||
$html .= ' /> '.$option['value'];
|
||||
$html .= ' /> '.esc_attr($option['value']);
|
||||
|
||||
$html .= '</label>';
|
||||
}
|
||||
|
||||
$html .= '<span class="mailpoet_error_'.$block['id'].'"></span>';
|
||||
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
|
@ -13,23 +13,27 @@ class Segment extends Base {
|
||||
|
||||
$html .= static::renderLabel($block);
|
||||
|
||||
if(!empty($block['params']['values'])) {
|
||||
// display values
|
||||
foreach($block['params']['values'] as $segment) {
|
||||
if(!isset($segment['id']) || !isset($segment['name'])) continue;
|
||||
$options = (!empty($block['params']['values'])
|
||||
? $block['params']['values']
|
||||
: array()
|
||||
);
|
||||
|
||||
$is_checked = (isset($segment['is_checked']) && $segment['is_checked']) ? 'checked="checked"' : '';
|
||||
foreach($options as $option) {
|
||||
if(!isset($option['id']) || !isset($option['name'])) continue;
|
||||
|
||||
$html .= '<label class="mailpoet_checkbox_label">';
|
||||
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
||||
$html .= 'name="'.$field_name.'[]" ';
|
||||
$html .= 'value="'.$segment['id'].'" '.$is_checked.' ';
|
||||
$html .= $field_validation;
|
||||
$html .= ' />'.$segment['name'];
|
||||
$html .= '</label>';
|
||||
}
|
||||
$is_checked = (isset($option['is_checked']) && $option['is_checked']) ? 'checked="checked"' : '';
|
||||
|
||||
$html .= '<label class="mailpoet_checkbox_label">';
|
||||
$html .= '<input type="checkbox" class="mailpoet_checkbox" ';
|
||||
$html .= 'name="'.$field_name.'[]" ';
|
||||
$html .= 'value="'.$option['id'].'" '.$is_checked.' ';
|
||||
$html .= $field_validation;
|
||||
$html .= ' />'.$option['name'];
|
||||
$html .= '</label>';
|
||||
}
|
||||
|
||||
$html .= '<span class="mailpoet_error_'.$block['id'].'"></span>';
|
||||
|
||||
$html .= '</p>';
|
||||
|
||||
return $html;
|
||||
|
@ -6,11 +6,11 @@ class Submit extends Base {
|
||||
static function render($block) {
|
||||
$html = '';
|
||||
|
||||
$html .= '<input class="mailpoet_submit" type="submit" ';
|
||||
$html .= '<p class="mailpoet_submit"><input type="submit" ';
|
||||
|
||||
$html .= 'value="'.static::getFieldLabel($block).'" ';
|
||||
|
||||
$html .= '/>';
|
||||
$html .= '/></p>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
@ -36,9 +36,9 @@ class Widget extends \WP_Widget {
|
||||
|
||||
return parent::__construct(
|
||||
'mailpoet_form',
|
||||
__("MailPoet Subscription Form"),
|
||||
__('MailPoet Form'),
|
||||
array(
|
||||
'title' => __("Newsletter subscription form"),
|
||||
'description' => __('Add a newsletter subscription form.')
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -194,114 +194,4 @@ class Widget extends \WP_Widget {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mailpoet shortcodes
|
||||
// form shortcode
|
||||
add_shortcode('mailpoet_form', 'mailpoet_form_shortcode');
|
||||
add_shortcode('wysija_form', 'mailpoet_form_shortcode');
|
||||
|
||||
function mailpoet_form_shortcode($params = array()) {
|
||||
// IMPORTANT: this is to make sure MagicMember won't scan our form and find [user_list] as a code they should replace.
|
||||
remove_shortcode('user_list');
|
||||
|
||||
if(isset($params['id']) && (int)$params['id'] > 0) {
|
||||
$form_widget = new \MailPoet\Form\Widget();
|
||||
return $form_widget->widget(array(
|
||||
'form' => (int)$params['id'],
|
||||
'form_type' => 'shortcode'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// set the content filter to replace the shortcode
|
||||
if(isset($_GET['mailpoet_page']) && strlen(trim($_GET['mailpoet_page'])) > 0) {
|
||||
switch($_GET['mailpoet_page']) {
|
||||
|
||||
case 'mailpoet_form_iframe':
|
||||
$id = (isset($_GET['mailpoet_form']) && (int)$_GET['mailpoet_form'] > 0) ? (int)$_GET['mailpoet_form'] : null;
|
||||
$form = Form::findOne($id);
|
||||
|
||||
if($form !== false) {
|
||||
// render form
|
||||
$output = Util\Export::get('html', $form->asArray());
|
||||
// $output = do_shortcode($output);
|
||||
print $output;
|
||||
exit;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// add_filter('wp_title', 'mailpoet_meta_page_title'));
|
||||
add_filter('the_title', 'mailpoet_page_title', 10, 2);
|
||||
add_filter('the_content', 'mailpoet_page_content', 98, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function mailpoet_page_title($title = '', $id = null) {
|
||||
// get signup confirmation page id
|
||||
$signup_confirmation = Setting::getValue('signup_confirmation');
|
||||
$page_id = $signup_confirmation['page'];
|
||||
|
||||
// check if we're on the signup confirmation page
|
||||
if((int)$page_id === (int)$id) {
|
||||
global $post;
|
||||
|
||||
// disable comments
|
||||
$post->comment_status = 'close';
|
||||
// disable password
|
||||
$post->post_password = '';
|
||||
|
||||
$subscriber = null;
|
||||
|
||||
// get subscriber key from url
|
||||
$subscriber_digest = (isset($_GET['mailpoet_key']) && strlen(trim($_GET['mailpoet_key'])) === 32) ? trim($_GET['mailpoet_key']) : null;
|
||||
|
||||
if($subscriber_digest !== null) {
|
||||
// get subscriber
|
||||
// TODO: change select() to selectOne() once it's implemented
|
||||
$subscribers = $mailpoet->subscribers()->select(array(
|
||||
'filter' => array(
|
||||
'subscriber_digest' => $subscriber_digest
|
||||
),
|
||||
'limit' => 1
|
||||
));
|
||||
|
||||
if(!empty($subscribers)) {
|
||||
$subscriber = array_shift($subscribers);
|
||||
}
|
||||
}
|
||||
|
||||
// check if we have a subscriber record
|
||||
if($subscriber === null) {
|
||||
return __('Your confirmation link expired, please subscribe again.');
|
||||
} else {
|
||||
// we have a subscriber, let's check its state
|
||||
switch($subscriber['subscriber_state']) {
|
||||
case MailPoetSubscribers::STATE_UNCONFIRMED:
|
||||
case MailPoetSubscribers::STATE_UNSUBSCRIBED:
|
||||
// set subscriber state as confirmed
|
||||
$mailpoet->subscribers()->update(array(
|
||||
'subscriber' => $subscriber['subscriber'],
|
||||
'subscriber_state' => MailPoetSubscribers::STATE_SUBSCRIBED,
|
||||
'subscriber_confirmed_at' => time()
|
||||
));
|
||||
return __("You've subscribed");
|
||||
break;
|
||||
case MailPoetSubscribers::STATE_SUBSCRIBED:
|
||||
return __("You've already subscribed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
|
||||
function mailpoet_page_content($content = '') {
|
||||
if(strpos($content, '[mailpoet_page]') !== FALSE) {
|
||||
$content = str_replace('[mailpoet_page]', '', $content);
|
||||
}
|
||||
return $content;
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\API;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class AmazonSES {
|
||||
function __construct($region, $accessKey, $secretKey, $from) {
|
||||
$this->awsAccessKey = $accessKey;
|
||||
$this->awsSecret_key = $secretKey;
|
||||
$this->awsRegion = $region;
|
||||
$this->awsEndpoint = sprintf('email.%s.amazonaws.com', $region);
|
||||
$this->awsSigningAlgorithm = 'AWS4-HMAC-SHA256';
|
||||
$this->awsService = 'ses';
|
||||
$this->awsTerminationString = 'aws4_request';
|
||||
$this->hashAlgorithm = 'sha256';
|
||||
$this->url = 'https://' . $this->awsEndpoint;
|
||||
$this->from = $from;
|
||||
$this->date = gmdate('Ymd\THis\Z');
|
||||
$this->dateWithoutTime = gmdate('Ymd');
|
||||
}
|
||||
|
||||
function send($newsletter, $subscriber) {
|
||||
$result = wp_remote_post(
|
||||
$this->url,
|
||||
$this->request($newsletter, $subscriber)
|
||||
);
|
||||
return (
|
||||
!is_wp_error($result) === true &&
|
||||
wp_remote_retrieve_response_code($result) === 200
|
||||
);
|
||||
}
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
$body = array(
|
||||
'Action' => 'SendEmail',
|
||||
'Version' => '2010-12-01',
|
||||
'Source' => $this->from,
|
||||
'Destination.ToAddresses.member.1' => $subscriber,
|
||||
'Message.Subject.Data' => $newsletter['subject'],
|
||||
'ReturnPath' => $this->from
|
||||
);
|
||||
if(!empty($newsletter['body']['html'])) {
|
||||
$body['Message.Body.Html.Data'] = $newsletter['body']['html'];
|
||||
}
|
||||
if(!empty($newsletter['body']['text'])) {
|
||||
$body['Message.Body.Text.Data'] = $newsletter['body']['text'];
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
function request($newsletter, $subscriber) {
|
||||
$body = $this->getBody($newsletter, $subscriber);
|
||||
return array(
|
||||
'timeout' => 10,
|
||||
'httpversion' => '1.1',
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Host' => $this->awsEndpoint,
|
||||
'Authorization' => $this->signRequest($body),
|
||||
'X-Amz-Date' => $this->date
|
||||
),
|
||||
'body' => urldecode(http_build_query($body))
|
||||
);
|
||||
}
|
||||
|
||||
function signRequest($body) {
|
||||
$stringToSign = $this->createStringToSign(
|
||||
$this->getCredentialScope(),
|
||||
$this->getCanonicalRequest($body)
|
||||
);
|
||||
$signature = hash_hmac($this->hashAlgorithm, $stringToSign, $this->getSigningKey());
|
||||
|
||||
return sprintf(
|
||||
'%s Credential=%s/%s, SignedHeaders=host;x-amz-date, Signature=%s',
|
||||
$this->awsSigningAlgorithm,
|
||||
$this->awsAccessKey,
|
||||
$this->getCredentialScope(),
|
||||
$signature);
|
||||
}
|
||||
|
||||
function getCredentialScope() {
|
||||
return sprintf('%s/%s/%s/%s', $this->dateWithoutTime, $this->awsRegion, $this->awsService, $this->awsTerminationString);
|
||||
}
|
||||
|
||||
function getCanonicalRequest($body) {
|
||||
return implode("\n", array(
|
||||
'POST',
|
||||
'/',
|
||||
'',
|
||||
'host:' . $this->awsEndpoint,
|
||||
'x-amz-date:' . $this->date,
|
||||
'',
|
||||
'host;x-amz-date',
|
||||
hash($this->hashAlgorithm, urldecode(http_build_query($body)))
|
||||
));
|
||||
}
|
||||
|
||||
function createStringToSign($credentialScope, $canonicalRequest) {
|
||||
return implode("\n", array(
|
||||
$this->awsSigningAlgorithm,
|
||||
$this->date,
|
||||
$credentialScope,
|
||||
hash($this->hashAlgorithm, $canonicalRequest)
|
||||
));
|
||||
}
|
||||
|
||||
function getSigningKey() {
|
||||
$dateKey = hash_hmac($this->hashAlgorithm, $this->dateWithoutTime, 'AWS4' . $this->awsSecret_key, true);
|
||||
$regionKey = hash_hmac($this->hashAlgorithm, $this->awsRegion, $dateKey, true);
|
||||
$serviceKey = hash_hmac($this->hashAlgorithm, $this->awsService, $regionKey, true);
|
||||
return hash_hmac($this->hashAlgorithm, $this->awsTerminationString, $serviceKey, true);
|
||||
}
|
||||
}
|
146
lib/Mailer/Mailer.php
Normal file
146
lib/Mailer/Mailer.php
Normal file
@ -0,0 +1,146 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer;
|
||||
|
||||
use MailPoet\Models\Setting;
|
||||
|
||||
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Mailer {
|
||||
public $mailer;
|
||||
public $sender;
|
||||
public $reply_to;
|
||||
public $mailer_instance;
|
||||
|
||||
function __construct($mailer = false, $sender = false, $reply_to = false) {
|
||||
$this->mailer = $this->getMailer($mailer);
|
||||
$this->sender = $this->getSender($sender);
|
||||
$this->reply_to = $this->getReplyTo($reply_to);
|
||||
$this->mailer_instance = $this->buildMailer();
|
||||
}
|
||||
|
||||
function send($newsletter, $subscriber) {
|
||||
$subscriber = $this->transformSubscriber($subscriber);
|
||||
return $this->mailer_instance->send($newsletter, $subscriber);
|
||||
}
|
||||
|
||||
function buildMailer() {
|
||||
switch($this->mailer['method']) {
|
||||
case 'AmazonSES':
|
||||
$mailer_instance = new $this->mailer['class'](
|
||||
$this->mailer['region'],
|
||||
$this->mailer['access_key'],
|
||||
$this->mailer['secret_key'],
|
||||
$this->sender['from_name_email']
|
||||
);
|
||||
break;
|
||||
case 'ElasticEmail':
|
||||
$mailer_instance = new $this->mailer['class'](
|
||||
$this->mailer['api_key'],
|
||||
$this->sender['from_email'],
|
||||
$this->sender['from_name']
|
||||
);
|
||||
break;
|
||||
case 'MailGun':
|
||||
$mailer_instance = new $this->mailer['class'](
|
||||
$this->mailer['domain'],
|
||||
$this->mailer['api_key'],
|
||||
$this->sender['from_name_email']
|
||||
);
|
||||
break;
|
||||
case 'MailPoet':
|
||||
$mailer_instance = new $this->mailer['class'](
|
||||
$this->mailer['mailpoet_api_key'],
|
||||
$this->sender['from_email'],
|
||||
$this->sender['from_name']
|
||||
);
|
||||
break;
|
||||
case 'Mandrill':
|
||||
$mailer_instance = new $this->mailer['class'](
|
||||
$this->mailer['api_key'],
|
||||
$this->sender['from_email'],
|
||||
$this->sender['from_name']
|
||||
);
|
||||
break;
|
||||
case 'SendGrid':
|
||||
$mailer_instance = new $this->mailer['class'](
|
||||
$this->mailer['api_key'],
|
||||
$this->sender['from_email'],
|
||||
$this->sender['from_name']
|
||||
);
|
||||
break;
|
||||
case 'WPMail':
|
||||
$mailer_instance = new $this->mailer['class'](
|
||||
$this->sender['from_email'],
|
||||
$this->sender['from_name']
|
||||
);
|
||||
break;
|
||||
case 'SMTP':
|
||||
$mailer_instance = new $this->mailer['class'](
|
||||
$this->mailer['host'],
|
||||
$this->mailer['port'],
|
||||
$this->mailer['authentication'],
|
||||
$this->mailer['login'],
|
||||
$this->mailer['password'],
|
||||
$this->mailer['encryption'],
|
||||
$this->sender['from_email'],
|
||||
$this->sender['from_name']
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new \Exception(__('Mailing method does not exist.'));
|
||||
break;
|
||||
}
|
||||
return $mailer_instance;
|
||||
}
|
||||
|
||||
function getMailer($mailer = false) {
|
||||
if(!$mailer) {
|
||||
$mailer = Setting::getValue('mta', null);
|
||||
if(!$mailer || !isset($mailer['method'])) throw new \Exception(__('Mailer is not configured.'));
|
||||
}
|
||||
$mailer['class'] = 'MailPoet\\Mailer\\Methods\\' . $mailer['method'];
|
||||
return $mailer;
|
||||
}
|
||||
|
||||
function getSender($sender = false) {
|
||||
if(!$sender) {
|
||||
$sender = Setting::getValue('sender', null);
|
||||
if(!$sender) throw new \Exception(__('Sender name and email are not configured.'));
|
||||
}
|
||||
return array(
|
||||
'from_name' => $sender['name'],
|
||||
'from_email' => $sender['address'],
|
||||
'from_name_email' => sprintf('%s <%s>', $sender['name'], $sender['address'])
|
||||
);
|
||||
}
|
||||
|
||||
function getReplyTo($reply_to = false) {
|
||||
if(!$reply_to) {
|
||||
$reply_to = Setting::getValue('reply_to', null);
|
||||
if(!$reply_to) {
|
||||
$reply_to = array(
|
||||
'name' => $this->sender['from_name'],
|
||||
'address' => $this->sender['from_email']
|
||||
);
|
||||
}
|
||||
}
|
||||
return array(
|
||||
'reply_to_name' => $reply_to['name'],
|
||||
'reply_to_email' => $reply_to['address'],
|
||||
'reply_to_name_email' => sprintf('%s <%s>', $reply_to['name'], $reply_to['address'])
|
||||
);
|
||||
}
|
||||
|
||||
function transformSubscriber($subscriber) {
|
||||
if(!is_array($subscriber)) return $subscriber;
|
||||
if(isset($subscriber['address'])) $subscriber['email'] = $subscriber['address'];
|
||||
$first_name = (isset($subscriber['first_name'])) ? $subscriber['first_name'] : '';
|
||||
$last_name = (isset($subscriber['last_name'])) ? $subscriber['last_name'] : '';
|
||||
if(!$first_name && !$last_name) return $subscriber['email'];
|
||||
$subscriber = sprintf('%s %s <%s>', $first_name, $last_name, $subscriber['email']);
|
||||
$subscriber = trim(preg_replace('!\s\s+!', ' ', $subscriber));
|
||||
return $subscriber;
|
||||
}
|
||||
}
|
155
lib/Mailer/Methods/AmazonSES.php
Normal file
155
lib/Mailer/Methods/AmazonSES.php
Normal file
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class AmazonSES {
|
||||
public $aws_access_key;
|
||||
public $aws_secret_key;
|
||||
public $aws_region;
|
||||
public $aws_endpoint;
|
||||
public $aws_signing_algorithm;
|
||||
public $aws_service;
|
||||
public $aws_termination_string;
|
||||
public $hash_algorithm;
|
||||
public $url;
|
||||
public $from;
|
||||
public $date;
|
||||
public $date_without_time;
|
||||
|
||||
function __construct($region, $access_key, $secret_key, $from) {
|
||||
$this->aws_access_key = $access_key;
|
||||
$this->aws_secret_key = $secret_key;
|
||||
$this->aws_region = $region;
|
||||
$this->aws_endpoint = sprintf('email.%s.amazonaws.com', $region);
|
||||
$this->aws_signing_algorithm = 'AWS4-HMAC-SHA256';
|
||||
$this->aws_service = 'ses';
|
||||
$this->aws_termination_string = 'aws4_request';
|
||||
$this->hash_algorithm = 'sha256';
|
||||
$this->url = 'https://' . $this->aws_endpoint;
|
||||
$this->from = $from;
|
||||
$this->date = gmdate('Ymd\THis\Z');
|
||||
$this->date_without_time = gmdate('Ymd');
|
||||
}
|
||||
|
||||
function send($newsletter, $subscriber) {
|
||||
$result = wp_remote_post(
|
||||
$this->url,
|
||||
$this->request($newsletter, $subscriber)
|
||||
);
|
||||
return (
|
||||
!is_wp_error($result) === true &&
|
||||
wp_remote_retrieve_response_code($result) === 200
|
||||
);
|
||||
}
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
$body = array(
|
||||
'Action' => 'SendEmail',
|
||||
'Version' => '2010-12-01',
|
||||
'Source' => $this->from,
|
||||
'Destination.ToAddresses.member.1' => $subscriber,
|
||||
'Message.Subject.Data' => $newsletter['subject'],
|
||||
'ReturnPath' => $this->from
|
||||
);
|
||||
if(!empty($newsletter['body']['html'])) {
|
||||
$body['Message.Body.Html.Data'] = $newsletter['body']['html'];
|
||||
}
|
||||
if(!empty($newsletter['body']['text'])) {
|
||||
$body['Message.Body.Text.Data'] = $newsletter['body']['text'];
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
function request($newsletter, $subscriber) {
|
||||
$body = $this->getBody($newsletter, $subscriber);
|
||||
return array(
|
||||
'timeout' => 10,
|
||||
'httpversion' => '1.1',
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Host' => $this->aws_endpoint,
|
||||
'Authorization' => $this->signRequest($body),
|
||||
'X-Amz-Date' => $this->date
|
||||
),
|
||||
'body' => urldecode(http_build_query($body))
|
||||
);
|
||||
}
|
||||
|
||||
function signRequest($body) {
|
||||
$string_to_sign = $this->createStringToSign(
|
||||
$this->getCredentialScope(),
|
||||
$this->getCanonicalRequest($body)
|
||||
);
|
||||
$signature = hash_hmac(
|
||||
$this->hash_algorithm,
|
||||
$string_to_sign,
|
||||
$this->getSigningKey()
|
||||
);
|
||||
|
||||
return sprintf(
|
||||
'%s Credential=%s/%s, SignedHeaders=host;x-amz-date, Signature=%s',
|
||||
$this->aws_signing_algorithm,
|
||||
$this->aws_access_key,
|
||||
$this->getCredentialScope(),
|
||||
$signature);
|
||||
}
|
||||
|
||||
function getCredentialScope() {
|
||||
return sprintf(
|
||||
'%s/%s/%s/%s',
|
||||
$this->date_without_time,
|
||||
$this->aws_region,
|
||||
$this->aws_service,
|
||||
$this->aws_termination_string);
|
||||
}
|
||||
|
||||
function getCanonicalRequest($body) {
|
||||
return implode("\n", array(
|
||||
'POST',
|
||||
'/',
|
||||
'',
|
||||
'host:' . $this->aws_endpoint,
|
||||
'x-amz-date:' . $this->date,
|
||||
'',
|
||||
'host;x-amz-date',
|
||||
hash($this->hash_algorithm, urldecode(http_build_query($body)))
|
||||
));
|
||||
}
|
||||
|
||||
function createStringToSign($credential_scope, $canonical_request) {
|
||||
return implode("\n", array(
|
||||
$this->aws_signing_algorithm,
|
||||
$this->date,
|
||||
$credential_scope,
|
||||
hash($this->hash_algorithm, $canonical_request)
|
||||
));
|
||||
}
|
||||
|
||||
function getSigningKey() {
|
||||
$date_key = hash_hmac(
|
||||
$this->hash_algorithm,
|
||||
$this->date_without_time,
|
||||
'AWS4' . $this->aws_secret_key,
|
||||
true
|
||||
);
|
||||
$region_key = hash_hmac(
|
||||
$this->hash_algorithm,
|
||||
$this->aws_region,
|
||||
$date_key,
|
||||
true
|
||||
);
|
||||
$service_key = hash_hmac(
|
||||
$this->hash_algorithm,
|
||||
$this->aws_service,
|
||||
$region_key,
|
||||
true
|
||||
);
|
||||
return hash_hmac(
|
||||
$this->hash_algorithm,
|
||||
$this->aws_termination_string,
|
||||
$service_key,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
@ -1,14 +1,18 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\API;
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class ElasticEmail {
|
||||
function __construct($apiKey, $fromEmail, $fromName) {
|
||||
$this->url = 'https://api.elasticemail.com/mailer/send';
|
||||
$this->apiKey = $apiKey;
|
||||
$this->fromEmail = $fromEmail;
|
||||
$this->fromName = $fromName;
|
||||
public $url = 'https://api.elasticemail.com/mailer/send';
|
||||
public $api_key;
|
||||
public $from_email;
|
||||
public $from_name;
|
||||
|
||||
function __construct($api_key, $from_email, $from_name) {
|
||||
$this->api_key = $api_key;
|
||||
$this->from_email = $from_email;
|
||||
$this->from_name = $from_name;
|
||||
}
|
||||
|
||||
function send($newsletter, $subscriber) {
|
||||
@ -23,9 +27,9 @@ class ElasticEmail {
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
$body = array(
|
||||
'api_key' => $this->apiKey,
|
||||
'from' => $this->fromEmail,
|
||||
'from_name' => $this->fromName,
|
||||
'api_key' => $this->api_key,
|
||||
'from' => $this->from_email,
|
||||
'from_name' => $this->from_name,
|
||||
'to' => $subscriber,
|
||||
'subject' => $newsletter['subject']
|
||||
);
|
@ -1,12 +1,16 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\API;
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class MailGun {
|
||||
function __construct($domain, $apiKey, $from) {
|
||||
public $url;
|
||||
public $api_key;
|
||||
public $from;
|
||||
|
||||
function __construct($domain, $api_key, $from) {
|
||||
$this->url = sprintf('https://api.mailgun.net/v3/%s/messages', $domain);
|
||||
$this->apiKey = $apiKey;
|
||||
$this->api_key = $api_key;
|
||||
$this->from = $from;
|
||||
}
|
||||
|
||||
@ -37,7 +41,7 @@ class MailGun {
|
||||
}
|
||||
|
||||
function auth() {
|
||||
return 'Basic ' . base64_encode('api:' . $this->apiKey);
|
||||
return 'Basic ' . base64_encode('api:' . $this->api_key);
|
||||
}
|
||||
|
||||
function request($newsletter, $subscriber) {
|
@ -1,16 +1,20 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer;
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class MailPoet {
|
||||
function __construct($apiKey, $fromEmail, $fromName) {
|
||||
$this->url = 'https://bridge.mailpoet.com/api/messages';
|
||||
$this->apiKey = $apiKey;
|
||||
$this->fromEmail = $fromEmail;
|
||||
$this->fromName = $fromName;
|
||||
public $url = 'https://bridge.mailpoet.com/api/messages';
|
||||
public $api_key;
|
||||
public $from_email;
|
||||
public $from_name;
|
||||
|
||||
function __construct($api_key, $from_email, $from_name) {
|
||||
$this->api_key = $api_key;
|
||||
$this->from_email = $from_email;
|
||||
$this->from_name = $from_name;
|
||||
}
|
||||
|
||||
|
||||
function send($newsletter, $subscriber) {
|
||||
$result = wp_remote_post(
|
||||
$this->url,
|
||||
@ -21,20 +25,20 @@ class MailPoet {
|
||||
wp_remote_retrieve_response_code($result) === 201
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function processSubscriber($subscriber) {
|
||||
preg_match('!(?P<name>.*?)\s<(?P<email>.*?)>!', $subscriber, $subscriberData);
|
||||
if(!isset($subscriberData['email'])) {
|
||||
$subscriberData = array(
|
||||
preg_match('!(?P<name>.*?)\s<(?P<email>.*?)>!', $subscriber, $subscriber_data);
|
||||
if(!isset($subscriber_data['email'])) {
|
||||
$subscriber_data = array(
|
||||
'email' => $subscriber,
|
||||
);
|
||||
}
|
||||
return array(
|
||||
'email' => $subscriberData['email'],
|
||||
'name' => (isset($subscriberData['name'])) ? $subscriberData['name'] : ''
|
||||
'email' => $subscriber_data['email'],
|
||||
'name' => (isset($subscriber_data['name'])) ? $subscriber_data['name'] : ''
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
$body = array(
|
||||
'to' => (array(
|
||||
@ -42,8 +46,8 @@ class MailPoet {
|
||||
'name' => $subscriber['name']
|
||||
)),
|
||||
'from' => (array(
|
||||
'address' => $this->fromEmail,
|
||||
'name' => $this->fromName
|
||||
'address' => $this->from_email,
|
||||
'name' => $this->from_name
|
||||
)),
|
||||
'subject' => $newsletter['subject']
|
||||
);
|
||||
@ -55,11 +59,11 @@ class MailPoet {
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
|
||||
function auth() {
|
||||
return 'Basic ' . base64_encode('api:' . $this->apiKey);
|
||||
return 'Basic ' . base64_encode('api:' . $this->api_key);
|
||||
}
|
||||
|
||||
|
||||
function request($newsletter, $subscriber) {
|
||||
$body = array($this->getBody($newsletter, $subscriber));
|
||||
return array(
|
||||
@ -70,7 +74,7 @@ class MailPoet {
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => $this->auth()
|
||||
),
|
||||
'body' => json_encode($body)
|
||||
'body' => $body
|
||||
);
|
||||
}
|
||||
}
|
@ -1,14 +1,18 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\API;
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class Mandrill {
|
||||
function __construct($apiKey, $fromEmail, $fromName) {
|
||||
$this->url = 'https://mandrillapp.com/api/1.0/messages/send.json';
|
||||
$this->apiKey = $apiKey;
|
||||
$this->fromName = $fromName;
|
||||
$this->fromEmail = $fromEmail;
|
||||
public $url = 'https://mandrillapp.com/api/1.0/messages/send.json';
|
||||
public $api_key;
|
||||
public $from_email;
|
||||
public $from_name;
|
||||
|
||||
function __construct($api_key, $from_email, $from_name) {
|
||||
$this->api_key = $api_key;
|
||||
$this->from_name = $from_name;
|
||||
$this->from_email = $from_email;
|
||||
}
|
||||
|
||||
function send($newsletter, $subscriber) {
|
||||
@ -24,24 +28,24 @@ class Mandrill {
|
||||
}
|
||||
|
||||
function processSubscriber($subscriber) {
|
||||
preg_match('!(?P<name>.*?)\s<(?P<email>.*?)>!', $subscriber, $subscriberData);
|
||||
if(!isset($subscriberData['email'])) {
|
||||
$subscriberData = array(
|
||||
preg_match('!(?P<name>.*?)\s<(?P<email>.*?)>!', $subscriber, $subscriber_data);
|
||||
if(!isset($subscriber_data['email'])) {
|
||||
$subscriber_data = array(
|
||||
'email' => $subscriber,
|
||||
);
|
||||
}
|
||||
return array(
|
||||
'email' => $subscriberData['email'],
|
||||
'name' => (isset($subscriberData['name'])) ? $subscriberData['name'] : ''
|
||||
'email' => $subscriber_data['email'],
|
||||
'name' => (isset($subscriber_data['name'])) ? $subscriber_data['name'] : ''
|
||||
);
|
||||
}
|
||||
|
||||
function getBody($newsletter, $subscriber) {
|
||||
$body = array(
|
||||
'key' => $this->apiKey,
|
||||
'key' => $this->api_key,
|
||||
'message' => array(
|
||||
'from_email' => $this->fromEmail,
|
||||
'from_name' => $this->fromName,
|
||||
'from_email' => $this->from_email,
|
||||
'from_name' => $this->from_name,
|
||||
'to' => array($subscriber),
|
||||
'subject' => $newsletter['subject']
|
||||
),
|
@ -1,19 +1,30 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer;
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SMTP {
|
||||
function __construct($host, $port, $authentication, $login = null, $password = null, $encryption,
|
||||
$fromEmail, $fromName) {
|
||||
public $host;
|
||||
public $port;
|
||||
public $authentication;
|
||||
public $login;
|
||||
public $password;
|
||||
public $encryption;
|
||||
public $from_name;
|
||||
public $from_email;
|
||||
public $mailer;
|
||||
|
||||
function __construct(
|
||||
$host, $port, $authentication, $login = null, $password = null, $encryption,
|
||||
$from_email, $from_name) {
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
$this->authentication = $authentication;
|
||||
$this->login = $login;
|
||||
$this->password = $password;
|
||||
$this->encryption = $encryption;
|
||||
$this->fromName = $fromName;
|
||||
$this->fromEmail = $fromEmail;
|
||||
$this->from_name = $from_name;
|
||||
$this->from_email = $from_email;
|
||||
$this->mailer = $this->buildMailer();
|
||||
}
|
||||
|
||||
@ -22,7 +33,6 @@ class SMTP {
|
||||
$message = $this->createMessage($newsletter, $subscriber);
|
||||
$result = $this->mailer->send($message);
|
||||
} catch(\Exception $e) {
|
||||
!d($e->getMessage());exit;
|
||||
$result = false;
|
||||
}
|
||||
return ($result === 1);
|
||||
@ -43,7 +53,7 @@ class SMTP {
|
||||
|
||||
function createMessage($newsletter, $subscriber) {
|
||||
$message = \Swift_Message::newInstance()
|
||||
->setFrom(array($this->fromEmail => $this->fromName))
|
||||
->setFrom(array($this->from_email => $this->from_name))
|
||||
->setTo($this->processSubscriber($subscriber))
|
||||
->setSubject($newsletter['subject']);
|
||||
if(!empty($newsletter['body']['html'])) {
|
||||
@ -56,15 +66,15 @@ class SMTP {
|
||||
}
|
||||
|
||||
function processSubscriber($subscriber) {
|
||||
preg_match('!(?P<name>.*?)\s<(?P<email>.*?)>!', $subscriber, $subscriberData);
|
||||
if(!isset($subscriberData['email'])) {
|
||||
$subscriberData = array(
|
||||
preg_match('!(?P<name>.*?)\s<(?P<email>.*?)>!', $subscriber, $subscriber_data);
|
||||
if(!isset($subscriber_data['email'])) {
|
||||
$subscriber_data = array(
|
||||
'email' => $subscriber,
|
||||
);
|
||||
}
|
||||
return array(
|
||||
$subscriberData['email'] =>
|
||||
(isset($subscriberData['name'])) ? $subscriberData['name'] : '',
|
||||
$subscriber_data['email'] =>
|
||||
(isset($subscriber_data['name'])) ? $subscriber_data['name'] : ''
|
||||
);
|
||||
}
|
||||
}
|
@ -1,14 +1,18 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer\API;
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SendGrid {
|
||||
function __construct($apiKey, $fromEmail, $fromName) {
|
||||
$this->url = 'https://api.sendgrid.com/api/mail.send.json';
|
||||
$this->apiKey = $apiKey;
|
||||
$this->fromEmail = $fromEmail;
|
||||
$this->fromName = $fromName;
|
||||
public $url = 'https://api.sendgrid.com/api/mail.send.json';
|
||||
public $api_key;
|
||||
public $from_email;
|
||||
public $from_name;
|
||||
|
||||
function __construct($api_key, $from_email, $from_name) {
|
||||
$this->api_key = $api_key;
|
||||
$this->from_email = $from_email;
|
||||
$this->from_name = $from_name;
|
||||
}
|
||||
|
||||
function send($newsletter, $subscriber) {
|
||||
@ -27,8 +31,8 @@ class SendGrid {
|
||||
function getBody($newsletter, $subscriber) {
|
||||
$body = array(
|
||||
'to' => $subscriber,
|
||||
'from' => $this->fromEmail,
|
||||
'fromname' => $this->fromName,
|
||||
'from' => $this->from_email,
|
||||
'from_name' => $this->from_name,
|
||||
'subject' => $newsletter['subject']
|
||||
);
|
||||
if(!empty($newsletter['body']['html'])) {
|
||||
@ -41,7 +45,7 @@ class SendGrid {
|
||||
}
|
||||
|
||||
function auth() {
|
||||
return 'Bearer ' . $this->apiKey;
|
||||
return 'Bearer ' . $this->api_key;
|
||||
}
|
||||
|
||||
function request($newsletter, $subscriber) {
|
@ -1,22 +1,22 @@
|
||||
<?php
|
||||
namespace MailPoet\Mailer;
|
||||
namespace MailPoet\Mailer\Methods;
|
||||
|
||||
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class WPMail {
|
||||
function __construct($fromEmail, $fromName) {
|
||||
$this->fromEmail = $fromEmail;
|
||||
$this->fromName = $fromName;
|
||||
add_filter('wp_mail_from', array(
|
||||
$this,
|
||||
'setFromEmail'
|
||||
));
|
||||
$this->filters = array(
|
||||
'wp_mail_from' => 'setFromEmail',
|
||||
'wp_mail_from_name' => 'setFromName',
|
||||
'wp_mail_content_type' => 'setContentType'
|
||||
);
|
||||
public $from_email;
|
||||
public $from_name;
|
||||
public $filters = array(
|
||||
'wp_mail_from' => 'setFromEmail',
|
||||
'wp_mail_from_name' => 'setFromName',
|
||||
'wp_mail_content_type' => 'setContentType'
|
||||
);
|
||||
|
||||
function __construct($from_email, $from_name) {
|
||||
$this->from_email = $from_email;
|
||||
$this->from_name = $from_name;
|
||||
}
|
||||
|
||||
function addFilters() {
|
||||
@ -38,11 +38,11 @@ class WPMail {
|
||||
}
|
||||
|
||||
function setFromEmail() {
|
||||
return $this->fromEmail;
|
||||
return $this->from_email;
|
||||
}
|
||||
|
||||
function setFromName() {
|
||||
return $this->fromName;
|
||||
return $this->from_name;
|
||||
}
|
||||
|
||||
function setContentType() {
|
||||
@ -53,7 +53,9 @@ class WPMail {
|
||||
$this->addFilters();
|
||||
$result = wp_mail(
|
||||
$subscriber, $newsletter['subject'],
|
||||
(!empty($newsletter['body']['html'])) ? $newsletter['body']['html'] : $newsletter['body']['text']
|
||||
(!empty($newsletter['body']['html'])) ?
|
||||
$newsletter['body']['html'] :
|
||||
$newsletter['body']['text']
|
||||
);
|
||||
$this->removeFilters();
|
||||
return ($result === true);
|
@ -4,7 +4,7 @@ namespace MailPoet\Models;
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class SendingQueue extends Model {
|
||||
public static $_table = MP_SENDING_QUEUE_TABLE;
|
||||
public static $_table = MP_SENDING_QUEUES_TABLE;
|
||||
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
|
@ -16,23 +16,73 @@ class Setting extends Model {
|
||||
}
|
||||
|
||||
public static function getValue($key, $default = null) {
|
||||
$setting = Setting::where('name', $key)->findOne();
|
||||
if($setting === false) {
|
||||
return $default;
|
||||
} else {
|
||||
if(is_serialized($setting->value)) {
|
||||
return unserialize($setting->value);
|
||||
$keys = explode('.', $key);
|
||||
|
||||
if(count($keys) === 1) {
|
||||
$setting = Setting::where('name', $key)->findOne();
|
||||
if($setting === false) {
|
||||
return $default;
|
||||
} else {
|
||||
return $setting->value;
|
||||
if(is_serialized($setting->value)) {
|
||||
return unserialize($setting->value);
|
||||
} else {
|
||||
return $setting->value;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$main_key = array_shift($keys);
|
||||
|
||||
$setting = static::getValue($main_key, $default);
|
||||
|
||||
if($setting !== $default) {
|
||||
for($i = 0, $count = count($keys); $i < $count; $i++) {
|
||||
if(array_key_exists($keys[$i], $setting)) {
|
||||
$setting = $setting[$keys[$i]];
|
||||
} else {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $setting;
|
||||
}
|
||||
}
|
||||
|
||||
public static function setValue($key, $value) {
|
||||
return Setting::createOrUpdate(array(
|
||||
'name' => $key,
|
||||
'value' => $value
|
||||
));
|
||||
$keys = explode('.', $key);
|
||||
|
||||
if(count($keys) === 1) {
|
||||
if(is_array($value)) {
|
||||
$value = serialize($value);
|
||||
}
|
||||
|
||||
return Setting::createOrUpdate(array(
|
||||
'name' => $key,
|
||||
'value' => $value
|
||||
));
|
||||
} else {
|
||||
$main_key = array_shift($keys);
|
||||
|
||||
$setting_value = static::getValue($main_key, array());
|
||||
$current_value = &$setting_value;
|
||||
$last_key = array_pop($keys);
|
||||
|
||||
foreach($keys as $key) {
|
||||
if(!is_array($current_value)) {
|
||||
$current_value = array();
|
||||
}
|
||||
|
||||
if(!array_key_exists($key, $current_value)) {
|
||||
$current_value = array($key => array());
|
||||
}
|
||||
$current_value =& $current_value[$key];
|
||||
}
|
||||
if(is_scalar($current_value)) {
|
||||
$current_value = array();
|
||||
}
|
||||
$current_value[$last_key] = $value;
|
||||
|
||||
return static::setValue($main_key, $setting_value);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getAll() {
|
||||
|
@ -32,6 +32,51 @@ class Subscriber extends Model {
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
function addToSegments(array $segment_ids = array()) {
|
||||
$segments = Segment::whereIn('id', $segment_ids)->findMany();
|
||||
foreach($segments as $segment) {
|
||||
$association = SubscriberSegment::create();
|
||||
$association->subscriber_id = $this->id;
|
||||
$association->segment_id = $segment->id;
|
||||
$association->save();
|
||||
}
|
||||
}
|
||||
|
||||
function sendConfirmationEmail() {
|
||||
$this->set('status', 'unconfirmed');
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
static function subscribe($subscriber_data = array(), $segment_ids = array()) {
|
||||
if(empty($subscriber_data) or empty($segment_ids)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$subscriber = static::createOrUpdate($subscriber_data);
|
||||
|
||||
if($subscriber !== false && $subscriber->id() > 0) {
|
||||
// restore deleted subscriber
|
||||
if($subscriber->deleted_at !== NULL) {
|
||||
$subscriber->setExpr('deleted_at', 'NULL');
|
||||
}
|
||||
|
||||
if((bool)Setting::getValue('signup_confirmation.enabled')) {
|
||||
if($subscriber->status !== 'subscribed') {
|
||||
$subscriber->sendConfirmationEmail();
|
||||
}
|
||||
} else {
|
||||
$subscriber->set('status', 'subscribed');
|
||||
}
|
||||
|
||||
if($subscriber->save()) {
|
||||
$subscriber->addToSegments($segment_ids);
|
||||
}
|
||||
}
|
||||
|
||||
return $subscriber;
|
||||
}
|
||||
|
||||
static function search($orm, $search = '') {
|
||||
if(strlen(trim($search) === 0)) {
|
||||
return $orm;
|
||||
@ -154,7 +199,7 @@ class Subscriber extends Model {
|
||||
$orm = $orm->selectExpr(
|
||||
'CASE WHEN ' .
|
||||
MP_CUSTOM_FIELDS_TABLE . '.id=' . $customField['id'] . ' THEN ' .
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value END as "' . $customField['name'].'"');
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value END as "' . $customField['id'].'"');
|
||||
}
|
||||
$orm = $orm
|
||||
->leftOuterJoin(
|
||||
@ -181,21 +226,82 @@ class Subscriber extends Model {
|
||||
$subscriber = false;
|
||||
|
||||
if(isset($data['id']) && (int)$data['id'] > 0) {
|
||||
$subscriber = self::findOne((int)$data['id']);
|
||||
$subscriber = static::findOne((int)$data['id']);
|
||||
unset($data['id']);
|
||||
}
|
||||
|
||||
if($subscriber === false && !empty($data['email'])) {
|
||||
$subscriber = static::where('email', $data['email'])->findOne();
|
||||
if($subscriber !== false) {
|
||||
unset($data['email']);
|
||||
}
|
||||
}
|
||||
|
||||
// custom fields
|
||||
$custom_fields = array();
|
||||
|
||||
foreach($data as $key => $value) {
|
||||
if(strpos($key, 'cf_') === 0) {
|
||||
$custom_fields[(int)substr($key, 3)] = $value;
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if($subscriber === false) {
|
||||
$subscriber = self::create();
|
||||
$subscriber = static::create();
|
||||
$subscriber->hydrate($data);
|
||||
} else {
|
||||
$subscriber->set($data);
|
||||
}
|
||||
|
||||
$subscriber->save();
|
||||
if($subscriber->save()) {
|
||||
if(!empty($custom_fields)) {
|
||||
foreach($custom_fields as $custom_field_id => $value) {
|
||||
$subscriber->setCustomField($custom_field_id, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $subscriber;
|
||||
}
|
||||
|
||||
function withCustomFields() {
|
||||
$custom_fields = CustomField::select('id')->findArray();
|
||||
if(empty($custom_fields)) return $this;
|
||||
|
||||
$custom_field_ids = Helpers::arrayColumn($custom_fields, 'id');
|
||||
$relations = SubscriberCustomField::select('custom_field_id')
|
||||
->select('value')
|
||||
->whereIn('custom_field_id', $custom_field_ids)
|
||||
->where('subscriber_id', $this->id())
|
||||
->findMany();
|
||||
foreach($relations as $relation) {
|
||||
$this->{'cf_'.$relation->custom_field_id} = $relation->value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
function getCustomField($custom_field_id, $default = null) {
|
||||
$custom_field = SubscriberCustomField::select('value')
|
||||
->where('custom_field_id', $custom_field_id)
|
||||
->where('subscriber_id', $this->id())
|
||||
->findOne();
|
||||
|
||||
if($custom_field === false) {
|
||||
return $default;
|
||||
} else {
|
||||
return $custom_field->value;
|
||||
}
|
||||
}
|
||||
|
||||
function setCustomField($custom_field_id, $value) {
|
||||
return SubscriberCustomField::createOrUpdate(array(
|
||||
'subscriber_id' => $this->id(),
|
||||
'custom_field_id' => $custom_field_id,
|
||||
'value' => $value
|
||||
));
|
||||
}
|
||||
|
||||
static function bulkMoveToList($orm, $data = array()) {
|
||||
$segment_id = (isset($data['segment_id']) ? (int)$data['segment_id'] : 0);
|
||||
$segment = Segment::findOne($segment_id);
|
||||
@ -273,8 +379,7 @@ class Subscriber extends Model {
|
||||
|
||||
if(!empty($subscribers)) {
|
||||
foreach($subscribers as $subscriber) {
|
||||
// TODO: send confirmation email
|
||||
// $subscriber->sendConfirmationEmail()
|
||||
$subscriber->sendConfirmationEmail();
|
||||
}
|
||||
|
||||
return $subscribers->count();
|
||||
|
@ -12,6 +12,49 @@ class SubscriberCustomField extends Model {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
static function createOrUpdate($data = array()) {
|
||||
$custom_field = CustomField::findOne($data['custom_field_id']);
|
||||
if($custom_field === false) {
|
||||
return false;
|
||||
} else {
|
||||
$custom_field = $custom_field->asArray();
|
||||
}
|
||||
|
||||
if($custom_field['type'] === 'date') {
|
||||
if(is_array($data['value'])) {
|
||||
$day = (
|
||||
isset($data['value']['day'])
|
||||
? (int)$data['value']['day']
|
||||
: 1
|
||||
);
|
||||
$month = (
|
||||
isset($data['value']['month'])
|
||||
? (int)$data['value']['month']
|
||||
: 1
|
||||
);
|
||||
$year = (
|
||||
isset($data['value']['year'])
|
||||
? (int)$data['value']['year']
|
||||
: 1970
|
||||
);
|
||||
$data['value'] = mktime(0, 0, 0, $month, $day, $year);
|
||||
}
|
||||
}
|
||||
|
||||
$relation = self::where('custom_field_id', $data['custom_field_id'])
|
||||
->where('subscriber_id', $data['subscriber_id'])
|
||||
->findOne();
|
||||
|
||||
if($relation === false) {
|
||||
$relation = self::create();
|
||||
$relation->hydrate($data);
|
||||
} else {
|
||||
$relation->set($data);
|
||||
}
|
||||
|
||||
return $relation->save();
|
||||
}
|
||||
|
||||
static function createMultiple($values) {
|
||||
$values = array_map('array_values', $values);
|
||||
return self::rawExecute(
|
||||
|
@ -33,6 +33,10 @@ class SubscriberSegment extends Model {
|
||||
return $orm;
|
||||
}
|
||||
|
||||
static function subscribed($orm) {
|
||||
return $orm->where('status', 'subscribed');
|
||||
}
|
||||
|
||||
static function createMultiple($segmnets, $subscribers) {
|
||||
$values = Helpers::flattenArray(
|
||||
array_map(function ($segment) use ($subscribers) {
|
||||
|
@ -1,47 +1,40 @@
|
||||
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
|
||||
use MailPoet\Newsletter\Renderer\StylesHelper;
|
||||
|
||||
class Button {
|
||||
static function render($element) {
|
||||
$stylesHelper = new StylesHelper();
|
||||
|
||||
$template = '
|
||||
<tr>
|
||||
<td class="mailpoet_col mailpoet_button mailpoet_padded" valign = "top" >
|
||||
<div>
|
||||
<table width="100%" cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td align="' . $element['styles']['block']['textAlign'] . '">
|
||||
<!--[if mso]>
|
||||
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:w="urn:schemas-microsoft-com:office:word"
|
||||
href="' . $element['url'] . '"
|
||||
style="height:' . $element['styles']['block']['lineHeight'] . ';
|
||||
width:' . $element['styles']['block']['width'] . ';
|
||||
v-text-anchor:middle;"
|
||||
arcsize="' . round($element['styles']['block']['borderRadius'] / $element['styles']['block']['lineHeight'] * 100) . '%"
|
||||
strokecolor="' . $element['styles']['block']['borderColor'] . '"
|
||||
fillcolor="' . $element['styles']['block']['backgroundColor'] . '">
|
||||
<tr>
|
||||
<td class="mailpoet_padded" valign="top">
|
||||
<div>
|
||||
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0;">
|
||||
<tr>
|
||||
<td class="mailpoet_button-container" style="padding:8px 0;text-align:' . $element['styles']['block']['textAlign'] . ';"><!--[if mso]>
|
||||
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"
|
||||
href="' . $element['url'] . '"
|
||||
style="height:' . $element['styles']['block']['lineHeight'] . ';
|
||||
width:' . $element['styles']['block']['width'] . ';
|
||||
v-text-anchor:middle;"
|
||||
arcsize="' . round($element['styles']['block']['borderRadius'] / $element['styles']['block']['lineHeight'] * 100) . '%"
|
||||
strokeweight="1px"
|
||||
strokecolor="' . $element['styles']['block']['borderColor'] . '"
|
||||
fillcolor="' . $element['styles']['block']['backgroundColor'] . '">
|
||||
<w:anchorlock/>
|
||||
<center style="color:' . $element['styles']['block']['fontColor'] . ';
|
||||
font-family:' . $element['styles']['block']['fontFamily'] . ';
|
||||
font-size:' . $element['styles']['block']['fontSize'] . ';
|
||||
font-weight:bold;">' . $element['text'] . '
|
||||
font-family:' . $element['styles']['block']['fontFamily'] . ';
|
||||
font-size:' . $element['styles']['block']['fontSize'] . ';
|
||||
font-weight:bold;">' . $element['text'] . '
|
||||
</center>
|
||||
</v:roundrect>
|
||||
<![endif]-->
|
||||
<a class="mailpoet_button"
|
||||
href="' . $element['url'] . '"
|
||||
style="display:inline-block;text-align:center;text-decoration:none;-webkit-text-size-adjust:none;mso-hide:all;' . $stylesHelper->getBlockStyles($element, array('textAlign')) . '"> ' . $element['text'] . '
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>';
|
||||
|
||||
<![endif]--><a class="mailpoet_button" href="' . $element['url'] . '" style="display:inline-block;-webkit-text-size-adjust:none;mso-hide:all;text-decoration:none!important;text-align:center;' . StylesHelper::getBlockStyles($element, $exclude = array('textAlign')) . '"> ' . $element['text'] . '
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>';
|
||||
return $template;
|
||||
}
|
||||
}
|
@ -1,23 +1,34 @@
|
||||
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
|
||||
use MailPoet\Newsletter\Renderer\StylesHelper;
|
||||
|
||||
class Divider {
|
||||
static function render($element) {
|
||||
$template = '
|
||||
<tr>
|
||||
<td class="mailpoet_col mailpoet_divider mailpoet_padded"
|
||||
style="background-color: ' . $element['styles']['block']['backgroundColor'] . '; padding: ' . $element['styles']['block']['padding'] . ' 0;"
|
||||
valign="top">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td style="border-top-width: ' . $element['styles']['block']['borderWidth'] . ';
|
||||
border-top-style: ' . $element['styles']['block']['borderStyle'] . ';
|
||||
border-top-color: ' . $element['styles']['block']['borderColor'] . ';">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>';
|
||||
|
||||
<tr>
|
||||
<td class="mailpoet_divider" valign="top" ' .
|
||||
(($element['styles']['block']['backgroundColor'] !== 'transparent') ?
|
||||
'bgColor="' . $element['styles']['block']['backgroundColor'] . '" style="background-color:' . $element['styles']['block']['backgroundColor'] . ';' :
|
||||
'style="'
|
||||
) .
|
||||
sprintf('padding: %s %spx %s %spx;',
|
||||
$element['styles']['block']['padding'],
|
||||
StylesHelper::$padding_width,
|
||||
$element['styles']['block']['padding'],
|
||||
StylesHelper::$padding_width) . '">
|
||||
<table width="100%" border="0" cellpadding="0" cellspacing="0"
|
||||
style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0;">
|
||||
<tr>
|
||||
<td class="mailpoet_divider-cell"
|
||||
style="border-top-width: ' . $element['styles']['block']['borderWidth'] . ';
|
||||
border-top-style: ' . $element['styles']['block']['borderStyle'] . ';
|
||||
border-top-color: ' . $element['styles']['block']['borderColor'] . ';">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>';
|
||||
return $template;
|
||||
}
|
||||
}
|
@ -1,30 +1,27 @@
|
||||
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
|
||||
use MailPoet\Newsletter\Renderer\StylesHelper;
|
||||
|
||||
class Footer {
|
||||
static function render($element) {
|
||||
$stylesHelper = new StylesHelper();
|
||||
|
||||
// apply link styles
|
||||
if(isset($element['styles']['link'])) {
|
||||
$element['text'] = str_replace('<a', '<a style="' . $stylesHelper->getStyles($element['styles'], 'link') . '"', $element['text']);
|
||||
$element['text'] = str_replace(
|
||||
'<a',
|
||||
'<a style="'
|
||||
. StylesHelper::getStyles($element['styles'], 'link')
|
||||
. '"', $element['text']
|
||||
);
|
||||
}
|
||||
|
||||
// apply text styles
|
||||
if(isset($element['styles']['link'])) {
|
||||
$element['text'] = str_replace('<p', '<p style="' . $stylesHelper->getStyles($element['styles'], 'text') . '"', $element['text']);
|
||||
}
|
||||
|
||||
$element['text'] = preg_replace('/\n/', '<br /><br />', $element['text']);
|
||||
$element['text'] = preg_replace('/(<\/?p>)/', '', $element['text']);
|
||||
$template = '
|
||||
<tr>
|
||||
<td class="mailpoet_col mailpoet_footer"
|
||||
style="' . $stylesHelper->getStyles($element['styles'], 'block') . '"
|
||||
valign="top">
|
||||
<div>' . $element['text'] . '</div>
|
||||
</td>
|
||||
</tr>';
|
||||
|
||||
<tr>
|
||||
<td class="mailpoet_padded_header_footer mailpoet_footer" bgcolor="' . $element['styles']['block']['backgroundColor'] . '"
|
||||
style="' . StylesHelper::getBlockStyles($element) . StylesHelper::getStyles($element['styles'], 'text') . '">
|
||||
' . $element['text'] . '
|
||||
</td>
|
||||
</tr>';
|
||||
return $template;
|
||||
}
|
||||
}
|
@ -1,30 +1,27 @@
|
||||
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
|
||||
use MailPoet\Newsletter\Renderer\StylesHelper;
|
||||
|
||||
class Header {
|
||||
static function render($element) {
|
||||
$stylesHelper = new StylesHelper();
|
||||
|
||||
// apply link styles
|
||||
if(isset($element['styles']['link'])) {
|
||||
$element['text'] = str_replace('<a', '<a style="' . $stylesHelper->getStyles($element['styles'], 'link') . '"', $element['text']);
|
||||
$element['text'] = str_replace(
|
||||
'<a',
|
||||
'<a style="'
|
||||
. StylesHelper::getStyles($element['styles'], 'link')
|
||||
. '"', $element['text']
|
||||
);
|
||||
}
|
||||
|
||||
// apply text styles
|
||||
if(isset($element['styles']['link'])) {
|
||||
$element['text'] = str_replace('<p', '<p style="' . $stylesHelper->getStyles($element['styles'], 'text') . '"', $element['text']);
|
||||
}
|
||||
|
||||
$element['text'] = preg_replace('/\n/', '<br /><br />', $element['text']);
|
||||
$element['text'] = preg_replace('/(<\/?p>)/', '', $element['text']);
|
||||
$template = '
|
||||
<tr>
|
||||
<td class="mailpoet_col mailpoet_header"
|
||||
style="' . $stylesHelper->getBlockStyles($element) . '"
|
||||
valign="top">
|
||||
<div>' . $element['text'] . '</div>
|
||||
</td>
|
||||
</tr>';
|
||||
|
||||
<tr>
|
||||
<td class="mailpoet_padded_header_footer mailpoet_header" bgcolor="' . $element['styles']['block']['backgroundColor'] . '"
|
||||
style="' . StylesHelper::getBlockStyles($element) . StylesHelper::getStyles($element['styles'], 'text') . '">
|
||||
' . $element['text'] . '
|
||||
</td>
|
||||
</tr>';
|
||||
return $template;
|
||||
}
|
||||
}
|
@ -1,24 +1,42 @@
|
||||
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
|
||||
use MailPoet\Newsletter\Renderer\Columns\ColumnsHelper;
|
||||
use MailPoet\Newsletter\Renderer\StylesHelper;
|
||||
|
||||
class Image {
|
||||
static function render($element) {
|
||||
$stylesHelper = new StylesHelper();
|
||||
|
||||
$element['width'] = (int) $element['width'];
|
||||
|
||||
static function render($element, $columnCount) {
|
||||
$element = self::getImageDimensions($element, $columnCount);
|
||||
$template = '
|
||||
<tr>
|
||||
<td class="mailpoet_col mailpoet_image ' . (($element['padded'] === true) ? "mailpoet_padded" : "") . '"
|
||||
style="' . $stylesHelper->getBlockStyles($element) . '"
|
||||
valign="top">
|
||||
<img style="top:0; left:0; height: auto; width:100%;"
|
||||
src="' . $element['src'] . '"
|
||||
width="' . (($element['padded'] === true) ? $element['width'] - (20 * 2) : $element['width']) . '">
|
||||
</td>
|
||||
</tr>';
|
||||
|
||||
<tr>
|
||||
<td class="mailpoet_image ' . $element['paddedClass'] . '" align="center" valign="top">
|
||||
<img style="max-width:' . $element['width'] . 'px;" src="' . $element['src'] . '"
|
||||
width="' . $element['width'] . '" height="' . $element['height'] . '" alt="' . $element['alt'] . '"/>
|
||||
</td>
|
||||
</tr>';
|
||||
return $template;
|
||||
}
|
||||
|
||||
static function getImageDimensions($element, $column_count) {
|
||||
$column_width = ColumnsHelper::columnWidth($column_count);
|
||||
$padded_width = StylesHelper::$padding_width * 2;
|
||||
// resize image if it's wider than the column width
|
||||
if((int) $element['width'] >= $column_width) {
|
||||
$ratio = (int) $element['width'] / $column_width;
|
||||
$element['width'] = $column_width;
|
||||
$element['height'] = ceil((int) $element['height'] / $ratio);
|
||||
}
|
||||
if($element['padded'] == "true" && $element['width'] >= $column_width) {
|
||||
// resize image if the padded option is on
|
||||
$ratio = (int) $element['width'] / ((int) $element['width'] - $padded_width);
|
||||
$element['width'] = (int) $element['width'] - $padded_width;
|
||||
$element['height'] = ceil((int) $element['height'] / $ratio);
|
||||
$element['paddedClass'] = 'mailpoet_padded';
|
||||
} else {
|
||||
$element['width'] = (int) $element['width'];
|
||||
$element['height'] = (int) $element['height'];
|
||||
$element['paddedClass'] = '';
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
}
|
@ -1,24 +1,24 @@
|
||||
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
|
||||
class Renderer {
|
||||
function render($data) {
|
||||
array_map(function ($block) use (&$blockContent, &$columns) {
|
||||
$blockContent .= $this->createElementFromBlockType($block);
|
||||
function render($data, $column_count) {
|
||||
$block_content = '';
|
||||
array_map(function ($block) use (&$block_content, &$columns, $column_count) {
|
||||
$block_content .= $this->createElementFromBlockType($block, $column_count);
|
||||
if(isset($block['blocks'])) {
|
||||
$blockContent = $this->render($block);
|
||||
$block_content = $this->render($block, $column_count);
|
||||
}
|
||||
// vertical orientation denotes column container
|
||||
if($block['type'] === 'container' && $block['orientation'] === 'vertical') {
|
||||
$columns[] = $blockContent;
|
||||
$columns[] = $block_content;
|
||||
}
|
||||
}, $data['blocks']);
|
||||
|
||||
return (isset($columns)) ? $columns : $blockContent;
|
||||
return (isset($columns)) ? $columns : $block_content;
|
||||
}
|
||||
|
||||
function createElementFromBlockType($block) {
|
||||
$blockClass = __NAMESPACE__ . '\\' . ucfirst($block['type']);
|
||||
return (class_exists($blockClass)) ? $blockClass::render($block) : '';
|
||||
function createElementFromBlockType($block, $column_count) {
|
||||
$block_class = __NAMESPACE__ . '\\' . ucfirst($block['type']);
|
||||
return (class_exists($block_class)) ? $block_class::render($block, $column_count) : '';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,26 +1,23 @@
|
||||
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
|
||||
class Social {
|
||||
static function render($element) {
|
||||
$iconsBlock = '';
|
||||
|
||||
$icons_block = '';
|
||||
if(is_array($element['icons'])) {
|
||||
foreach ($element['icons'] as $icon) {
|
||||
$iconsBlock .= '
|
||||
<a href="' . $icon['link'] . '">
|
||||
<img src="' . $icon['image'] . '" width = "32" height = "32" style="width: 32px; height: 32px;" alt="' . $icon['iconType'] . '">
|
||||
</a>
|
||||
<img src="http://mp3.mailpoet.net/spacer.gif" width = "10" height = "1" style=" width: 10px; height: 1px;">';
|
||||
foreach($element['icons'] as $index => $icon) {
|
||||
$icons_block .= '
|
||||
<a href="' . $icon['link'] . '" style="text-decoration:none!important;">
|
||||
<img src="' . $icon['image'] . '" width="' . (int) $icon['width'] . '" height="' . (int) $icon['height'] . '" style="width:' . $icon['width'] . ';height:' . $icon['width'] . ';-ms-interpolation-mode:bicubic;border:0;display:inline;outline:none;" alt="' . $icon['iconType'] . '">
|
||||
</a>';
|
||||
}
|
||||
$template = '
|
||||
<tr>
|
||||
<td class="mailpoet_padded" valign="top" align="center">
|
||||
' . $icons_block . '
|
||||
</td>
|
||||
</tr>';
|
||||
return $template;
|
||||
}
|
||||
|
||||
$template = '
|
||||
<tr>
|
||||
<td class="mailpoet_col mailpoet_social" valign="top">
|
||||
<div class="mailpoet_social-icon mailpoet_padded">' . $iconsBlock . ' </div>
|
||||
</td>
|
||||
</tr>';
|
||||
|
||||
return $template;
|
||||
}
|
||||
}
|
@ -1,23 +1,12 @@
|
||||
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
|
||||
use MailPoet\Newsletter\Renderer\StylesHelper;
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
|
||||
class Spacer {
|
||||
static function render($element) {
|
||||
|
||||
$stylesHelper = new StylesHelper();
|
||||
|
||||
// if the parent container (column) has background set and the divider element has a transparent background,
|
||||
// it will assume the newsletter background, not that of the parent container
|
||||
if($element['styles']['block']['backgroundColor'] === 'transparent') {
|
||||
unset($element['styles']['block']['backgroundColor']);
|
||||
}
|
||||
|
||||
$template = '
|
||||
<tr>
|
||||
<td class="mailpoet_col mailpoet_spacer" style="' . $stylesHelper->getBlockStyles($element) . '" valign="top"> </td>
|
||||
</tr>';
|
||||
|
||||
<tr>
|
||||
<td class="mailpoet_spacer" height="' . (int) $element['styles']['block']['height'] . '" valign="top"></td>
|
||||
</tr>';
|
||||
return $template;
|
||||
}
|
||||
}
|
@ -1,114 +1,110 @@
|
||||
<?php namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
<?php
|
||||
namespace MailPoet\Newsletter\Renderer\Blocks;
|
||||
|
||||
class Text {
|
||||
static $typeFace = array(
|
||||
'Arial' => "Arial, 'Helvetica Neue', Helvetica, sans-serif",
|
||||
'Comic Sans MS' => "'Comic Sans MS', 'Marker Felt-Thin', Arial, sans-serif",
|
||||
'Courier New' => "'Courier New', Courier, 'Lucida Sans Typewriter', 'Lucida Typewriter', monospace",
|
||||
'Georgia' => "Georgia, Times, 'Times New Roman', serif",
|
||||
'Lucida' => "'Lucida Sans Unicode', 'Lucida Grande', sans-serif",
|
||||
'Tahoma' => "Tahoma, Verdana, Segoe, sans-serif",
|
||||
'Times New Roman' => "'Times New Roman', Times, Baskerville, Georgia, serif",
|
||||
'Trebuchet MS' => "'Trebuchet MS', 'Lucida Grande', 'Lucida Sans Unicode', 'Lucida Sans', Tahoma, sans-serif",
|
||||
'Verdana' => "Verdana, Geneva, sans-serif"
|
||||
);
|
||||
|
||||
static function render($element) {
|
||||
$html = $element['text'];
|
||||
|
||||
$html = self::convertBlockquotesToTables($html);
|
||||
$html = self::addLineBreakAfterTags($html);
|
||||
$html = self::removeEmptyTags($html);
|
||||
$html = self::convertEmptyParagraphsToLineBreaks($html);
|
||||
$html = self::convertParagraphsToTables($html);
|
||||
$html = self::removeLastBreakLine($html);
|
||||
|
||||
$html = self::addLineBreakAfterTags($html);
|
||||
$html = self::styleLists($html);
|
||||
$html = self::styleHeadings($html);
|
||||
$html = self::removeLastElementBreakLine($html);
|
||||
$template = '
|
||||
<tr>
|
||||
<td class="mailpoet_col mailpoet_text mailpoet_padded" valign="top">' . $html . ' </td>
|
||||
</tr>';
|
||||
|
||||
<tr>
|
||||
<td class="mailpoet_text mailpoet_padded" valign="top" style="word-break:break-word;word-wrap:break-word;">
|
||||
' . $html . '
|
||||
</td>
|
||||
</tr>';
|
||||
return $template;
|
||||
}
|
||||
|
||||
static function removeLastBreakLine($html) {
|
||||
return preg_replace('/<br>([^<br>]*)$/s', '', $html);
|
||||
}
|
||||
|
||||
static function convertParagraphsToTables($html) {
|
||||
$html = preg_replace('/<p>(.*?)<\/p>/', '
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<span class="paragraph">
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0">
|
||||
<tr>
|
||||
<td class="mailpoet_paragraph" style="word-break:break-word;word-wrap:break-word;">
|
||||
$1
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>', $html);
|
||||
|
||||
return preg_replace('/<p(.+style=\".*?\")?>(.*?)<\/p>/', '
|
||||
<table cellpadding="0" cellspacing="0" border="0">
|
||||
<tr>
|
||||
<td $1>
|
||||
<span class="paragraph">
|
||||
<br /><br />
|
||||
</td>
|
||||
</tr>
|
||||
</table>'
|
||||
, $html);
|
||||
$html = preg_replace('/<p style=\"(.*)\">(.*?)<\/p>/', '
|
||||
<table width="100%" cellpadding="0" cellspacing="0" style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0">
|
||||
<tr>
|
||||
<td class="mailpoet_paragraph" style="word-break:break-word;word-wrap:break-word;$1">
|
||||
$2
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>', $html);
|
||||
<br /><br />
|
||||
</td>
|
||||
</tr>
|
||||
</table>'
|
||||
, $html);
|
||||
return $html;
|
||||
}
|
||||
|
||||
static function convertEmptyParagraphsToLineBreaks($html) {
|
||||
return preg_replace('/<p(?:.+style=\".*?\")?><\/p>/', '<br>', $html);
|
||||
|
||||
|
||||
static function removeLastElementBreakLine($html) {
|
||||
return preg_replace('/<br\/>([^<br\/>]*)$/s', '', $html);
|
||||
}
|
||||
|
||||
|
||||
static function addLineBreakAfterTags($html) {
|
||||
return preg_replace('/(<\/(ul|ol|h\d)>)/', '$1<br>', $html);
|
||||
return preg_replace('/(<\/(ul|ol|h\d)>)/', '$1<br />', $html);
|
||||
}
|
||||
|
||||
|
||||
static function convertBlockquotesToTables($html) {
|
||||
$template = '
|
||||
<table cellpadding="0" cellspacing="0" border="0" class="mailpoet_blockquote">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td valign="top">$1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br>';
|
||||
|
||||
return preg_replace('/<blockquote>(.*?)<\/blockquote>/s', $template, $html);
|
||||
<table width="100%" cellpadding="0" cellspacing="0" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="2" bgcolor="#565656"></td>
|
||||
<td width="10"></td>
|
||||
<td valign="top">
|
||||
<table style="border-spacing:0;mso-table-lspace:0;mso-table-rspace:0">
|
||||
<tr>
|
||||
<td class="mailpoet_blockquote">
|
||||
$1
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br/>';
|
||||
preg_match('/<blockquote>.*?<\/blockquote>/s', $html, $blockquotes);
|
||||
foreach($blockquotes as $index => $blockquote) {
|
||||
$blockquote = preg_replace('/<\/p>\n<p>/', '<br/><br/>', $blockquote);
|
||||
$blockquote = preg_replace('/<\/?p>/', '', $blockquote);
|
||||
$blockquote = preg_replace(
|
||||
'/<blockquote>(.*?)<\/blockquote>/s',
|
||||
$template,
|
||||
$blockquote
|
||||
);
|
||||
$html = preg_replace(
|
||||
'/' . preg_quote($blockquotes[$index], '/') . '/',
|
||||
$blockquote,
|
||||
$html
|
||||
);
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
static function removeEmptyTags($html) {
|
||||
$pattern = <<<'EOD'
|
||||
~
|
||||
<
|
||||
(?:
|
||||
!--[^-]*(?:-(?!->)[^-]*)*-->[^<]*(*SKIP)(*F) # skip comments
|
||||
|
|
||||
( # group 1
|
||||
(span|em|strong) # tag name in group 2
|
||||
[^"'>]* #'"# all that is not a quote or a closing angle bracket
|
||||
(?: # quoted attributes
|
||||
"[^\\"]*(?:\\.[^\\"]*)*+" [^"'>]* #'"# double quote
|
||||
|
|
||||
'[^\\']*(?:\\.[^\\']*)*+' [^"'>]* #'"# single quote
|
||||
)*+
|
||||
>
|
||||
\s*
|
||||
(?:
|
||||
<!--[^-]*(?:-(?!->)[^-]*)*+--> \s* # html comments
|
||||
|
|
||||
<(?1) \s* # recursion with the group 1
|
||||
)*+
|
||||
</\2> # closing tag
|
||||
) # end of the group 1
|
||||
)
|
||||
~sxi
|
||||
EOD;
|
||||
|
||||
return preg_replace($pattern, '', $html);
|
||||
|
||||
static function styleHeadings($html) {
|
||||
return preg_replace(
|
||||
'/<(h[1-6])(?:.+style=\"(.*)?\")?>/',
|
||||
'<$1 style="margin:0;font-style:normal;font-weight:normal;$2">',
|
||||
$html
|
||||
);
|
||||
}
|
||||
|
||||
static function styleLists($html) {
|
||||
$html = preg_replace(
|
||||
'/<(ul|ol)>/',
|
||||
'<$1 class="mailpoet_paragraph" style="padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;">',
|
||||
$html
|
||||
);
|
||||
$html = preg_replace('/<li>/', '<li class="mailpoet_paragraph">', $html);
|
||||
return $html;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user