Compare commits
31 Commits
Author | SHA1 | Date | |
---|---|---|---|
daff3d5016 | |||
f13a4dd4f3 | |||
04238f3339 | |||
bc62474f3c | |||
98005a2a6f | |||
b7fe8dc6d6 | |||
436faea591 | |||
4208b148b4 | |||
5ce5f0bf8a | |||
18518de397 | |||
68f747211a | |||
ebd26ddd98 | |||
924aa0439f | |||
3124d6a61b | |||
149d031b52 | |||
fa96c4697d | |||
d46c9d5412 | |||
9425ac1593 | |||
4e32479609 | |||
7d95b38dc4 | |||
17c83c5bd4 | |||
23bb2f111f | |||
4655b2c64c | |||
84fede11b8 | |||
f37488fc0b | |||
20e2e03982 | |||
a5d96f1534 | |||
a516eb1a95 | |||
6dd8270bec | |||
981cbd579f | |||
52a0aae10f |
67
Vagrantfile
vendored
67
Vagrantfile
vendored
@ -1,67 +0,0 @@
|
|||||||
# -*- mode: ruby -*-
|
|
||||||
# vi: set ft=ruby :
|
|
||||||
|
|
||||||
Vagrant.configure(2) do |config|
|
|
||||||
config.vm.provider "virtualbox" do |v|
|
|
||||||
v.name = "phoenix"
|
|
||||||
v.memory = "2048"
|
|
||||||
end
|
|
||||||
|
|
||||||
config.vm.define :web do |web|
|
|
||||||
web.vm.box = "ubuntu/trusty64"
|
|
||||||
web.vm.hostname = "phoenix"
|
|
||||||
web.vm.network "forwarded_port", guest: 80, host: 8080
|
|
||||||
web.vm.synced_folder(
|
|
||||||
".",
|
|
||||||
"/var/www/html/wp-content/plugins/wysija-newsletters",
|
|
||||||
create: true,
|
|
||||||
owner: "vagrant",
|
|
||||||
group: "www-data"
|
|
||||||
)
|
|
||||||
|
|
||||||
web.vm.provision "shell", inline: <<-SHELL
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y apache2 curl zip sendmail git build-essential
|
|
||||||
|
|
||||||
sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password root'
|
|
||||||
sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password root'
|
|
||||||
sudo apt-get install -y mysql-server-5.5
|
|
||||||
|
|
||||||
sudo apt-get install -y php5 libapache2-mod-php5 php5-curl php5-gd php5-mcrypt php5-readline mysql-server-5.5 php5-mysql php-apc
|
|
||||||
sudo sed -i "s/error_reporting = .*/error_reporting = E_ALL/" /etc/php5/apache2/php.ini
|
|
||||||
sudo sed -i "s/display_errors = .*/display_errors = On/" /etc/php5/apache2/php.ini
|
|
||||||
|
|
||||||
cd /var/www/html
|
|
||||||
|
|
||||||
sudo wget https://github.com/calvinlough/sqlbuddy/raw/gh-pages/sqlbuddy.zip -O /var/www/html/sqlbuddy.zip
|
|
||||||
sudo rm index.html
|
|
||||||
unzip sqlbuddy.zip
|
|
||||||
|
|
||||||
sudo curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
|
|
||||||
sudo chmod +x wp-cli.phar
|
|
||||||
sudo mv wp-cli.phar /usr/local/bin/wp
|
|
||||||
sudo wp core download --allow-root
|
|
||||||
mysql -uroot -proot -e "create database wordpress"
|
|
||||||
sudo wp core config --allow-root --dbname=wordpress --dbuser=root --dbpass=root
|
|
||||||
sudo wp core install --allow-root --url="http://localhost:8080" --title=WordPress --admin_user=admin --admin_password=password --admin_email=test@mailpoet-container.com
|
|
||||||
|
|
||||||
sudo sed -i "s/upload_max_filesize = .*/upload_max_filesize = 32M/" /etc/php5/apache2/php.ini
|
|
||||||
sudo sed -i "s/post_max_size = .*/post_max_size = 32M/" /etc/php5/apache2/php.ini
|
|
||||||
sudo chown -hR vagrant:www-data /var/www/html/
|
|
||||||
sudo a2enmod rewrite > /dev/null 2>&1
|
|
||||||
|
|
||||||
cd /var/www/html/wp-content/plugins/wysija-newsletters
|
|
||||||
|
|
||||||
curl -sS https://getcomposer.org/installer | php
|
|
||||||
|
|
||||||
sudo add-apt-repository -y ppa:chris-lea/node.js
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y nodejs
|
|
||||||
|
|
||||||
sudo sed -i "s/export APACHE_RUN_USER.*/export APACHE_RUN_USER=vagrant/" /etc/apache2/envvars
|
|
||||||
sudo chown -R vagrant:www-data /var/lock/apache2
|
|
||||||
|
|
||||||
sudo service apache2 restart
|
|
||||||
SHELL
|
|
||||||
end
|
|
||||||
end
|
|
@ -18,6 +18,38 @@
|
|||||||
height: 150px
|
height: 150px
|
||||||
margin-right: 15px
|
margin-right: 15px
|
||||||
float: left
|
float: left
|
||||||
|
overflow: hidden
|
||||||
|
position: relative
|
||||||
|
|
||||||
|
img
|
||||||
|
min-width: 150px
|
||||||
|
min-height: 150px
|
||||||
|
height: auto
|
||||||
|
width: 110%
|
||||||
|
position: relative
|
||||||
|
top: 0
|
||||||
|
left: 50%
|
||||||
|
transform: translate(-50%, 0%)
|
||||||
|
|
||||||
|
.mailpoet_overlay
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
left: 0
|
||||||
|
right: 0
|
||||||
|
bottom: 0
|
||||||
|
background-color: rgba(255, 255, 255, 0.0)
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
background-color: rgba(255, 255, 255, 0.7)
|
||||||
|
|
||||||
|
&::after
|
||||||
|
content: " "
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
left: 0
|
||||||
|
bottom: 0
|
||||||
|
right: 0
|
||||||
|
background: url(../img/preview_magnifying_glass.svg) no-repeat center center
|
||||||
|
|
||||||
.mailpoet_boxes .mailpoet_description
|
.mailpoet_boxes .mailpoet_description
|
||||||
float:left
|
float:left
|
||||||
|
12
assets/img/preview_magnifying_glass.svg
Normal file
12
assets/img/preview_magnifying_glass.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="47.002px" height="38.003px" viewBox="0 0 47.002 38.003" enable-background="new 0 0 47.002 38.003" xml:space="preserve">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" fill="#565656" d="M46.328,36.365c-1.188,1.725-3.553,2.158-5.273,0.962L25.479,26.52
|
||||||
|
c-1.104-0.763-1.674-2.007-1.631-3.257c-2.006,2.157-4.642,3.606-7.594,4.145c-3.626,0.663-7.288-0.13-10.311-2.227
|
||||||
|
c-3.024-2.098-5.054-5.253-5.714-8.887c-0.661-3.636,0.127-7.31,2.221-10.344c4.325-6.264,12.927-7.834,19.177-3.5
|
||||||
|
c5.672,3.938,7.486,11.412,4.537,17.443c1.152-0.486,2.519-0.392,3.627,0.377l15.58,10.808C47.09,32.274,47.52,34.641,46.328,36.365
|
||||||
|
z M23.235,12.09c-0.459-2.534-1.874-4.734-3.982-6.196C14.897,2.87,8.896,3.963,5.878,8.331c-3.014,4.373-1.922,10.388,2.435,13.408
|
||||||
|
c4.356,3.025,10.356,1.932,13.374-2.438C23.146,17.187,23.696,14.625,23.235,12.09z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/img/sample_template/coffee-grain.jpg
Normal file
BIN
assets/img/sample_template/coffee-grain.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 178 KiB |
BIN
assets/img/sample_template/header-v2.jpg
Normal file
BIN
assets/img/sample_template/header-v2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
BIN
assets/img/sample_template/map-v2.jpg
Normal file
BIN
assets/img/sample_template/map-v2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 130 KiB |
BIN
assets/img/sample_template/sandwich.jpg
Normal file
BIN
assets/img/sample_template/sandwich.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
@ -105,6 +105,9 @@ const item_actions = [
|
|||||||
refresh();
|
refresh();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'trash'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -79,27 +79,48 @@ define(
|
|||||||
|
|
||||||
if(custom_actions.length > 0) {
|
if(custom_actions.length > 0) {
|
||||||
item_actions = custom_actions.map(function(action, index) {
|
item_actions = custom_actions.map(function(action, index) {
|
||||||
if(action.refresh) {
|
if(action.display !== undefined) {
|
||||||
|
if(action.display(this.props.item) === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(action.name === 'trash') {
|
||||||
|
return (
|
||||||
|
<span key={ 'action-'+index } className="trash">
|
||||||
|
{(index > 0) ? ' | ' : ''}
|
||||||
|
<a
|
||||||
|
href="javascript:;"
|
||||||
|
onClick={ this.handleTrashItem.bind(
|
||||||
|
null,
|
||||||
|
this.props.item.id
|
||||||
|
) }>
|
||||||
|
Trash
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
} else if(action.refresh) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
onClick={ this.props.onRefreshItems }
|
onClick={ this.props.onRefreshItems }
|
||||||
key={ 'action-'+index } className={ action.name }>
|
key={ 'action-'+index } className={ action.name }>
|
||||||
|
{(index > 0) ? ' | ' : ''}
|
||||||
{ action.link(this.props.item) }
|
{ action.link(this.props.item) }
|
||||||
{(index < (custom_actions.length - 1)) ? ' | ' : ''}
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
} else if(action.link) {
|
} else if(action.link) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
key={ 'action-'+index } className={ action.name }>
|
key={ 'action-'+index } className={ action.name }>
|
||||||
|
{(index > 0) ? ' | ' : ''}
|
||||||
{ action.link(this.props.item) }
|
{ action.link(this.props.item) }
|
||||||
{(index < (custom_actions.length - 1)) ? ' | ' : ''}
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
key={ 'action-'+index } className={ action.name }>
|
key={ 'action-'+index } className={ action.name }>
|
||||||
|
{(index > 0) ? ' | ' : ''}
|
||||||
<a href="javascript:;" onClick={
|
<a href="javascript:;" onClick={
|
||||||
(action.onClick !== undefined)
|
(action.onClick !== undefined)
|
||||||
? action.onClick.bind(null,
|
? action.onClick.bind(null,
|
||||||
@ -108,7 +129,6 @@ define(
|
|||||||
)
|
)
|
||||||
: false
|
: false
|
||||||
}>{ action.label }</a>
|
}>{ action.label }</a>
|
||||||
{(index < (custom_actions.length - 1)) ? ' | ' : ''}
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -158,17 +178,6 @@ define(
|
|||||||
<div>
|
<div>
|
||||||
<div className="row-actions">
|
<div className="row-actions">
|
||||||
{ item_actions }
|
{ item_actions }
|
||||||
{ ' | ' }
|
|
||||||
<span className="trash">
|
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
onClick={ this.handleTrashItem.bind(
|
|
||||||
null,
|
|
||||||
this.props.item.id
|
|
||||||
) }>
|
|
||||||
Trash
|
|
||||||
</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={ this.handleToggleItem.bind(null, this.props.item.id) }
|
onClick={ this.handleToggleItem.bind(null, this.props.item.id) }
|
||||||
@ -637,7 +646,7 @@ define(
|
|||||||
// bulk actions
|
// bulk actions
|
||||||
var bulk_actions = this.props.bulk_actions || [];
|
var bulk_actions = this.props.bulk_actions || [];
|
||||||
|
|
||||||
if(this.state.group === 'trash') {
|
if(this.state.group === 'trash' && bulk_actions.length > 0) {
|
||||||
bulk_actions = [
|
bulk_actions = [
|
||||||
{
|
{
|
||||||
name: 'restore',
|
name: 'restore',
|
||||||
|
@ -6,8 +6,9 @@ define([
|
|||||||
'backbone.marionette',
|
'backbone.marionette',
|
||||||
'jquery',
|
'jquery',
|
||||||
'blob',
|
'blob',
|
||||||
'filesaver'
|
'filesaver',
|
||||||
], function(App, MailPoet, Notice, Backbone, Marionette, jQuery, Blob, FileSaver) {
|
'html2canvas'
|
||||||
|
], function(App, MailPoet, Notice, Backbone, Marionette, jQuery, Blob, FileSaver, html2canvas) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
@ -56,16 +57,26 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Module.exportTemplate = function(options) {
|
Module.getThumbnail = function(element, options) {
|
||||||
var data = _.extend(options || {}, {
|
return html2canvas(element, options || {});
|
||||||
body: App.getBody(),
|
};
|
||||||
});
|
|
||||||
var blob = new Blob(
|
|
||||||
[JSON.stringify(data)],
|
|
||||||
{ type: 'application/json;charset=utf-8' }
|
|
||||||
);
|
|
||||||
|
|
||||||
FileSaver.saveAs(blob, 'template.json');
|
Module.exportTemplate = function(options) {
|
||||||
|
var that = this;
|
||||||
|
return Module.getThumbnail(
|
||||||
|
jQuery('#mailpoet_editor_content > .mailpoet_block').get(0)
|
||||||
|
).then(function(thumbnail) {
|
||||||
|
var data = _.extend(options || {}, {
|
||||||
|
thumbnail: thumbnail.toDataURL('image/jpeg'),
|
||||||
|
body: App.getBody(),
|
||||||
|
});
|
||||||
|
var blob = new Blob(
|
||||||
|
[JSON.stringify(data)],
|
||||||
|
{ type: 'application/json;charset=utf-8' }
|
||||||
|
);
|
||||||
|
|
||||||
|
FileSaver.saveAs(blob, 'template.json');
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Module.SaveView = Marionette.LayoutView.extend({
|
Module.SaveView = Marionette.LayoutView.extend({
|
||||||
|
@ -56,7 +56,7 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
Module.getTransformedPosts = function(options) {
|
Module.getTransformedPosts = function(options) {
|
||||||
return Module._query({
|
return Module._cachedQuery({
|
||||||
action: 'getTransformedPosts',
|
action: 'getTransformedPosts',
|
||||||
options: options,
|
options: options,
|
||||||
});
|
});
|
||||||
|
@ -112,6 +112,9 @@ define(
|
|||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'trash'
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -150,6 +150,13 @@ define(
|
|||||||
this.setState({ loading: false });
|
this.setState({ loading: false });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
handleShowTemplate: function(template) {
|
||||||
|
MailPoet.Modal.popup({
|
||||||
|
title: template.name,
|
||||||
|
template: '<img src="{{ thumbnail }}" />',
|
||||||
|
data: template,
|
||||||
|
});
|
||||||
|
},
|
||||||
handleTemplateImport: function() {
|
handleTemplateImport: function() {
|
||||||
this.getTemplates();
|
this.getTemplates();
|
||||||
},
|
},
|
||||||
@ -164,11 +171,22 @@ define(
|
|||||||
Delete
|
Delete
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
), thumbnail = '';
|
||||||
|
|
||||||
|
if (typeof template.thumbnail === 'string'
|
||||||
|
&& template.thumbnail.length > 0) {
|
||||||
|
thumbnail = (
|
||||||
|
<a href="javascript:;" onClick={this.handleShowTemplate.bind(null, template)}>
|
||||||
|
<img src={ template.thumbnail } />
|
||||||
|
<div className="mailpoet_overlay"></div>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={ 'template-'+index }>
|
<li key={ 'template-'+index }>
|
||||||
<div className="mailpoet_thumbnail">
|
<div className="mailpoet_thumbnail">
|
||||||
|
{ thumbnail }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mailpoet_description">
|
<div className="mailpoet_description">
|
||||||
|
75
assets/js/src/queue.jsx
Normal file
75
assets/js/src/queue.jsx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
define(
|
||||||
|
[
|
||||||
|
'react',
|
||||||
|
'react-dom',
|
||||||
|
'mailpoet',
|
||||||
|
'classnames'
|
||||||
|
],
|
||||||
|
function (
|
||||||
|
React,
|
||||||
|
ReactDOM,
|
||||||
|
MailPoet,
|
||||||
|
classNames
|
||||||
|
) {
|
||||||
|
var QueueDaemonControl = React.createClass({
|
||||||
|
getInitialState: function () {
|
||||||
|
return (queueDaemon) ? {
|
||||||
|
status: queueDaemon.status,
|
||||||
|
timeSinceStart: queueDaemon.time_since_start,
|
||||||
|
timeSinceUpdate: queueDaemon.time_since_update,
|
||||||
|
counter: queueDaemon.counter
|
||||||
|
} : null;
|
||||||
|
},
|
||||||
|
getDaemonData: function () {
|
||||||
|
MailPoet.Ajax.post({
|
||||||
|
endpoint: 'queue',
|
||||||
|
action: 'getQueueStatus'
|
||||||
|
}).done(function (response) {
|
||||||
|
this.setState({
|
||||||
|
status: response.status,
|
||||||
|
timeSinceStart: response.time_since_start,
|
||||||
|
timeSinceUpdate: response.time_since_update,
|
||||||
|
counter: response.counter,
|
||||||
|
});
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
componentDidMount: function () {
|
||||||
|
this.getDaemonData;
|
||||||
|
setInterval(this.getDaemonData, 5000);
|
||||||
|
},
|
||||||
|
render: function () {
|
||||||
|
if (!this.state) {
|
||||||
|
return (
|
||||||
|
<div className="QueueControl">
|
||||||
|
Woops, daemon is not running ;\
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
Queue is currently <b>{this.state.status}</b>.
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
It was started
|
||||||
|
<b> {this.state.timeSinceStart} </b> and was last executed
|
||||||
|
<b> {this.state.timeSinceUpdate} </b> for a total of
|
||||||
|
<b> {this.state.counter} </b> times (once every 30 seconds, unless it was interrupted and restarted).
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let container = document.getElementById('queue_container');
|
||||||
|
if (container) {
|
||||||
|
ReactDOM.render(
|
||||||
|
<QueueDaemonControl />,
|
||||||
|
container
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
@ -121,6 +121,30 @@ const item_actions = [
|
|||||||
);
|
);
|
||||||
refresh();
|
refresh();
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
display: function(segment) {
|
||||||
|
return (segment.type !== 'wp_users');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'synchronize_segment',
|
||||||
|
label: 'Update',
|
||||||
|
className: 'update',
|
||||||
|
onClick: function(item, refresh) {
|
||||||
|
return MailPoet.Ajax.post({
|
||||||
|
endpoint: 'segments',
|
||||||
|
action: 'synchronize'
|
||||||
|
}).done(function(response) {
|
||||||
|
if(response === true) {
|
||||||
|
MailPoet.Notice.success(
|
||||||
|
('List "%$1s" has been synchronized.').replace('%$1s', item.name)
|
||||||
|
);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
display: function(segment) {
|
||||||
|
return (segment.type === 'wp_users');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -130,15 +154,16 @@ const item_actions = [
|
|||||||
<a href={ item.subscribers_url }>View subscribers</a>
|
<a href={ item.subscribers_url }>View subscribers</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'trash',
|
||||||
|
display: function(segment) {
|
||||||
|
return (segment.type !== 'wp_users');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const bulk_actions = [
|
const bulk_actions = [
|
||||||
{
|
|
||||||
name: 'trash',
|
|
||||||
label: 'Trash',
|
|
||||||
onSuccess: messages.onTrash
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const SegmentList = React.createClass({
|
const SegmentList = React.createClass({
|
||||||
@ -148,7 +173,6 @@ const SegmentList = React.createClass({
|
|||||||
'column-primary',
|
'column-primary',
|
||||||
'has-row-actions'
|
'has-row-actions'
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<td className={ rowClasses }>
|
<td className={ rowClasses }>
|
||||||
|
@ -20,6 +20,7 @@ define(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
jQuery(document).ready(function () {
|
jQuery(document).ready(function () {
|
||||||
|
jQuery('input[name="select_method"]').attr('checked', false);
|
||||||
// configure router
|
// configure router
|
||||||
router = new (Backbone.Router.extend({
|
router = new (Backbone.Router.extend({
|
||||||
routes: {
|
routes: {
|
||||||
@ -299,11 +300,11 @@ define(
|
|||||||
var test,
|
var test,
|
||||||
cleanEmail =
|
cleanEmail =
|
||||||
email
|
email
|
||||||
// left/right trim spaces, punctuation (e.g., " 'email@email.com'; ")
|
// left/right trim spaces, punctuation (e.g., " 'email@email.com'; ")
|
||||||
// right trim non-printable characters (e.g., "email@email.com<6F>")
|
// right trim non-printable characters (e.g., "email@email.com<6F>")
|
||||||
.replace(/^["';.,\s]+|[^\x20-\x7E]+$|["';.,_\s]+$/g, '')
|
.replace(/^["';.,\s]+|[^\x20-\x7E]+$|["';.,_\s]+$/g, '')
|
||||||
// remove spaces (e.g., "email @ email . com")
|
// remove spaces (e.g., "email @ email . com")
|
||||||
// remove urlencoded characters
|
// remove urlencoded characters
|
||||||
.replace(/\s+|%\d+|,+/g, '')
|
.replace(/\s+|%\d+|,+/g, '')
|
||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
|
|
||||||
@ -1000,7 +1001,6 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggleNextStepButton(condition) {
|
function toggleNextStepButton(condition) {
|
||||||
console.log(condition);
|
|
||||||
var disabled = 'button-disabled';
|
var disabled = 'button-disabled';
|
||||||
if (condition === 'on') {
|
if (condition === 'on') {
|
||||||
nextStepButton.removeClass(disabled);
|
nextStepButton.removeClass(disabled);
|
@ -103,7 +103,9 @@ const bulk_actions = [
|
|||||||
id: 'move_to_segment',
|
id: 'move_to_segment',
|
||||||
endpoint: 'segments',
|
endpoint: 'segments',
|
||||||
filter: function(segment) {
|
filter: function(segment) {
|
||||||
return !!(!segment.deleted_at);
|
return !!(
|
||||||
|
!segment.deleted_at && segment.type === 'default'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -132,7 +134,9 @@ const bulk_actions = [
|
|||||||
id: 'add_to_segment',
|
id: 'add_to_segment',
|
||||||
endpoint: 'segments',
|
endpoint: 'segments',
|
||||||
filter: function(segment) {
|
filter: function(segment) {
|
||||||
return !!(!segment.deleted_at);
|
return !!(
|
||||||
|
!segment.deleted_at && segment.type === 'default'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -159,7 +163,12 @@ const bulk_actions = [
|
|||||||
onSelect: function() {
|
onSelect: function() {
|
||||||
let field = {
|
let field = {
|
||||||
id: 'remove_from_segment',
|
id: 'remove_from_segment',
|
||||||
endpoint: 'segments'
|
endpoint: 'segments',
|
||||||
|
filter: function(segment) {
|
||||||
|
return !!(
|
||||||
|
segment.type === 'default'
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -206,6 +215,21 @@ const bulk_actions = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const item_actions = [
|
||||||
|
{
|
||||||
|
name: 'edit',
|
||||||
|
label: 'Edit',
|
||||||
|
link: function(item) {
|
||||||
|
return (
|
||||||
|
<Link to={ `/edit/${item.id}` }>Edit</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'trash'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const SubscriberList = React.createClass({
|
const SubscriberList = React.createClass({
|
||||||
renderItem: function(subscriber, actions) {
|
renderItem: function(subscriber, actions) {
|
||||||
let row_classes = classNames(
|
let row_classes = classNames(
|
||||||
@ -295,6 +319,7 @@ const SubscriberList = React.createClass({
|
|||||||
onRenderItem={ this.renderItem }
|
onRenderItem={ this.renderItem }
|
||||||
columns={ columns }
|
columns={ columns }
|
||||||
bulk_actions={ bulk_actions }
|
bulk_actions={ bulk_actions }
|
||||||
|
item_actions={ item_actions }
|
||||||
messages={ messages }
|
messages={ messages }
|
||||||
onGetItems={ this.onGetItems }
|
onGetItems={ this.onGetItems }
|
||||||
/>
|
/>
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
"tburry/pquery": "*",
|
"tburry/pquery": "*",
|
||||||
"j4mie/paris": "1.5.4",
|
"j4mie/paris": "1.5.4",
|
||||||
"swiftmailer/swiftmailer": "^5.4",
|
"swiftmailer/swiftmailer": "^5.4",
|
||||||
"phpseclib/phpseclib": "*"
|
"phpseclib/phpseclib": "*",
|
||||||
|
"mtdowling/cron-expression": "^1.0",
|
||||||
|
"nesbot/carbon": "^1.21"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"codeception/codeception": "*",
|
"codeception/codeception": "*",
|
||||||
|
@ -4,36 +4,37 @@ namespace MailPoet\Config;
|
|||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
class Env {
|
class Env {
|
||||||
public static $version;
|
static $version;
|
||||||
public static $plugin_name;
|
static $plugin_name;
|
||||||
public static $plugin_url;
|
static $plugin_url;
|
||||||
public static $file;
|
static $plugin_path;
|
||||||
public static $path;
|
static $file;
|
||||||
public static $views_path;
|
static $path;
|
||||||
public static $assets_path;
|
static $views_path;
|
||||||
public static $assets_url;
|
static $assets_path;
|
||||||
public static $temp_name;
|
static $assets_url;
|
||||||
public static $temp_path;
|
static $temp_name;
|
||||||
public static $languages_path;
|
static $temp_path;
|
||||||
public static $lib_path;
|
static $languages_path;
|
||||||
public static $plugin_prefix;
|
static $lib_path;
|
||||||
public static $db_prefix;
|
static $plugin_prefix;
|
||||||
public static $db_source_name;
|
static $db_prefix;
|
||||||
public static $db_host;
|
static $db_source_name;
|
||||||
public static $db_socket;
|
static $db_host;
|
||||||
public static $db_port;
|
static $db_socket;
|
||||||
public static $db_name;
|
static $db_port;
|
||||||
public static $db_username;
|
static $db_name;
|
||||||
public static $db_password;
|
static $db_username;
|
||||||
public static $db_charset;
|
static $db_password;
|
||||||
|
static $db_charset;
|
||||||
|
|
||||||
public static function init($file, $version) {
|
static function init($file, $version) {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
self::$version = $version;
|
self::$version = $version;
|
||||||
self::$file = $file;
|
self::$file = $file;
|
||||||
self::$path = dirname(self::$file);
|
self::$path = dirname(self::$file);
|
||||||
self::$plugin_name = 'mailpoet';
|
self::$plugin_name = 'mailpoet';
|
||||||
self::$plugin_url = plugins_url() . '/' . basename(Env::$path);
|
self::$plugin_url = plugin_dir_url(__FILE__);
|
||||||
self::$views_path = self::$path . '/views';
|
self::$views_path = self::$path . '/views';
|
||||||
self::$assets_path = self::$path . '/assets';
|
self::$assets_path = self::$path . '/assets';
|
||||||
self::$assets_url = plugins_url('/assets', $file);
|
self::$assets_url = plugins_url('/assets', $file);
|
||||||
@ -46,11 +47,12 @@ class Env {
|
|||||||
self::$db_host = DB_HOST;
|
self::$db_host = DB_HOST;
|
||||||
self::$db_port = 3306;
|
self::$db_port = 3306;
|
||||||
self::$db_socket = false;
|
self::$db_socket = false;
|
||||||
if (preg_match('/(?=:\d+$)/', DB_HOST)) {
|
if(preg_match('/(?=:\d+$)/', DB_HOST)) {
|
||||||
list(self::$db_host, self::$db_port) = explode(':', DB_HOST);
|
list(self::$db_host, self::$db_port) = explode(':', DB_HOST);
|
||||||
}
|
} else {
|
||||||
else if (preg_match('/:/', DB_HOST)) {
|
if(preg_match('/:/', DB_HOST)) {
|
||||||
self::$db_socket = true;
|
self::$db_socket = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self::$db_name = DB_NAME;
|
self::$db_name = DB_NAME;
|
||||||
self::$db_username = DB_USER;
|
self::$db_username = DB_USER;
|
||||||
@ -59,7 +61,7 @@ class Env {
|
|||||||
self::$db_source_name = self::dbSourceName(self::$db_host, self::$db_socket, self::$db_port);
|
self::$db_source_name = self::dbSourceName(self::$db_host, self::$db_socket, self::$db_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function dbSourceName($host, $socket,$port) {
|
private static function dbSourceName($host, $socket, $port) {
|
||||||
$source_name = array(
|
$source_name = array(
|
||||||
(!$socket) ? 'mysql:host=' : 'mysql:unix_socket=',
|
(!$socket) ? 'mysql:host=' : 'mysql:unix_socket=',
|
||||||
$host,
|
$host,
|
||||||
@ -72,4 +74,14 @@ class Env {
|
|||||||
);
|
);
|
||||||
return implode('', $source_name);
|
return implode('', $source_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function isPluginActivated() {
|
||||||
|
$activatesPlugins = get_option('active_plugins');
|
||||||
|
$isActivated =
|
||||||
|
in_array(
|
||||||
|
sprintf('%s/%s.php', basename(self::$path), self::$plugin_name),
|
||||||
|
$activatesPlugins
|
||||||
|
);
|
||||||
|
return ($isActivated) ? true : false;
|
||||||
|
}
|
||||||
}
|
}
|
42
lib/Config/Hooks.php
Normal file
42
lib/Config/Hooks.php
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Config;
|
||||||
|
|
||||||
|
class Hooks {
|
||||||
|
function __construct() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
// WP Users synchronization
|
||||||
|
add_action(
|
||||||
|
'user_register',
|
||||||
|
'\MailPoet\Segments\WP::synchronizeUser',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
add_action(
|
||||||
|
'added_existing_user',
|
||||||
|
'\MailPoet\Segments\WP::synchronizeUser',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
add_action(
|
||||||
|
'profile_update',
|
||||||
|
'\MailPoet\Segments\WP::synchronizeUser',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
add_action(
|
||||||
|
'delete_user',
|
||||||
|
'\MailPoet\Segments\WP::synchronizeUser',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
// multisite
|
||||||
|
add_action(
|
||||||
|
'deleted_user',
|
||||||
|
'\MailPoet\Segments\WP::synchronizeUser',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
add_action(
|
||||||
|
'remove_user_from_blog',
|
||||||
|
'\MailPoet\Segments\WP::synchronizeUser',
|
||||||
|
1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
namespace MailPoet\Config;
|
namespace MailPoet\Config;
|
||||||
|
|
||||||
use MailPoet\Models;
|
use MailPoet\Models;
|
||||||
|
use MailPoet\Queue\Supervisor;
|
||||||
use MailPoet\Router;
|
use MailPoet\Router;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
@ -25,6 +26,9 @@ class Initializer {
|
|||||||
$this->setupAnalytics();
|
$this->setupAnalytics();
|
||||||
$this->setupPermissions();
|
$this->setupPermissions();
|
||||||
$this->setupChangelog();
|
$this->setupChangelog();
|
||||||
|
$this->setupPublicAPI();
|
||||||
|
$this->runQueueSupervisor();
|
||||||
|
$this->setupHooks();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupDB() {
|
function setupDB() {
|
||||||
@ -33,7 +37,8 @@ class Initializer {
|
|||||||
\ORM::configure('password', Env::$db_password);
|
\ORM::configure('password', Env::$db_password);
|
||||||
\ORM::configure('logging', WP_DEBUG);
|
\ORM::configure('logging', WP_DEBUG);
|
||||||
\ORM::configure('driver_options', array(
|
\ORM::configure('driver_options', array(
|
||||||
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
|
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
|
||||||
|
\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET TIME_ZONE = "+00:00"'
|
||||||
));
|
));
|
||||||
|
|
||||||
$subscribers = Env::$db_prefix . 'subscribers';
|
$subscribers = Env::$db_prefix . 'subscribers';
|
||||||
@ -41,6 +46,8 @@ class Initializer {
|
|||||||
$newsletters = Env::$db_prefix . 'newsletters';
|
$newsletters = Env::$db_prefix . 'newsletters';
|
||||||
$newsletter_templates = Env::$db_prefix . 'newsletter_templates';
|
$newsletter_templates = Env::$db_prefix . 'newsletter_templates';
|
||||||
$segments = Env::$db_prefix . 'segments';
|
$segments = Env::$db_prefix . 'segments';
|
||||||
|
$filters = Env::$db_prefix . 'filters';
|
||||||
|
$segment_filter = Env::$db_prefix . 'segment_filter';
|
||||||
$forms = Env::$db_prefix . 'forms';
|
$forms = Env::$db_prefix . 'forms';
|
||||||
$subscriber_segment = Env::$db_prefix . 'subscriber_segment';
|
$subscriber_segment = Env::$db_prefix . 'subscriber_segment';
|
||||||
$newsletter_segment = Env::$db_prefix . 'newsletter_segment';
|
$newsletter_segment = Env::$db_prefix . 'newsletter_segment';
|
||||||
@ -48,11 +55,15 @@ class Initializer {
|
|||||||
$subscriber_custom_field = Env::$db_prefix . 'subscriber_custom_field';
|
$subscriber_custom_field = Env::$db_prefix . 'subscriber_custom_field';
|
||||||
$newsletter_option_fields = Env::$db_prefix . 'newsletter_option_fields';
|
$newsletter_option_fields = Env::$db_prefix . 'newsletter_option_fields';
|
||||||
$newsletter_option = Env::$db_prefix . 'newsletter_option';
|
$newsletter_option = Env::$db_prefix . 'newsletter_option';
|
||||||
|
$queues = Env::$db_prefix . 'queues';
|
||||||
|
$newsletter_statistics = Env::$db_prefix . 'newsletter_statistics';
|
||||||
|
|
||||||
define('MP_SUBSCRIBERS_TABLE', $subscribers);
|
define('MP_SUBSCRIBERS_TABLE', $subscribers);
|
||||||
define('MP_SETTINGS_TABLE', $settings);
|
define('MP_SETTINGS_TABLE', $settings);
|
||||||
define('MP_NEWSLETTERS_TABLE', $newsletters);
|
define('MP_NEWSLETTERS_TABLE', $newsletters);
|
||||||
define('MP_SEGMENTS_TABLE', $segments);
|
define('MP_SEGMENTS_TABLE', $segments);
|
||||||
|
define('MP_FILTERS_TABLE', $filters);
|
||||||
|
define('MP_SEGMENT_FILTER_TABLE', $segment_filter);
|
||||||
define('MP_FORMS_TABLE', $forms);
|
define('MP_FORMS_TABLE', $forms);
|
||||||
define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment);
|
define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment);
|
||||||
define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates);
|
define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates);
|
||||||
@ -61,6 +72,8 @@ class Initializer {
|
|||||||
define('MP_SUBSCRIBER_CUSTOM_FIELD_TABLE', $subscriber_custom_field);
|
define('MP_SUBSCRIBER_CUSTOM_FIELD_TABLE', $subscriber_custom_field);
|
||||||
define('MP_NEWSLETTER_OPTION_FIELDS_TABLE', $newsletter_option_fields);
|
define('MP_NEWSLETTER_OPTION_FIELDS_TABLE', $newsletter_option_fields);
|
||||||
define('MP_NEWSLETTER_OPTION_TABLE', $newsletter_option);
|
define('MP_NEWSLETTER_OPTION_TABLE', $newsletter_option);
|
||||||
|
define('MP_QUEUES_TABLE', $queues);
|
||||||
|
define('MP_NEWSLETTER_STATISTICS_TABLE', $newsletter_statistics);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupActivator() {
|
function setupActivator() {
|
||||||
@ -110,4 +123,21 @@ class Initializer {
|
|||||||
$changelog = new Changelog();
|
$changelog = new Changelog();
|
||||||
$changelog->init();
|
$changelog->init();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
function setupHooks() {
|
||||||
|
$hooks = new Hooks();
|
||||||
|
$hooks->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupPublicAPI() {
|
||||||
|
$publicAPI = new PublicAPI();
|
||||||
|
$publicAPI->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
function runQueueSupervisor() {
|
||||||
|
try {
|
||||||
|
$supervisor = new Supervisor();
|
||||||
|
$supervisor->checkDaemon();
|
||||||
|
} catch (\Exception $e) {}
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Config;
|
namespace MailPoet\Config;
|
||||||
|
|
||||||
|
use MailPoet\Form\Block;
|
||||||
|
use MailPoet\Form\Renderer as FormRenderer;
|
||||||
|
use MailPoet\Models\Form;
|
||||||
|
use MailPoet\Models\Segment;
|
||||||
|
use MailPoet\Models\Setting;
|
||||||
|
use MailPoet\Settings\Charsets;
|
||||||
|
use MailPoet\Settings\Hosts;
|
||||||
|
use MailPoet\Settings\Pages;
|
||||||
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
||||||
use \MailPoet\Models\Segment;
|
use MailPoet\Util\DKIM;
|
||||||
use \MailPoet\Models\Setting;
|
use MailPoet\Util\Permissions;
|
||||||
use \MailPoet\Models\Form;
|
|
||||||
use \MailPoet\Form\Block;
|
|
||||||
use \MailPoet\Form\Renderer as FormRenderer;
|
|
||||||
use \MailPoet\Settings\Hosts;
|
|
||||||
use \MailPoet\Settings\Pages;
|
|
||||||
use \MailPoet\Settings\Charsets;
|
|
||||||
use \MailPoet\Util\Permissions;
|
|
||||||
use \MailPoet\Util\DKIM;
|
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
@ -24,7 +24,10 @@ class Menu {
|
|||||||
function init() {
|
function init() {
|
||||||
add_action(
|
add_action(
|
||||||
'admin_menu',
|
'admin_menu',
|
||||||
array($this, 'setup')
|
array(
|
||||||
|
$this,
|
||||||
|
'setup'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +37,10 @@ class Menu {
|
|||||||
'MailPoet',
|
'MailPoet',
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet',
|
'mailpoet',
|
||||||
array($this, 'home'),
|
array(
|
||||||
|
$this,
|
||||||
|
'home'
|
||||||
|
),
|
||||||
$this->assets_url . '/img/menu_icon.png',
|
$this->assets_url . '/img/menu_icon.png',
|
||||||
30
|
30
|
||||||
);
|
);
|
||||||
@ -44,7 +50,10 @@ class Menu {
|
|||||||
__('Newsletters'),
|
__('Newsletters'),
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet-newsletters',
|
'mailpoet-newsletters',
|
||||||
array($this, 'newsletters')
|
array(
|
||||||
|
$this,
|
||||||
|
'newsletters'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
add_submenu_page(
|
add_submenu_page(
|
||||||
'mailpoet',
|
'mailpoet',
|
||||||
@ -52,7 +61,10 @@ class Menu {
|
|||||||
__('Forms'),
|
__('Forms'),
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet-forms',
|
'mailpoet-forms',
|
||||||
array($this, 'forms')
|
array(
|
||||||
|
$this,
|
||||||
|
'forms'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
add_submenu_page(
|
add_submenu_page(
|
||||||
'mailpoet',
|
'mailpoet',
|
||||||
@ -60,7 +72,10 @@ class Menu {
|
|||||||
__('Subscribers'),
|
__('Subscribers'),
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet-subscribers',
|
'mailpoet-subscribers',
|
||||||
array($this, 'subscribers')
|
array(
|
||||||
|
$this,
|
||||||
|
'subscribers'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
add_submenu_page(
|
add_submenu_page(
|
||||||
'mailpoet',
|
'mailpoet',
|
||||||
@ -68,7 +83,10 @@ class Menu {
|
|||||||
__('Segments'),
|
__('Segments'),
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet-segments',
|
'mailpoet-segments',
|
||||||
array($this, 'segments')
|
array(
|
||||||
|
$this,
|
||||||
|
'segments'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
add_submenu_page(
|
add_submenu_page(
|
||||||
'mailpoet',
|
'mailpoet',
|
||||||
@ -76,7 +94,10 @@ class Menu {
|
|||||||
__('Settings'),
|
__('Settings'),
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet-settings',
|
'mailpoet-settings',
|
||||||
array($this, 'settings')
|
array(
|
||||||
|
$this,
|
||||||
|
'settings'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
add_submenu_page(
|
add_submenu_page(
|
||||||
null,
|
null,
|
||||||
@ -84,7 +105,10 @@ class Menu {
|
|||||||
__('Import'),
|
__('Import'),
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet-import',
|
'mailpoet-import',
|
||||||
array($this, 'import')
|
array(
|
||||||
|
$this,
|
||||||
|
'import'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
add_submenu_page(
|
add_submenu_page(
|
||||||
null,
|
null,
|
||||||
@ -92,7 +116,10 @@ class Menu {
|
|||||||
__('Export'),
|
__('Export'),
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet-export',
|
'mailpoet-export',
|
||||||
array($this, 'export')
|
array(
|
||||||
|
$this,
|
||||||
|
'export'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
add_submenu_page(
|
add_submenu_page(
|
||||||
@ -101,7 +128,10 @@ class Menu {
|
|||||||
__('Welcome'),
|
__('Welcome'),
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet-welcome',
|
'mailpoet-welcome',
|
||||||
array($this, 'welcome')
|
array(
|
||||||
|
$this,
|
||||||
|
'welcome'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
add_submenu_page(
|
add_submenu_page(
|
||||||
@ -110,7 +140,10 @@ class Menu {
|
|||||||
__('Update'),
|
__('Update'),
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet-update',
|
'mailpoet-update',
|
||||||
array($this, 'update')
|
array(
|
||||||
|
$this,
|
||||||
|
'update'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
add_submenu_page(
|
add_submenu_page(
|
||||||
@ -119,7 +152,10 @@ class Menu {
|
|||||||
__('Form editor'),
|
__('Form editor'),
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet-form-editor',
|
'mailpoet-form-editor',
|
||||||
array($this, 'formEditor')
|
array(
|
||||||
|
$this,
|
||||||
|
'formEditor'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
add_submenu_page(
|
add_submenu_page(
|
||||||
@ -128,7 +164,22 @@ class Menu {
|
|||||||
__('Newsletter editor'),
|
__('Newsletter editor'),
|
||||||
'manage_options',
|
'manage_options',
|
||||||
'mailpoet-newsletter-editor',
|
'mailpoet-newsletter-editor',
|
||||||
array($this, 'newletterEditor')
|
array(
|
||||||
|
$this,
|
||||||
|
'newletterEditor'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
add_submenu_page(
|
||||||
|
'mailpoet',
|
||||||
|
__('Queue'),
|
||||||
|
__('Queue'),
|
||||||
|
'manage_options',
|
||||||
|
'mailpoet-queue',
|
||||||
|
array(
|
||||||
|
$this,
|
||||||
|
'queue'
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,8 +193,8 @@ class Menu {
|
|||||||
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
||||||
$redirect_url =
|
$redirect_url =
|
||||||
(!empty($_GET['mailpoet_redirect']))
|
(!empty($_GET['mailpoet_redirect']))
|
||||||
? urldecode($_GET['mailpoet_redirect'])
|
? urldecode($_GET['mailpoet_redirect'])
|
||||||
: wp_get_referer();
|
: wp_get_referer();
|
||||||
|
|
||||||
if(
|
if(
|
||||||
$redirect_url === $current_url
|
$redirect_url === $current_url
|
||||||
@ -166,8 +217,8 @@ class Menu {
|
|||||||
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
||||||
$redirect_url =
|
$redirect_url =
|
||||||
(!empty($_GET['mailpoet_redirect']))
|
(!empty($_GET['mailpoet_redirect']))
|
||||||
? urldecode($_GET['mailpoet_redirect'])
|
? urldecode($_GET['mailpoet_redirect'])
|
||||||
: wp_get_referer();
|
: wp_get_referer();
|
||||||
|
|
||||||
if(
|
if(
|
||||||
$redirect_url === $current_url
|
$redirect_url === $current_url
|
||||||
@ -206,7 +257,8 @@ class Menu {
|
|||||||
|
|
||||||
$data = array(
|
$data = array(
|
||||||
'settings' => $settings,
|
'settings' => $settings,
|
||||||
'segments' => Segment::getPublished()->findArray(),
|
'segments' => Segment::getPublished()
|
||||||
|
->findArray(),
|
||||||
'pages' => Pages::getAll(),
|
'pages' => Pages::getAll(),
|
||||||
'flags' => $this->_getFlags(),
|
'flags' => $this->_getFlags(),
|
||||||
'charsets' => Charsets::getAll(),
|
'charsets' => Charsets::getAll(),
|
||||||
@ -234,11 +286,14 @@ class Menu {
|
|||||||
|
|
||||||
// check if users can register
|
// check if users can register
|
||||||
$flags['registration_enabled'] =
|
$flags['registration_enabled'] =
|
||||||
!(in_array($registration, array('none', 'blog')));
|
!(in_array($registration, array(
|
||||||
|
'none',
|
||||||
|
'blog'
|
||||||
|
)));
|
||||||
} else {
|
} else {
|
||||||
// check if users can register
|
// check if users can register
|
||||||
$flags['registration_enabled'] =
|
$flags['registration_enabled'] =
|
||||||
(bool)get_option('users_can_register', false);
|
(bool) get_option('users_can_register', false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $flags;
|
return $flags;
|
||||||
@ -249,7 +304,7 @@ class Menu {
|
|||||||
|
|
||||||
$data['segments'] = Segment::findArray();
|
$data['segments'] = Segment::findArray();
|
||||||
|
|
||||||
echo $this->renderer->render('subscribers.html', $data);
|
echo $this->renderer->render('subscribers/subscribers.html', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function segments() {
|
function segments() {
|
||||||
@ -272,7 +327,7 @@ class Menu {
|
|||||||
$data['segments'] = Segment::findArray();
|
$data['segments'] = Segment::findArray();
|
||||||
$settings = Setting::findArray();
|
$settings = Setting::findArray();
|
||||||
$data['settings'] = array();
|
$data['settings'] = array();
|
||||||
foreach($settings as $setting) {
|
foreach ($settings as $setting) {
|
||||||
$data['settings'][$setting['name']] = $setting['value'];
|
$data['settings'][$setting['name']] = $setting['value'];
|
||||||
}
|
}
|
||||||
$data['roles'] = $wp_roles->get_names();
|
$data['roles'] = $wp_roles->get_names();
|
||||||
@ -290,17 +345,17 @@ class Menu {
|
|||||||
function import() {
|
function import() {
|
||||||
$import = new BootStrapMenu('import');
|
$import = new BootStrapMenu('import');
|
||||||
$data = $import->bootstrap();
|
$data = $import->bootstrap();
|
||||||
echo $this->renderer->render('import.html', $data);
|
echo $this->renderer->render('subscribers/importExport/import.html', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function export() {
|
function export() {
|
||||||
$export = new BootStrapMenu('export');
|
$export = new BootStrapMenu('export');
|
||||||
$data = $export->bootstrap();
|
$data = $export->bootstrap();
|
||||||
echo $this->renderer->render('export.html', $data);
|
echo $this->renderer->render('subscribers/importExport/export.html', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formEditor() {
|
function formEditor() {
|
||||||
$id = (isset($_GET['id']) ? (int)$_GET['id'] : 0);
|
$id = (isset($_GET['id']) ? (int) $_GET['id'] : 0);
|
||||||
$form = Form::findOne($id);
|
$form = Form::findOne($id);
|
||||||
if($form !== false) {
|
if($form !== false) {
|
||||||
$form = $form->asArray();
|
$form = $form->asArray();
|
||||||
@ -309,7 +364,8 @@ class Menu {
|
|||||||
$data = array(
|
$data = array(
|
||||||
'form' => $form,
|
'form' => $form,
|
||||||
'pages' => Pages::getAll(),
|
'pages' => Pages::getAll(),
|
||||||
'segments' => Segment::getPublished()->findArray(),
|
'segments' => Segment::getPublished()
|
||||||
|
->findArray(),
|
||||||
'styles' => FormRenderer::getStyles($form),
|
'styles' => FormRenderer::getStyles($form),
|
||||||
'date_types' => Block\Date::getDateTypes(),
|
'date_types' => Block\Date::getDateTypes(),
|
||||||
'date_formats' => Block\Date::getDateFormats()
|
'date_formats' => Block\Date::getDateFormats()
|
||||||
@ -317,4 +373,10 @@ class Menu {
|
|||||||
|
|
||||||
echo $this->renderer->render('form/editor.html', $data);
|
echo $this->renderer->render('form/editor.html', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function queue() {
|
||||||
|
$daemon = new \MailPoet\Queue\BootStrapMenu();
|
||||||
|
$data['daemon'] = json_encode($daemon->bootstrap());
|
||||||
|
echo $this->renderer->render('queue.html', $data);
|
||||||
|
}
|
||||||
}
|
}
|
@ -21,6 +21,8 @@ class Migrator {
|
|||||||
'subscriber_custom_field',
|
'subscriber_custom_field',
|
||||||
'newsletter_option_fields',
|
'newsletter_option_fields',
|
||||||
'newsletter_option',
|
'newsletter_option',
|
||||||
|
'queues',
|
||||||
|
'newsletter_statistics',
|
||||||
'forms'
|
'forms'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -50,6 +52,7 @@ class Migrator {
|
|||||||
function subscribers() {
|
function subscribers() {
|
||||||
$attributes = array(
|
$attributes = array(
|
||||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||||
|
'wp_user_id bigint(20) NULL,',
|
||||||
'first_name tinytext NOT NULL,',
|
'first_name tinytext NOT NULL,',
|
||||||
'last_name tinytext NOT NULL,',
|
'last_name tinytext NOT NULL,',
|
||||||
'email varchar(150) NOT NULL,',
|
'email varchar(150) NOT NULL,',
|
||||||
@ -97,6 +100,7 @@ class Migrator {
|
|||||||
'name varchar(250) NOT NULL,',
|
'name varchar(250) NOT NULL,',
|
||||||
'description varchar(250) NOT NULL,',
|
'description varchar(250) NOT NULL,',
|
||||||
'body longtext,',
|
'body longtext,',
|
||||||
|
'thumbnail longtext,',
|
||||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||||
'PRIMARY KEY (id)'
|
'PRIMARY KEY (id)'
|
||||||
@ -106,14 +110,15 @@ class Migrator {
|
|||||||
|
|
||||||
function segments() {
|
function segments() {
|
||||||
$attributes = array(
|
$attributes = array(
|
||||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||||
'name varchar(90) NOT NULL,',
|
'name varchar(90) NOT NULL,',
|
||||||
'description varchar(250) NOT NULL,',
|
'type varchar(90) NOT NULL DEFAULT "default",',
|
||||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
'description varchar(250) NOT NULL,',
|
||||||
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
|
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
|
||||||
'PRIMARY KEY (id),',
|
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||||
'UNIQUE KEY name (name)'
|
'PRIMARY KEY (id),',
|
||||||
|
'UNIQUE KEY name (name)'
|
||||||
);
|
);
|
||||||
return $this->sqlify(__FUNCTION__, $attributes);
|
return $this->sqlify(__FUNCTION__, $attributes);
|
||||||
}
|
}
|
||||||
@ -123,6 +128,7 @@ class Migrator {
|
|||||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||||
'subscriber_id mediumint(9) NOT NULL,',
|
'subscriber_id mediumint(9) NOT NULL,',
|
||||||
'segment_id mediumint(9) NOT NULL,',
|
'segment_id mediumint(9) NOT NULL,',
|
||||||
|
'status varchar(12) NOT NULL DEFAULT "subscribed",',
|
||||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||||
'PRIMARY KEY (id),',
|
'PRIMARY KEY (id),',
|
||||||
@ -199,6 +205,41 @@ class Migrator {
|
|||||||
return $this->sqlify(__FUNCTION__, $attributes);
|
return $this->sqlify(__FUNCTION__, $attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function queues() {
|
||||||
|
$attributes = array(
|
||||||
|
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||||
|
'newsletter_id mediumint(9) NOT NULL,',
|
||||||
|
'subscribers longtext,',
|
||||||
|
'status varchar(12) NOT NULL,',
|
||||||
|
'priority mediumint(9) NOT NULL DEFAULT 0,',
|
||||||
|
'count_total mediumint(9) NOT NULL DEFAULT 0,',
|
||||||
|
'count_processed mediumint(9) NOT NULL DEFAULT 0,',
|
||||||
|
'count_to_process mediumint(9) NOT NULL DEFAULT 0,',
|
||||||
|
'count_failed mediumint(9) NOT NULL DEFAULT 0,',
|
||||||
|
'processed_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||||
|
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||||
|
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||||
|
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
|
||||||
|
'PRIMARY KEY (id)',
|
||||||
|
);
|
||||||
|
return $this->sqlify(__FUNCTION__, $attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
function newsletter_statistics() {
|
||||||
|
$attributes = array(
|
||||||
|
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||||
|
'newsletter_id mediumint(9) NOT NULL,',
|
||||||
|
'subscriber_id mediumint(9) NOT NULL,',
|
||||||
|
'queue_id mediumint(9) NOT NULL,',
|
||||||
|
'sent_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||||
|
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||||
|
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||||
|
'deleted_at TIMESTAMP NULL DEFAULT NULL,',
|
||||||
|
'PRIMARY KEY (id)',
|
||||||
|
);
|
||||||
|
return $this->sqlify(__FUNCTION__, $attributes);
|
||||||
|
}
|
||||||
|
|
||||||
function forms() {
|
function forms() {
|
||||||
$attributes = array(
|
$attributes = array(
|
||||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||||
@ -224,4 +265,4 @@ class Migrator {
|
|||||||
|
|
||||||
return implode("\n", $sql);
|
return implode("\n", $sql);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Config;
|
namespace MailPoet\Config;
|
||||||
|
|
||||||
|
use MailPoet\Config\PopulatorData\Templates\SampleTemplate;
|
||||||
|
|
||||||
if (!defined('ABSPATH')) exit;
|
if (!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
||||||
@ -10,6 +12,7 @@ class Populator {
|
|||||||
$this->prefix = Env::$db_prefix;
|
$this->prefix = Env::$db_prefix;
|
||||||
$this->models = array(
|
$this->models = array(
|
||||||
'newsletter_option_fields',
|
'newsletter_option_fields',
|
||||||
|
'newsletter_templates',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +87,12 @@ class Populator {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function newsletter_templates() {
|
||||||
|
return array(
|
||||||
|
(new SampleTemplate(Env::$assets_url))->get(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private function populate($model) {
|
private function populate($model) {
|
||||||
$rows = $this->$model();
|
$rows = $this->$model();
|
||||||
$table = $this->prefix . $model;
|
$table = $this->prefix . $model;
|
||||||
|
379
lib/Config/PopulatorData/Templates/SampleTemplate.php
Normal file
379
lib/Config/PopulatorData/Templates/SampleTemplate.php
Normal file
File diff suppressed because one or more lines are too long
45
lib/Config/PublicAPI.php
Normal file
45
lib/Config/PublicAPI.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Config;
|
||||||
|
|
||||||
|
use MailPoet\Queue\Daemon;
|
||||||
|
use MailPoet\Util\Helpers;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class PublicAPI {
|
||||||
|
function __construct() {
|
||||||
|
# http://example.com/?mailpoet-api§ion=&action=&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) :
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
if(!$this->api && !$this->section) return;
|
||||||
|
$this->_checkAndCallMethod($this, $this->section, $terminate = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function queue() {
|
||||||
|
$queue = new Daemon($this->payload);
|
||||||
|
$this->_checkAndCallMethod($queue, $this->action);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _checkAndCallMethod($class, $method, $terminate = false) {
|
||||||
|
if(!method_exists($class, $method)) {
|
||||||
|
if(!$terminate) return;
|
||||||
|
header('HTTP/1.0 404 Not Found');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
call_user_func(
|
||||||
|
array(
|
||||||
|
$class,
|
||||||
|
$method
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
50
lib/Models/Filter.php
Normal file
50
lib/Models/Filter.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Models;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class Filter extends Model {
|
||||||
|
static $_table = MP_FILTERS_TABLE;
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->addValidations('name', array(
|
||||||
|
'required' => __('You need to specify a name.')
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete() {
|
||||||
|
// delete all relations to subscribers
|
||||||
|
SegmentFilter::where('filter_id', $this->id)->deleteMany();
|
||||||
|
return parent::delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
function segments() {
|
||||||
|
return $this->has_many_through(
|
||||||
|
__NAMESPACE__.'\Segment',
|
||||||
|
__NAMESPACE__.'\SegmentFilter',
|
||||||
|
'filter_id',
|
||||||
|
'segment_id'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function createOrUpdate($data = array()) {
|
||||||
|
$filter = false;
|
||||||
|
|
||||||
|
if(isset($data['id']) && (int)$data['id'] > 0) {
|
||||||
|
$filter = self::findOne((int)$data['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($filter === false) {
|
||||||
|
$filter = self::create();
|
||||||
|
$filter->hydrate($data);
|
||||||
|
} else {
|
||||||
|
unset($data['id']);
|
||||||
|
$filter->set($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$filter->save();
|
||||||
|
return $filter;
|
||||||
|
}
|
||||||
|
}
|
12
lib/Models/NewsletterStatistics.php
Normal file
12
lib/Models/NewsletterStatistics.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Models;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class NewsletterStatistics extends Model {
|
||||||
|
public static $_table = MP_NEWSLETTER_STATISTICS_TABLE;
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
}
|
12
lib/Models/Queue.php
Normal file
12
lib/Models/Queue.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Models;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class Queue extends Model {
|
||||||
|
public static $_table = MP_QUEUES_TABLE;
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,15 @@ class Segment extends Model {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function segmentFilters() {
|
||||||
|
return $this->has_many_through(
|
||||||
|
__NAMESPACE__.'\Filter',
|
||||||
|
__NAMESPACE__.'\SegmentFilter',
|
||||||
|
'segment_id',
|
||||||
|
'filter_id'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function duplicate($data = array()) {
|
function duplicate($data = array()) {
|
||||||
$duplicate = parent::duplicate($data);
|
$duplicate = parent::duplicate($data);
|
||||||
|
|
||||||
@ -67,6 +76,23 @@ class Segment extends Model {
|
|||||||
->delete();
|
->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function getWPUsers() {
|
||||||
|
$segment = self::where('type', 'wp_users')->findOne();
|
||||||
|
|
||||||
|
if($segment === false) {
|
||||||
|
// create the wp users list
|
||||||
|
$segment = self::create();
|
||||||
|
$segment->hydrate(array(
|
||||||
|
'name' => __('WordPress Users'),
|
||||||
|
'type' => 'wp_users'
|
||||||
|
));
|
||||||
|
$segment->save();
|
||||||
|
return self::findOne($segment->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $segment;
|
||||||
|
}
|
||||||
|
|
||||||
static function search($orm, $search = '') {
|
static function search($orm, $search = '') {
|
||||||
return $orm->whereLike('name', '%'.$search.'%');
|
return $orm->whereLike('name', '%'.$search.'%');
|
||||||
}
|
}
|
||||||
@ -102,8 +128,13 @@ class Segment extends Model {
|
|||||||
->left_outer_join(
|
->left_outer_join(
|
||||||
MP_SUBSCRIBER_SEGMENT_TABLE,
|
MP_SUBSCRIBER_SEGMENT_TABLE,
|
||||||
array(self::$_table.'.id', '=', MP_SUBSCRIBER_SEGMENT_TABLE.'.segment_id'))
|
array(self::$_table.'.id', '=', MP_SUBSCRIBER_SEGMENT_TABLE.'.segment_id'))
|
||||||
|
->left_outer_join(
|
||||||
|
MP_SUBSCRIBERS_TABLE,
|
||||||
|
array(MP_SUBSCRIBER_SEGMENT_TABLE.'.subscriber_id', '=', MP_SUBSCRIBERS_TABLE.'.id'))
|
||||||
|
->whereNull(MP_SUBSCRIBERS_TABLE.'.deleted_at')
|
||||||
->group_by(self::$_table.'.id')
|
->group_by(self::$_table.'.id')
|
||||||
->group_by(self::$_table.'.name')
|
->group_by(self::$_table.'.name')
|
||||||
|
->where(self::$_table.'.type', 'default')
|
||||||
->findArray();
|
->findArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,16 +145,18 @@ class Segment extends Model {
|
|||||||
'LEFT JOIN ' . self::$_table . ' segments ON segments.id = relation.segment_id ' .
|
'LEFT JOIN ' . self::$_table . ' segments ON segments.id = relation.segment_id ' .
|
||||||
'LEFT JOIN ' . MP_SUBSCRIBERS_TABLE . ' subscribers ON subscribers.id = relation.subscriber_id ' .
|
'LEFT JOIN ' . MP_SUBSCRIBERS_TABLE . ' subscribers ON subscribers.id = relation.subscriber_id ' .
|
||||||
(($withConfirmedSubscribers) ?
|
(($withConfirmedSubscribers) ?
|
||||||
'WHERE subscribers.status = 1 ' :
|
'WHERE subscribers.status = "subscribed" ' :
|
||||||
'WHERE relation.segment_id IS NOT NULL ') .
|
'WHERE relation.segment_id IS NOT NULL ') .
|
||||||
|
'AND subscribers.deleted_at IS NULL ' .
|
||||||
'GROUP BY segments.id) ' .
|
'GROUP BY segments.id) ' .
|
||||||
'UNION ALL ' .
|
'UNION ALL ' .
|
||||||
'(SELECT 0 as id, "' . __('Not In List') . '" as name, COUNT(*) as subscribers ' .
|
'(SELECT 0 as id, "' . __('Not In List') . '" as name, COUNT(*) as subscribers ' .
|
||||||
'FROM ' . MP_SUBSCRIBERS_TABLE . ' subscribers ' .
|
'FROM ' . MP_SUBSCRIBERS_TABLE . ' subscribers ' .
|
||||||
'LEFT JOIN ' . MP_SUBSCRIBER_SEGMENT_TABLE . ' relation on relation.subscriber_id = subscribers.id ' .
|
'LEFT JOIN ' . MP_SUBSCRIBER_SEGMENT_TABLE . ' relation on relation.subscriber_id = subscribers.id ' .
|
||||||
(($withConfirmedSubscribers) ?
|
(($withConfirmedSubscribers) ?
|
||||||
'WHERE relation.subscriber_id is NULL AND subscribers.status = 1 ' :
|
'WHERE relation.subscriber_id is NULL AND subscribers.status = "subscribed" ' :
|
||||||
'WHERE relation.subscriber_id is NULL ') .
|
'WHERE relation.subscriber_id is NULL ') .
|
||||||
|
'AND subscribers.deleted_at IS NULL ' .
|
||||||
'HAVING subscribers) ' .
|
'HAVING subscribers) ' .
|
||||||
'ORDER BY name'
|
'ORDER BY name'
|
||||||
)->findArray();
|
)->findArray();
|
||||||
@ -147,4 +180,8 @@ class Segment extends Model {
|
|||||||
$segment->save();
|
$segment->save();
|
||||||
return $segment;
|
return $segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function getPublic() {
|
||||||
|
return self::getPublished()->where('type', 'default');
|
||||||
|
}
|
||||||
}
|
}
|
12
lib/Models/SegmentFilter.php
Normal file
12
lib/Models/SegmentFilter.php
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Models;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class SegmentFilter extends Model {
|
||||||
|
public static $_table = MP_SEGMENT_FILTER_TABLE;
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
}
|
@ -324,7 +324,7 @@ class Subscriber extends Model {
|
|||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
->where('status', 'unconfirmed');
|
->where('status', 'unconfirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
static function createMultiple($columns, $values) {
|
static function createMultiple($columns, $values) {
|
||||||
return self::rawExecute(
|
return self::rawExecute(
|
||||||
'INSERT INTO `' . self::$_table . '` ' .
|
'INSERT INTO `' . self::$_table . '` ' .
|
||||||
|
36
lib/Queue/BootStrapMenu.php
Normal file
36
lib/Queue/BootStrapMenu.php
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Queue;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use MailPoet\Models\Queue;
|
||||||
|
use MailPoet\Models\Setting;
|
||||||
|
|
||||||
|
class BootStrapMenu {
|
||||||
|
function __construct() {
|
||||||
|
$this->daemon = Setting::where('name', 'daemon')
|
||||||
|
->findOne();
|
||||||
|
}
|
||||||
|
|
||||||
|
function bootStrap() {
|
||||||
|
$queues = Queue::findMany();
|
||||||
|
return ($this->daemon) ?
|
||||||
|
array_merge(
|
||||||
|
array(
|
||||||
|
'time_since_start' =>
|
||||||
|
Carbon::createFromFormat(
|
||||||
|
'Y-m-d H:i:s',
|
||||||
|
$this->daemon->created_at,
|
||||||
|
'UTC'
|
||||||
|
)->diffForHumans(),
|
||||||
|
'time_since_update' =>
|
||||||
|
Carbon::createFromFormat(
|
||||||
|
'Y-m-d H:i:s',
|
||||||
|
$this->daemon->updated_at,
|
||||||
|
'UTC'
|
||||||
|
)->diffForHumans()
|
||||||
|
),
|
||||||
|
json_decode($this->daemon->value, true)
|
||||||
|
) :
|
||||||
|
"false";
|
||||||
|
}
|
||||||
|
}
|
128
lib/Queue/Daemon.php
Normal file
128
lib/Queue/Daemon.php
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Queue;
|
||||||
|
|
||||||
|
use MailPoet\Models\Setting;
|
||||||
|
use MailPoet\Util\Security;
|
||||||
|
|
||||||
|
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class Daemon {
|
||||||
|
function __construct($payload = array()) {
|
||||||
|
set_time_limit(0);
|
||||||
|
ignore_user_abort();
|
||||||
|
list ($this->daemon, $this->daemonData) = $this->getDaemon();
|
||||||
|
$this->refreshedToken = $this->refreshToken();
|
||||||
|
$this->payload = $payload;
|
||||||
|
$this->timer = microtime(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
if(!isset($this->payload['session'])) {
|
||||||
|
$this->abortWithError('missing session ID');
|
||||||
|
}
|
||||||
|
$this->manageSession('start');
|
||||||
|
$daemon = $this->daemon;
|
||||||
|
$daemonData = $this->daemonData;
|
||||||
|
if(!$daemon) {
|
||||||
|
$daemon = Setting::create();
|
||||||
|
$daemon->name = 'daemon';
|
||||||
|
$daemon->value = json_encode(array('status' => 'stopped'));
|
||||||
|
$daemon->save();
|
||||||
|
}
|
||||||
|
if($daemonData['status'] !== 'started') {
|
||||||
|
$_SESSION['daemon'] = 'started';
|
||||||
|
$daemonData = array(
|
||||||
|
'status' => 'started',
|
||||||
|
'token' => $this->refreshedToken,
|
||||||
|
'counter' => ($daemonData['status'] === 'paused') ?
|
||||||
|
$daemonData['counter'] :
|
||||||
|
0
|
||||||
|
);
|
||||||
|
$_SESSION['daemon'] = array('result' => true);
|
||||||
|
$this->manageSession('end');
|
||||||
|
$daemon->value = json_encode($daemonData);
|
||||||
|
$daemon->save();
|
||||||
|
$this->callSelf();
|
||||||
|
} else {
|
||||||
|
$_SESSION['daemon'] = array(
|
||||||
|
'result' => false,
|
||||||
|
'error' => 'already started'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$this->manageSession('end');
|
||||||
|
}
|
||||||
|
|
||||||
|
function run() {
|
||||||
|
if(!$this->daemon || $this->daemonData['status'] !== 'started') {
|
||||||
|
$this->abortWithError('not running');
|
||||||
|
}
|
||||||
|
if(!isset($this->payload['token']) ||
|
||||||
|
$this->payload['token'] !== $this->daemonData['token']
|
||||||
|
) {
|
||||||
|
$this->abortWithError('invalid token');
|
||||||
|
}
|
||||||
|
|
||||||
|
$worker = new Worker();
|
||||||
|
$worker->process();
|
||||||
|
$elapsedTime = microtime(true) - $this->timer;
|
||||||
|
if ($elapsedTime < 30) {
|
||||||
|
sleep(30 - $elapsedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
$this->callSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDaemon() {
|
||||||
|
$daemon = Setting::where('name', 'daemon')
|
||||||
|
->findOne();
|
||||||
|
return array(
|
||||||
|
($daemon) ? $daemon : null,
|
||||||
|
($daemon) ? json_decode($daemon->value, true) : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshToken() {
|
||||||
|
return Security::generateRandomString(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
function manageSession($action) {
|
||||||
|
switch ($action) {
|
||||||
|
case 'start':
|
||||||
|
if(session_id()) {
|
||||||
|
session_write_close();
|
||||||
|
}
|
||||||
|
session_id($this->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)
|
||||||
|
|
||||||
|
);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
function abortWithError($error) {
|
||||||
|
wp_send_json(
|
||||||
|
array(
|
||||||
|
'result' => false,
|
||||||
|
'error' => $error
|
||||||
|
));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
89
lib/Queue/Supervisor.php
Normal file
89
lib/Queue/Supervisor.php
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Queue;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use MailPoet\Config\Env;
|
||||||
|
use MailPoet\Models\Setting;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class Supervisor {
|
||||||
|
function __construct($forceStart = false) {
|
||||||
|
$this->forceStart = $forceStart;
|
||||||
|
if(!Env::isPluginActivated()) {
|
||||||
|
throw new \Exception('Database has not been configured.');
|
||||||
|
}
|
||||||
|
list ($this->daemon, $this->daemonData) = $this->getDaemon();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkDaemon() {
|
||||||
|
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) return;
|
||||||
|
if(!$this->daemon) {
|
||||||
|
return $this->startDaemon();
|
||||||
|
} else {
|
||||||
|
if(!$this->forceStart && ($this->daemonData['status'] === 'paused' ||
|
||||||
|
$this->daemonData['status'] === 'stopped'
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$currentTime = Carbon::now('UTC');
|
||||||
|
$lastUpdateTime = Carbon::createFromFormat(
|
||||||
|
'Y-m-d H:i:s',
|
||||||
|
$this->daemon->updated_at, 'UTC'
|
||||||
|
);
|
||||||
|
$timeSinceLastStart = $currentTime->diffInSeconds($lastUpdateTime);
|
||||||
|
if($timeSinceLastStart < 50) return;
|
||||||
|
$this->daemonData['status'] = 'paused';
|
||||||
|
$this->daemon->value = json_encode($this->daemonData);
|
||||||
|
$this->daemon->save();
|
||||||
|
return $this->startDaemon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startDaemon() {
|
||||||
|
if(!session_id()) session_start();
|
||||||
|
$sessionId = session_id();
|
||||||
|
session_write_close();
|
||||||
|
$_SESSION['daemon'] = null;
|
||||||
|
$payload = json_encode(array('session' => $sessionId));
|
||||||
|
self::getRemoteUrl(
|
||||||
|
'/?mailpoet-api§ion=queue&action=start&payload=' . urlencode($payload)
|
||||||
|
);
|
||||||
|
session_start();
|
||||||
|
$daemonStatus = $_SESSION['daemon'];
|
||||||
|
unset($_SESSION['daemon']);
|
||||||
|
session_write_close();
|
||||||
|
return $daemonStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDaemon() {
|
||||||
|
$daemon = Setting::where('name', 'daemon')
|
||||||
|
->findOne();
|
||||||
|
$daemonData = ($daemon) ? json_decode($daemon->value, true) : false;
|
||||||
|
return array(
|
||||||
|
$daemon,
|
||||||
|
$daemonData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getRemoteUrl($url) {
|
||||||
|
$args = array(
|
||||||
|
'timeout' => 1,
|
||||||
|
'user-agent' => 'MailPoet (www.mailpoet.com)'
|
||||||
|
);
|
||||||
|
wp_remote_get(
|
||||||
|
self::getSiteUrl() . $url,
|
||||||
|
$args
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getSiteUrl() {
|
||||||
|
if(preg_match('!:\d+/!', site_url())) return site_url();
|
||||||
|
preg_match('!http://(?P<host>.*?):(?P<port>\d+)!', site_url(), $server);
|
||||||
|
$fp = @fsockopen($server['host'], $server['port'], $errno, $errstr, 1);
|
||||||
|
return ($fp) ?
|
||||||
|
site_url() :
|
||||||
|
preg_replace('/(?=:\d+):\d+/', '$1', site_url());
|
||||||
|
}
|
||||||
|
}
|
62
lib/Queue/Worker.php
Normal file
62
lib/Queue/Worker.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Queue;
|
||||||
|
|
||||||
|
use MailPoet\Models\Newsletter;
|
||||||
|
use MailPoet\Models\NewsletterStatistics;
|
||||||
|
use MailPoet\Models\Queue;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class Worker {
|
||||||
|
function __construct($timer = false) {
|
||||||
|
$this->timer = $timer;
|
||||||
|
$this->timer = microtime(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function process() {
|
||||||
|
$queues =
|
||||||
|
Queue::orderByDesc('priority')
|
||||||
|
->whereNotIn('status', array(
|
||||||
|
'paused',
|
||||||
|
'completed'
|
||||||
|
))
|
||||||
|
->findResultSet();
|
||||||
|
foreach ($queues as $queue) {
|
||||||
|
$newsletter = Newsletter::findOne($queue->newsletter_id)
|
||||||
|
->asArray();
|
||||||
|
$subscribers = json_decode($queue->subscribers, true);
|
||||||
|
if(!isset($subscribers['failed'])) $subscribers['failed'] = array();
|
||||||
|
if(!isset($subscribers['processed'])) $subscribers['processed'] = array();
|
||||||
|
$subscribersToProcess = $subscribers['to_process'];
|
||||||
|
foreach ($subscribersToProcess as $subscriber) {
|
||||||
|
$elapsedTime = microtime(true) - $this->timer;
|
||||||
|
if($elapsedTime >= 28) break;
|
||||||
|
// TODO: hook up to mailer
|
||||||
|
sleep(1);
|
||||||
|
$newsletterStatistics = NewsletterStatistics::create();
|
||||||
|
$newsletterStatistics->subscriber_id = $subscriber;
|
||||||
|
$newsletterStatistics->newsletter_id = $newsletter['id'];
|
||||||
|
$newsletterStatistics->queue_id = $queue->id;
|
||||||
|
$newsletterStatistics->save();
|
||||||
|
$subscribers['processed'][] = $subscriber;
|
||||||
|
$subscribers['to_process'] = array_values(
|
||||||
|
array_diff(
|
||||||
|
$subscribers['to_process'],
|
||||||
|
$subscribers['processed']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$queue->count_processed = count($subscribers['processed']);
|
||||||
|
$queue->count_to_process = count($subscribers['to_process']);
|
||||||
|
$queue->count_failed = count($subscribers['failed']);
|
||||||
|
$queue->count_total =
|
||||||
|
$queue->count_processed + $queue->count_to_process + $queue->count_failed;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
lib/Router/Queue.php
Normal file
51
lib/Router/Queue.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Router;
|
||||||
|
|
||||||
|
use MailPoet\Models\Setting;
|
||||||
|
use MailPoet\Queue\Daemon;
|
||||||
|
use MailPoet\Queue\Supervisor;
|
||||||
|
|
||||||
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
|
class Queue {
|
||||||
|
function start() {
|
||||||
|
$supervisor = new Supervisor();
|
||||||
|
wp_send_json(
|
||||||
|
array(
|
||||||
|
'result' => ($supervisor->checkDaemon($forceStart = true)) ?
|
||||||
|
true :
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function update($data) {
|
||||||
|
switch ($data['action']) {
|
||||||
|
case 'stop':
|
||||||
|
$status = 'stopped';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$status = 'paused';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$daemon = new Daemon();
|
||||||
|
if(!$daemon->daemon || $daemon->daemonData['status'] !== 'started') {
|
||||||
|
$result = false;
|
||||||
|
} else {
|
||||||
|
$daemon->daemonData['status'] = $status;
|
||||||
|
$daemon->daemon->value = json_encode($daemon->daemonData);
|
||||||
|
$result = $daemon->daemon->save();
|
||||||
|
}
|
||||||
|
wp_send_json(
|
||||||
|
array(
|
||||||
|
'result' => $result
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getQueueStatus() {
|
||||||
|
$daemon = new \MailPoet\Queue\BootStrapMenu();
|
||||||
|
wp_send_json($daemon->bootStrap());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,9 @@
|
|||||||
namespace MailPoet\Router;
|
namespace MailPoet\Router;
|
||||||
use \MailPoet\Models\Segment;
|
use \MailPoet\Models\Segment;
|
||||||
use \MailPoet\Models\SubscriberSegment;
|
use \MailPoet\Models\SubscriberSegment;
|
||||||
|
use \MailPoet\Models\SegmentFilter;
|
||||||
use \MailPoet\Listing;
|
use \MailPoet\Listing;
|
||||||
|
use \MailPoet\Segments\WP;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
@ -42,15 +44,15 @@ class Segments {
|
|||||||
'subscribers'
|
'subscribers'
|
||||||
)
|
)
|
||||||
->select_expr(
|
->select_expr(
|
||||||
'SUM(CASE status WHEN "subscribed" THEN 1 ELSE 0 END)',
|
'SUM(CASE subscribers.status WHEN "subscribed" THEN 1 ELSE 0 END)',
|
||||||
'subscribed'
|
'subscribed'
|
||||||
)
|
)
|
||||||
->select_expr(
|
->select_expr(
|
||||||
'SUM(CASE status WHEN "unsubscribed" THEN 1 ELSE 0 END)',
|
'SUM(CASE subscribers.status WHEN "unsubscribed" THEN 1 ELSE 0 END)',
|
||||||
'unsubscribed'
|
'unsubscribed'
|
||||||
)
|
)
|
||||||
->select_expr(
|
->select_expr(
|
||||||
'SUM(CASE status WHEN "unconfirmed" THEN 1 ELSE 0 END)',
|
'SUM(CASE subscribers.status WHEN "unconfirmed" THEN 1 ELSE 0 END)',
|
||||||
'unconfirmed'
|
'unconfirmed'
|
||||||
)
|
)
|
||||||
->findOne()->asArray();
|
->findOne()->asArray();
|
||||||
@ -135,6 +137,12 @@ class Segments {
|
|||||||
wp_send_json($result);
|
wp_send_json($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function synchronize() {
|
||||||
|
$result = WP::synchronizeUsers();
|
||||||
|
|
||||||
|
wp_send_json($result);
|
||||||
|
}
|
||||||
|
|
||||||
function bulkAction($data = array()) {
|
function bulkAction($data = array()) {
|
||||||
$bulk_action = new Listing\BulkAction(
|
$bulk_action = new Listing\BulkAction(
|
||||||
'\MailPoet\Models\Segment',
|
'\MailPoet\Models\Segment',
|
||||||
|
88
lib/Segments/WP.php
Normal file
88
lib/Segments/WP.php
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Segments;
|
||||||
|
use \MailPoet\Models\Subscriber;
|
||||||
|
use \MailPoet\Models\Segment;
|
||||||
|
|
||||||
|
class WP {
|
||||||
|
static function synchronizeUser($wp_user_id) {
|
||||||
|
$wpUser = \get_userdata($wp_user_id);
|
||||||
|
if($wpUser === false) return;
|
||||||
|
|
||||||
|
$subscriber = Subscriber::where('wp_user_id', $wpUser->ID)
|
||||||
|
->findOne();
|
||||||
|
|
||||||
|
switch(current_filter()) {
|
||||||
|
case 'delete_user':
|
||||||
|
case 'deleted_user':
|
||||||
|
case 'remove_user_from_blog':
|
||||||
|
if($subscriber !== false && $subscriber->id()) {
|
||||||
|
$subscriber->delete();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'user_register':
|
||||||
|
case 'added_existing_user':
|
||||||
|
case 'profile_update':
|
||||||
|
default:
|
||||||
|
// get first name & last name
|
||||||
|
$first_name = $wpUser->first_name;
|
||||||
|
$last_name = $wpUser->last_name;
|
||||||
|
if(empty($wpUser->first_name) && empty($wpUser->last_name)) {
|
||||||
|
$first_name = $wpUser->display_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscriber data
|
||||||
|
$data = array(
|
||||||
|
'wp_user_id'=> $wpUser->ID,
|
||||||
|
'email' => $wpUser->user_email,
|
||||||
|
'first_name' => $first_name,
|
||||||
|
'last_name' => $last_name,
|
||||||
|
'status' => 'subscribed'
|
||||||
|
);
|
||||||
|
|
||||||
|
if($subscriber !== false) {
|
||||||
|
$data['id'] = $subscriber->id();
|
||||||
|
}
|
||||||
|
$subscriber = Subscriber::createOrUpdate($data);
|
||||||
|
|
||||||
|
if($subscriber !== false && $subscriber->id()) {
|
||||||
|
$segment = Segment::getWPUsers();
|
||||||
|
$segment->addSubscriber($subscriber->id());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function synchronizeUsers() {
|
||||||
|
// get wordpress users list
|
||||||
|
$segment = Segment::getWPUsers();
|
||||||
|
|
||||||
|
// count WP users
|
||||||
|
$users_count = \count_users()['total_users'];
|
||||||
|
$linked_subscribers_count = $segment->subscribers()->count();
|
||||||
|
|
||||||
|
if($users_count !== $linked_subscribers_count) {
|
||||||
|
$linked_subscribers = Subscriber::select('wp_user_id')
|
||||||
|
->whereNotNull('wp_user_id')
|
||||||
|
->findArray();
|
||||||
|
|
||||||
|
$exclude_ids = array();
|
||||||
|
if(!empty($linked_subscribers)) {
|
||||||
|
$exclude_ids = array_map(function($subscriber) {
|
||||||
|
return $subscriber['wp_user_id'];
|
||||||
|
}, $linked_subscribers);
|
||||||
|
}
|
||||||
|
|
||||||
|
$users = \get_users(array(
|
||||||
|
'count_total' => false,
|
||||||
|
'fields' => 'ID',
|
||||||
|
'exclude' => $exclude_ids
|
||||||
|
));
|
||||||
|
|
||||||
|
foreach($users as $user) {
|
||||||
|
static::synchronizeUser($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,6 @@ use MailPoet\Models\SubscriberSegment;
|
|||||||
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
||||||
use MailPoet\Util\Helpers;
|
use MailPoet\Util\Helpers;
|
||||||
use MailPoet\Util\XLSXWriter;
|
use MailPoet\Util\XLSXWriter;
|
||||||
use Symfony\Component\Console\Helper\Helper;
|
|
||||||
|
|
||||||
class Export {
|
class Export {
|
||||||
public function __construct($data) {
|
public function __construct($data) {
|
||||||
@ -93,7 +92,12 @@ class Export {
|
|||||||
);
|
);
|
||||||
$lastSegment = $subscriber['segment_name'];
|
$lastSegment = $subscriber['segment_name'];
|
||||||
}
|
}
|
||||||
$writer->writeSheet(array_merge($headerRow, $rows), 'MailPoet');
|
$writer->writeSheet(
|
||||||
|
array_merge($headerRow, $rows),
|
||||||
|
($this->groupBySegmentOption) ?
|
||||||
|
ucwords($subscriber['segment_name']) :
|
||||||
|
'MailPoet'
|
||||||
|
);
|
||||||
$writer->writeToFile($this->exportFile);
|
$writer->writeToFile($this->exportFile);
|
||||||
}
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
@ -155,6 +159,8 @@ class Export {
|
|||||||
$subscribers =
|
$subscribers =
|
||||||
$subscribers->where(Subscriber::$_table . '.status', 'subscribed');
|
$subscribers->where(Subscriber::$_table . '.status', 'subscribed');
|
||||||
}
|
}
|
||||||
|
$subscribers = $subscribers->whereNull(Subscriber::$_table . '.deleted_at');
|
||||||
|
|
||||||
return $subscribers->findArray();
|
return $subscribers->findArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Subscribers\ImportExport\Import;
|
namespace MailPoet\Subscribers\ImportExport\Import;
|
||||||
|
|
||||||
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
|
||||||
use MailPoet\Models\Subscriber;
|
use MailPoet\Models\Subscriber;
|
||||||
use MailPoet\Models\SubscriberCustomField;
|
use MailPoet\Models\SubscriberCustomField;
|
||||||
use MailPoet\Models\SubscriberSegment;
|
use MailPoet\Models\SubscriberSegment;
|
||||||
|
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
||||||
use MailPoet\Util\Helpers;
|
use MailPoet\Util\Helpers;
|
||||||
|
|
||||||
class Import {
|
class Import {
|
||||||
@ -27,7 +27,9 @@ class Import {
|
|||||||
$subscriberFields = $this->subscriberFields;
|
$subscriberFields = $this->subscriberFields;
|
||||||
$subscriberCustomFields = $this->subscriberCustomFields;
|
$subscriberCustomFields = $this->subscriberCustomFields;
|
||||||
$subscribersData = $this->subscribersData;
|
$subscribersData = $this->subscribersData;
|
||||||
$subscribersData = $this->filterSubscriberStatus($subscribersData);
|
list ($subscribersData, $subscriberFields) =
|
||||||
|
$this->filterSubscriberStatus($subscribersData, $subscriberFields);
|
||||||
|
$this->deleteExistingTrashedSubscribers($subscribersData);
|
||||||
list($subscribersData, $subscriberFields) = $this->extendSubscribersAndFields(
|
list($subscribersData, $subscriberFields) = $this->extendSubscribersAndFields(
|
||||||
$subscribersData, $subscriberFields
|
$subscribersData, $subscriberFields
|
||||||
);
|
);
|
||||||
@ -48,7 +50,7 @@ class Import {
|
|||||||
$updatedSubscribers =
|
$updatedSubscribers =
|
||||||
$this->createOrUpdateSubscribers(
|
$this->createOrUpdateSubscribers(
|
||||||
'update',
|
'update',
|
||||||
$existingSubscribers,
|
$existingSubscribers,
|
||||||
$subscriberFields,
|
$subscriberFields,
|
||||||
$subscriberCustomFields
|
$subscriberCustomFields
|
||||||
);
|
);
|
||||||
@ -84,6 +86,7 @@ class Import {
|
|||||||
array_map(function ($subscriberEmails) {
|
array_map(function ($subscriberEmails) {
|
||||||
return Subscriber::selectMany(array('email'))
|
return Subscriber::selectMany(array('email'))
|
||||||
->whereIn('email', $subscriberEmails)
|
->whereIn('email', $subscriberEmails)
|
||||||
|
->whereNull('deleted_at')
|
||||||
->findArray();
|
->findArray();
|
||||||
}, array_chunk($subscribersData['email'], 200))
|
}, array_chunk($subscribersData['email'], 200))
|
||||||
);
|
);
|
||||||
@ -131,6 +134,25 @@ class Import {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteExistingTrashedSubscribers($subscribersData) {
|
||||||
|
$existingTrashedRecords = array_filter(
|
||||||
|
array_map(function ($subscriberEmails) {
|
||||||
|
return Subscriber::selectMany(array('id'))
|
||||||
|
->whereIn('email', $subscriberEmails)
|
||||||
|
->whereNotNull('deleted_at')
|
||||||
|
->findArray();
|
||||||
|
}, array_chunk($subscribersData['email'], 200))
|
||||||
|
);
|
||||||
|
if(!$existingTrashedRecords) return;
|
||||||
|
$existingTrashedRecords = Helpers::flattenArray($existingTrashedRecords);
|
||||||
|
foreach (array_chunk($existingTrashedRecords, 200) as $subscriberIds) {
|
||||||
|
Subscriber::whereIn('id', $subscriberIds)
|
||||||
|
->deleteMany();
|
||||||
|
SubscriberSegment::whereIn('subscriber_id', $subscriberIds)
|
||||||
|
->deleteMany();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function extendSubscribersAndFields($subscribersData, $subscriberFields) {
|
function extendSubscribersAndFields($subscribersData, $subscriberFields) {
|
||||||
$subscribersData['created_at'] = $this->filterSubscriberCreatedAtDate();
|
$subscribersData['created_at'] = $this->filterSubscriberCreatedAtDate();
|
||||||
$subscriberFields[] = 'created_at';
|
$subscriberFields[] = 'created_at';
|
||||||
@ -164,8 +186,16 @@ class Import {
|
|||||||
return array_fill(0, $this->subscribersCount, $this->currentTime);
|
return array_fill(0, $this->subscribersCount, $this->currentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterSubscriberStatus($subscribersData) {
|
function filterSubscriberStatus($subscribersData, $subscriberFields) {
|
||||||
if(!in_array('status', $this->subscriberFields)) return $subscribersData;
|
if(!in_array('status', $subscriberFields)) {
|
||||||
|
$subscribersData['status'] =
|
||||||
|
array_fill(0, count($subscribersData['email']), 'subscribed');
|
||||||
|
$subscriberFields[] = 'status';
|
||||||
|
return array(
|
||||||
|
$subscribersData,
|
||||||
|
$subscriberFields
|
||||||
|
);
|
||||||
|
}
|
||||||
$statuses = array(
|
$statuses = array(
|
||||||
'subscribed' => array(
|
'subscribed' => array(
|
||||||
'subscribed',
|
'subscribed',
|
||||||
@ -198,7 +228,10 @@ class Import {
|
|||||||
}
|
}
|
||||||
return 'subscribed'; // make "subscribed" a default status
|
return 'subscribed'; // make "subscribed" a default status
|
||||||
}, $subscribersData['status']);
|
}, $subscribersData['status']);
|
||||||
return $subscribersData;
|
return array(
|
||||||
|
$subscribersData,
|
||||||
|
$subscriberFields
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createOrUpdateSubscribers(
|
function createOrUpdateSubscribers(
|
||||||
|
@ -76,12 +76,18 @@ class Helpers {
|
|||||||
static function getMaxPostSize($bytes = false) {
|
static function getMaxPostSize($bytes = false) {
|
||||||
$maxPostSize = ini_get('post_max_size');
|
$maxPostSize = ini_get('post_max_size');
|
||||||
if(!$bytes) return $maxPostSize;
|
if(!$bytes) return $maxPostSize;
|
||||||
switch (substr ($maxPostSize, -1))
|
switch (substr($maxPostSize, -1)) {
|
||||||
{
|
case 'M':
|
||||||
case 'M': case 'm': return (int)$maxPostSize * 1048576;
|
case 'm':
|
||||||
case 'K': case 'k': return (int)$maxPostSize * 1024;
|
return (int) $maxPostSize * 1048576;
|
||||||
case 'G': case 'g': return (int)$maxPostSize * 1073741824;
|
case 'K':
|
||||||
default: return $maxPostSize;
|
case 'k':
|
||||||
|
return (int) $maxPostSize * 1024;
|
||||||
|
case 'G':
|
||||||
|
case 'g':
|
||||||
|
return (int) $maxPostSize * 1073741824;
|
||||||
|
default:
|
||||||
|
return $maxPostSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,4 +170,18 @@ class Helpers {
|
|||||||
}
|
}
|
||||||
return $resultArray;
|
return $resultArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function underscoreToCamelCase($str, $capitalise_first_char = false) {
|
||||||
|
if($capitalise_first_char) {
|
||||||
|
$str[0] = strtoupper($str[0]);
|
||||||
|
}
|
||||||
|
$func = create_function('$c', 'return strtoupper($c[1]);');
|
||||||
|
return preg_replace_callback('/_([a-z])/', $func, $str);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function camelCaseToUnderscore($str) {
|
||||||
|
$str[0] = strtolower($str[0]);
|
||||||
|
$func = create_function('$c', 'return "_" . strtolower($c[1]);');
|
||||||
|
return preg_replace_callback('/([A-Z])/', $func, $str);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,8 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Util;
|
namespace MailPoet\Util;
|
||||||
|
|
||||||
|
require_once(ABSPATH . 'wp-includes/pluggable.php');
|
||||||
|
|
||||||
class Security {
|
class Security {
|
||||||
static function generateToken() {
|
static function generateToken() {
|
||||||
return wp_create_nonce('mailpoet_token');
|
return wp_create_nonce('mailpoet_token');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static function generateRandomString($length) {
|
||||||
|
return substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, $length);
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,7 +5,8 @@
|
|||||||
},
|
},
|
||||||
"napa": {
|
"napa": {
|
||||||
"blob": "eligrey/Blob.js.git",
|
"blob": "eligrey/Blob.js.git",
|
||||||
"filesaver": "eligrey/FileSaver.js.git"
|
"filesaver": "eligrey/FileSaver.js.git",
|
||||||
|
"sticky-kit": "leafo/sticky-kit.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"backbone": "1.2.3",
|
"backbone": "1.2.3",
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
|
||||||
use MailPoet\Models\CustomField;
|
use MailPoet\Models\CustomField;
|
||||||
use MailPoet\Models\Segment;
|
use MailPoet\Models\Segment;
|
||||||
use MailPoet\Models\Subscriber;
|
use MailPoet\Models\Subscriber;
|
||||||
use MailPoet\Models\SubscriberSegment;
|
use MailPoet\Models\SubscriberSegment;
|
||||||
|
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
||||||
|
|
||||||
class BootStrapMenuCest {
|
class BootStrapMenuCest {
|
||||||
function _before() {
|
function _before() {
|
||||||
@ -22,13 +22,13 @@ class BootStrapMenuCest {
|
|||||||
array(
|
array(
|
||||||
'first_name' => 'John',
|
'first_name' => 'John',
|
||||||
'last_name' => 'Mailer',
|
'last_name' => 'Mailer',
|
||||||
'status' => 0,
|
'status' => 'unconfirmed',
|
||||||
'email' => 'john@mailpoet.com'
|
'email' => 'john@mailpoet.com'
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'first_name' => 'Mike',
|
'first_name' => 'Mike',
|
||||||
'last_name' => 'Smith',
|
'last_name' => 'Smith',
|
||||||
'status' => 1,
|
'status' => 'subscribed',
|
||||||
'email' => 'mike@maipoet.com'
|
'email' => 'mike@maipoet.com'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -52,6 +52,28 @@ class BootStrapMenuCest {
|
|||||||
expect($segments[1]['subscriberCount'])->equals(1);
|
expect($segments[1]['subscriberCount'])->equals(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function itCanGetSegmentsForImportWithoutTrashedSubscribers() {
|
||||||
|
$this->_createSegmentsAndSubscribers();
|
||||||
|
$segments = $this->bootStrapImportMenu->getSegments();
|
||||||
|
expect(count($segments))->equals(2);
|
||||||
|
$subscriber = Subscriber::findOne(1);
|
||||||
|
$subscriber->deleted_at = date('Y-m-d H:i:s');
|
||||||
|
$subscriber->save();
|
||||||
|
$segments = $this->bootStrapImportMenu->getSegments();
|
||||||
|
expect(count($segments))->equals(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function itCanGetSegmentsForExportWithoutTrashedSubscribers() {
|
||||||
|
$this->_createSegmentsAndSubscribers();
|
||||||
|
$segments = $this->bootStrapExportMenu->getSegments();
|
||||||
|
expect(count($segments))->equals(2);
|
||||||
|
$subscriber = Subscriber::findOne(1);
|
||||||
|
$subscriber->deleted_at = date('Y-m-d H:i:s');
|
||||||
|
$subscriber->save();
|
||||||
|
$segments = $this->bootStrapExportMenu->getSegments();
|
||||||
|
expect(count($segments))->equals(1);
|
||||||
|
}
|
||||||
|
|
||||||
function itCanGetSegmentsForExport() {
|
function itCanGetSegmentsForExport() {
|
||||||
$this->_createSegmentsAndSubscribers();
|
$this->_createSegmentsAndSubscribers();
|
||||||
$segments = $this->bootStrapExportMenu->getSegments();
|
$segments = $this->bootStrapExportMenu->getSegments();
|
||||||
@ -270,13 +292,9 @@ class BootStrapMenuCest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _after() {
|
function _after() {
|
||||||
ORM::forTable(Subscriber::$_table)
|
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
|
||||||
->deleteMany();
|
ORM::raw_execute('TRUNCATE ' . Segment::$_table);
|
||||||
ORM::forTable(CustomField::$_table)
|
ORM::raw_execute('TRUNCATE ' . SubscriberSegment::$_table);
|
||||||
->deleteMany();
|
ORM::raw_execute('TRUNCATE ' . CustomField::$_table);
|
||||||
ORM::forTable(Segment::$_table)
|
|
||||||
->deleteMany();
|
|
||||||
ORM::forTable(SubscriberSegment::$_table)
|
|
||||||
->deleteMany();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -105,28 +105,39 @@ class ImportCest {
|
|||||||
expect($fields)->equals(array(39));
|
expect($fields)->equals(array(39));
|
||||||
}
|
}
|
||||||
|
|
||||||
function itCanFilterSubscriberState() {
|
function itCanFilterSubscriberStatus() {
|
||||||
$data = array(
|
$subscibersData = $this->subscribersData;
|
||||||
|
$subscriberFields = $this->subscriberFields;
|
||||||
|
list($subscibersData, $subsciberFields) =
|
||||||
|
$this->import->filterSubscriberStatus($subscibersData, $subscriberFields);
|
||||||
|
// subscribers' status was set to "subscribed" & status column was added
|
||||||
|
// to subscribers fields
|
||||||
|
expect(array_pop($subsciberFields))->equals('status');
|
||||||
|
expect($subscibersData['status'][0])->equals('subscribed');
|
||||||
|
expect(count($subscibersData['status']))->equals(2);
|
||||||
|
$subscriberFields[] = 'status';
|
||||||
|
$subscibersData = array(
|
||||||
'status' => array(
|
'status' => array(
|
||||||
//subscribed
|
#subscribed
|
||||||
'subscribed',
|
'subscribed',
|
||||||
'confirmed',
|
'confirmed',
|
||||||
1,
|
1,
|
||||||
'1',
|
'1',
|
||||||
'true',
|
'true',
|
||||||
//unconfirmed
|
#unconfirmed
|
||||||
'unconfirmed',
|
'unconfirmed',
|
||||||
0,
|
0,
|
||||||
"0",
|
"0",
|
||||||
//unsubscribed
|
#unsubscribed
|
||||||
'unsubscribed',
|
'unsubscribed',
|
||||||
-1,
|
-1,
|
||||||
'-1',
|
'-1',
|
||||||
'false'
|
'false'
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
$statuses = $this->import->filterSubscriberStatus($data);
|
list($subscibersData, $subsciberFields) =
|
||||||
expect($statuses)->equals(
|
$this->import->filterSubscriberStatus($subscibersData, $subscriberFields);
|
||||||
|
expect($subscibersData)->equals(
|
||||||
array(
|
array(
|
||||||
'status' => array(
|
'status' => array(
|
||||||
'subscribed',
|
'subscribed',
|
||||||
@ -170,6 +181,41 @@ class ImportCest {
|
|||||||
->equals($subscribersData['first_name'][1]);
|
->equals($subscribersData['first_name'][1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function itCanDeleteTrashedSubscribers() {
|
||||||
|
$subscribersData = $this->subscribersData;
|
||||||
|
$subscriberFields = $this->subscriberFields;
|
||||||
|
$subscribersData['deleted_at'] = array(
|
||||||
|
null,
|
||||||
|
date('Y-m-d H:i:s')
|
||||||
|
);
|
||||||
|
$subscriberFields[] = 'deleted_at';
|
||||||
|
$this->import->createOrUpdateSubscribers(
|
||||||
|
'create',
|
||||||
|
$subscribersData,
|
||||||
|
$subscriberFields,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
$dbSubscribers = Helpers::arrayColumn(
|
||||||
|
Subscriber::select('id')
|
||||||
|
->findArray(),
|
||||||
|
'id'
|
||||||
|
);
|
||||||
|
expect(count($dbSubscribers))->equals(2);
|
||||||
|
$this->import->addSubscribersToSegments(
|
||||||
|
$dbSubscribers,
|
||||||
|
$this->segments
|
||||||
|
);
|
||||||
|
$subscribersSegments = SubscriberSegment::findArray();
|
||||||
|
expect(count($subscribersSegments))->equals(4);
|
||||||
|
$this->import->deleteExistingTrashedSubscribers(
|
||||||
|
$subscribersData
|
||||||
|
);
|
||||||
|
$subscribersSegments = SubscriberSegment::findArray();
|
||||||
|
$dbSubscribers = Subscriber::findArray();
|
||||||
|
expect(count($subscribersSegments))->equals(2);
|
||||||
|
expect(count($dbSubscribers))->equals(1);
|
||||||
|
}
|
||||||
|
|
||||||
function itCanCreateOrUpdateCustomFields() {
|
function itCanCreateOrUpdateCustomFields() {
|
||||||
$subscribersData = $this->subscribersData;
|
$subscribersData = $this->subscribersData;
|
||||||
$this->import->createOrUpdateSubscribers(
|
$this->import->createOrUpdateSubscribers(
|
||||||
@ -231,6 +277,22 @@ class ImportCest {
|
|||||||
expect(count($subscribersSegments))->equals(4);
|
expect(count($subscribersSegments))->equals(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function itCanDeleteExistingTrashedSubscribers() {
|
||||||
|
$subscribersData = $this->subscribersData;
|
||||||
|
$subscriberFields = $this->subscriberFields;
|
||||||
|
$subscriberFields[] = 'deleted_at';
|
||||||
|
$subscribersData['deleted_at'] = array(
|
||||||
|
null,
|
||||||
|
date('Y-m-d H:i:s')
|
||||||
|
);
|
||||||
|
$this->import->createOrUpdateSubscribers(
|
||||||
|
'create',
|
||||||
|
$subscribersData,
|
||||||
|
$subscriberFields,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function itCanProcess() {
|
function itCanProcess() {
|
||||||
$import = clone($this->import);
|
$import = clone($this->import);
|
||||||
$result = $import->process();
|
$result = $import->process();
|
||||||
@ -253,11 +315,8 @@ class ImportCest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _after() {
|
function _after() {
|
||||||
ORM::forTable(Subscriber::$_table)
|
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
|
||||||
->deleteMany();
|
ORM::raw_execute('TRUNCATE ' . SubscriberSegment::$_table);
|
||||||
ORM::forTable(SubscriberCustomField::$_table)
|
ORM::raw_execute('TRUNCATE ' . SubscriberCustomField::$_table);
|
||||||
->deleteMany();
|
|
||||||
ORM::forTable(SubscriberSegment::$_table)
|
|
||||||
->deleteMany();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,9 +4,15 @@
|
|||||||
<h2 class="title">
|
<h2 class="title">
|
||||||
<span id="mailpoet_form_name"><%= form.name %></span>
|
<span id="mailpoet_form_name"><%= form.name %></span>
|
||||||
<input id="mailpoet_form_name_input" type="text" value="" style="display:none;" />
|
<input id="mailpoet_form_name_input" type="text" value="" style="display:none;" />
|
||||||
<span>
|
<a
|
||||||
<a id="mailpoet_form_edit_name" class="button" href="javascript:;"><%= __('Edit name' ) %></a>
|
id="mailpoet_form_edit_name"
|
||||||
</span>
|
class="add-new-h2"
|
||||||
|
href="javascript:;"
|
||||||
|
><%= __('Edit name' ) %></a>
|
||||||
|
<a
|
||||||
|
href="<%= admin_url('admin.php?page=mailpoet-forms') | raw %>"
|
||||||
|
class="add-new-h2"
|
||||||
|
><%= __('List of forms' ) %></a>
|
||||||
</h2>
|
</h2>
|
||||||
<% endblock %>
|
<% endblock %>
|
||||||
|
|
||||||
@ -42,7 +48,7 @@
|
|||||||
<div id="mailpoet_settings_segment_selection">
|
<div id="mailpoet_settings_segment_selection">
|
||||||
<!-- Form settings: list selection -->
|
<!-- Form settings: list selection -->
|
||||||
<p>
|
<p>
|
||||||
<strong><%= __('This form adds subscribers to these lists:') %></strong>
|
<strong><%= __('This form adds subscribers to these lists:') %></strong>
|
||||||
</p>
|
</p>
|
||||||
<select
|
<select
|
||||||
id="mailpoet_form_segments"
|
id="mailpoet_form_segments"
|
||||||
|
@ -57,12 +57,10 @@
|
|||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Text') %></div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Text') %></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<label>
|
<div class="mailpoet_form_field_input_option">
|
||||||
<div class="mailpoet_form_field_input_option">
|
<input type="text" name="background-color" class="mailpoet_field_button_background_color mailpoet_color" value="{{ model.styles.block.backgroundColor }}" />
|
||||||
<input type="text" name="background-color" class="mailpoet_field_button_background_color mailpoet_color" value="{{ model.styles.block.backgroundColor }}" />
|
</div>
|
||||||
</div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Background') %></div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Background') %></div>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<div class="mailpoet_form_field_input_option">
|
<div class="mailpoet_form_field_input_option">
|
||||||
|
@ -16,20 +16,16 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<label>
|
<div class="mailpoet_form_field_input_option">
|
||||||
<div class="mailpoet_form_field_input_option">
|
<input type="text" name="divider-color" class="mailpoet_field_divider_border_color mailpoet_color" value="{{ model.styles.block.borderColor }}" />
|
||||||
<input type="text" name="divider-color" class="mailpoet_field_divider_border_color mailpoet_color" value="{{ model.styles.block.borderColor }}" />
|
</div>
|
||||||
</div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Divider color') %></div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Divider color') %></div>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<label>
|
<div class="mailpoet_form_field_input_option">
|
||||||
<div class="mailpoet_form_field_input_option">
|
<input type="text" name="background-color" class="mailpoet_field_divider_background_color mailpoet_color" value="{{ model.styles.block.backgroundColor }}" />
|
||||||
<input type="text" name="background-color" class="mailpoet_field_divider_background_color mailpoet_color" value="{{ model.styles.block.backgroundColor }}" />
|
</div>
|
||||||
</div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Background') %></div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Background') %></div>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
{{#ifCond renderOptions.hideApplyToAll '!==' true}}
|
{{#ifCond renderOptions.hideApplyToAll '!==' true}}
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
|
@ -1,29 +1,25 @@
|
|||||||
<h3><%= __('Footer') %></h3>
|
<h3><%= __('Footer') %></h3>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<label>
|
<div class="mailpoet_form_field_input_option">
|
||||||
<div class="mailpoet_form_field_input_option">
|
<input type="text" name="font-color" id="mailpoet_field_footer_text_color" class="mailpoet_field_footer_text_color mailpoet_color" value="{{ model.styles.text.fontColor }}" />
|
||||||
<input type="text" name="font-color" id="mailpoet_field_footer_text_color" class="mailpoet_field_footer_text_color mailpoet_color" value="{{ model.styles.text.fontColor }}" />
|
<select id="mailpoet_field_footer_text_font_family" name="font-family" class="mailpoet_select mailpoet_select_medium mailpoet_field_footer_text_font_family mailpoet_font_family">
|
||||||
<select id="mailpoet_field_footer_text_font_family" name="font-family" class="mailpoet_select mailpoet_select_medium mailpoet_field_footer_text_font_family mailpoet_font_family">
|
{{#each availableStyles.fonts}}
|
||||||
{{#each availableStyles.fonts}}
|
<option value="{{ this }}" {{#ifCond this '==' ../model.styles.text.fontFamily}}SELECTED{{/ifCond}}>{{ this }}</option>
|
||||||
<option value="{{ this }}" {{#ifCond this '==' ../model.styles.text.fontFamily}}SELECTED{{/ifCond}}>{{ this }}</option>
|
{{/each}}
|
||||||
{{/each}}
|
</select>
|
||||||
</select>
|
<select id="mailpoet_field_footer_text_size" name="font-size" class="mailpoet_select mailpoet_select_small mailpoet_field_footer_text_size mailpoet_font_size">
|
||||||
<select id="mailpoet_field_footer_text_size" name="font-size" class="mailpoet_select mailpoet_select_small mailpoet_field_footer_text_size mailpoet_font_size">
|
{{#each availableStyles.textSizes}}
|
||||||
{{#each availableStyles.textSizes}}
|
<option value="{{ this }}" {{#ifCond this '==' ../model.styles.text.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
||||||
<option value="{{ this }}" {{#ifCond this '==' ../model.styles.text.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
{{/each}}
|
||||||
{{/each}}
|
</select>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Text') %></div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Text') %></div>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<label>
|
<div class="mailpoet_form_field_input_option">
|
||||||
<div class="mailpoet_form_field_input_option">
|
<input type="text" class="mailpoet_color" size="6" maxlength="6" name="link-color" value="{{ model.styles.link.fontColor }}" id="mailpoet_field_footer_link_color" />
|
||||||
<input type="text" class="mailpoet_color" size="6" maxlength="6" name="link-color" value="{{ model.styles.link.fontColor }}" id="mailpoet_field_footer_link_color" />
|
</div>
|
||||||
</div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Links') %></div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Links') %></div>
|
|
||||||
</label>
|
|
||||||
<label>
|
<label>
|
||||||
<div class="mailpoet_form_field_checkbox_option mailpoet_option_offset_left_small">
|
<div class="mailpoet_form_field_checkbox_option mailpoet_option_offset_left_small">
|
||||||
<input type="checkbox" name="underline" value="underline" id="mailpoet_field_footer_link_underline" {{#ifCond model.styles.link.textDecoration '==' 'underline'}}CHECKED{{/ifCond}}/> <%= __('Underline') %>
|
<input type="checkbox" name="underline" value="underline" id="mailpoet_field_footer_link_underline" {{#ifCond model.styles.link.textDecoration '==' 'underline'}}CHECKED{{/ifCond}}/> <%= __('Underline') %>
|
||||||
@ -32,12 +28,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<label>
|
<div class="mailpoet_form_field_input_option">
|
||||||
<div class="mailpoet_form_field_input_option">
|
<input type="text" name="background-color" class="mailpoet_field_footer_background_color mailpoet_color" value="{{ model.styles.block.backgroundColor }}" />
|
||||||
<input type="text" name="background-color" class="mailpoet_field_footer_background_color mailpoet_color" value="{{ model.styles.block.backgroundColor }}" />
|
</div>
|
||||||
</div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Background') %></div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Background') %></div>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
|
@ -1,29 +1,25 @@
|
|||||||
<h3><%= __('Header') %></h3>
|
<h3><%= __('Header') %></h3>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<label>
|
<div class="mailpoet_form_field_input_option">
|
||||||
<div class="mailpoet_form_field_input_option">
|
<input type="text" name="font-color" id="mailpoet_field_header_text_color" class="mailpoet_field_header_text_color mailpoet_color" value="{{ model.styles.text.fontColor }}" />
|
||||||
<input type="text" name="font-color" id="mailpoet_field_header_text_color" class="mailpoet_field_header_text_color mailpoet_color" value="{{ model.styles.text.fontColor }}" />
|
<select id="mailpoet_field_header_text_font_family" name="font-family" class="mailpoet_select mailpoet_select_medium mailpoet_field_header_text_font_family mailpoet_font_family">
|
||||||
<select id="mailpoet_field_header_text_font_family" name="font-family" class="mailpoet_select mailpoet_select_medium mailpoet_field_header_text_font_family mailpoet_font_family">
|
{{#each availableStyles.fonts}}
|
||||||
{{#each availableStyles.fonts}}
|
<option value="{{ this }}" {{#ifCond this '==' ../model.styles.text.fontFamily}}SELECTED{{/ifCond}}>{{ this }}</option>
|
||||||
<option value="{{ this }}" {{#ifCond this '==' ../model.styles.text.fontFamily}}SELECTED{{/ifCond}}>{{ this }}</option>
|
{{/each}}
|
||||||
{{/each}}
|
</select>
|
||||||
</select>
|
<select id="mailpoet_field_header_text_size" name="font-size" class="mailpoet_select mailpoet_select_small mailpoet_field_header_text_size mailpoet_font_size">
|
||||||
<select id="mailpoet_field_header_text_size" name="font-size" class="mailpoet_select mailpoet_select_small mailpoet_field_header_text_size mailpoet_font_size">
|
{{#each availableStyles.textSizes}}
|
||||||
{{#each availableStyles.textSizes}}
|
<option value="{{ this }}" {{#ifCond this '==' ../model.styles.text.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
||||||
<option value="{{ this }}" {{#ifCond this '==' ../model.styles.text.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
{{/each}}
|
||||||
{{/each}}
|
</select>
|
||||||
</select>
|
</div>
|
||||||
</div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Text') %></div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Text') %></div>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<label>
|
<div class="mailpoet_form_field_input_option">
|
||||||
<div class="mailpoet_form_field_input_option">
|
<input type="text" class="mailpoet_color" size="6" maxlength="6" name="link-color" value="{{ model.styles.link.fontColor }}" id="mailpoet_field_header_link_color" />
|
||||||
<input type="text" class="mailpoet_color" size="6" maxlength="6" name="link-color" value="{{ model.styles.link.fontColor }}" id="mailpoet_field_header_link_color" />
|
</div>
|
||||||
</div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Links') %></div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Links') %></div>
|
|
||||||
</label>
|
|
||||||
<label>
|
<label>
|
||||||
<div class="mailpoet_form_field_checkbox_option mailpoet_option_offset_left_small">
|
<div class="mailpoet_form_field_checkbox_option mailpoet_option_offset_left_small">
|
||||||
<input type="checkbox" name="underline" value="underline" id="mailpoet_field_header_link_underline" {{#ifCond model.styles.link.textDecoration '==' 'underline'}}CHECKED{{/ifCond}}/> <%= __('Underline') %>
|
<input type="checkbox" name="underline" value="underline" id="mailpoet_field_header_link_underline" {{#ifCond model.styles.link.textDecoration '==' 'underline'}}CHECKED{{/ifCond}}/> <%= __('Underline') %>
|
||||||
@ -32,12 +28,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<label>
|
<div class="mailpoet_form_field_input_option">
|
||||||
<div class="mailpoet_form_field_input_option">
|
<input type="text" name="background-color" class="mailpoet_field_header_background_color mailpoet_color" value="{{ model.styles.block.backgroundColor }}" />
|
||||||
<input type="text" name="background-color" class="mailpoet_field_header_background_color mailpoet_color" value="{{ model.styles.block.backgroundColor }}" />
|
</div>
|
||||||
</div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Background') %></div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Background') %></div>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
<h3><%= __('Spacer') %></h3>
|
<h3><%= __('Spacer') %></h3>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<label>
|
<div class="mailpoet_form_field_input_option">
|
||||||
<div class="mailpoet_form_field_input_option">
|
<input type="text" name="background-color" class="mailpoet_field_spacer_background_color mailpoet_color" value="{{ styles.block.backgroundColor }}" />
|
||||||
<input type="text" name="background-color" class="mailpoet_field_spacer_background_color mailpoet_color" value="{{ styles.block.backgroundColor }}" />
|
</div>
|
||||||
</div>
|
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Background') %></div>
|
||||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_inline"><%= __('Background') %></div>
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
{{#each availableStyles.textSizes}}
|
{{#each availableStyles.textSizes}}
|
||||||
<option value="{{ this }}" {{#ifCond this '==' ../model.text.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
<option value="{{ this }}" {{#ifCond this '==' ../model.text.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</select> <label for="mailpoet_text_font_color"><%= __('Text') %></label>
|
</select> <%= __('Text') %>
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<span>
|
<span>
|
||||||
@ -30,7 +30,7 @@
|
|||||||
{{#each availableStyles.headingSizes}}
|
{{#each availableStyles.headingSizes}}
|
||||||
<option value="{{ this }}" {{#ifCond this '==' ../model.h1.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
<option value="{{ this }}" {{#ifCond this '==' ../model.h1.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</select> <label for="mailpoet_h1_font_color"><%= __('Heading 1') %></label>
|
</select> <%= __('Heading 1') %>
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<span>
|
<span>
|
||||||
@ -45,7 +45,7 @@
|
|||||||
{{#each availableStyles.headingSizes}}
|
{{#each availableStyles.headingSizes}}
|
||||||
<option value="{{ this }}" {{#ifCond this '==' ../model.h2.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
<option value="{{ this }}" {{#ifCond this '==' ../model.h2.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</select> <label for="mailpoet_h2_font_color"><%= __('Heading 2') %></label>
|
</select> <%= __('Heading 2') %>
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<span>
|
<span>
|
||||||
@ -60,23 +60,23 @@
|
|||||||
{{#each availableStyles.headingSizes}}
|
{{#each availableStyles.headingSizes}}
|
||||||
<option value="{{ this }}" {{#ifCond this '==' ../model.h3.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
<option value="{{ this }}" {{#ifCond this '==' ../model.h3.fontSize}}SELECTED{{/ifCond}}>{{ this }}</option>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</select> <label for="mailpoet_h3_font_color"><%= __('Heading 3') %></label>
|
</select> <%= __('Heading 3') %>
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<span>
|
<span>
|
||||||
<span><input type="text" class="mailpoet_color" size="6" maxlength="6" name="link-color" value="{{ model.link.fontColor }}" id="mailpoet_a_font_color"></span>
|
<span><input type="text" class="mailpoet_color" size="6" maxlength="6" name="link-color" value="{{ model.link.fontColor }}" id="mailpoet_a_font_color"></span>
|
||||||
</span><label for="mailpoet_a_font_color"><%= __('Links') %></label> <input type="checkbox" name="underline" value="underline" id="mailpoet_a_font_underline" {{#ifCond model.link.textDecoration '==' 'underline'}}CHECKED{{/ifCond}} class="mailpoet_option_offset_left_small"/> <%= __('Underline') %>
|
</span><%= __('Links') %> <label><input type="checkbox" name="underline" value="underline" id="mailpoet_a_font_underline" {{#ifCond model.link.textDecoration '==' 'underline'}}CHECKED{{/ifCond}} class="mailpoet_option_offset_left_small"/> <%= __('Underline') %></label>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<span>
|
<span>
|
||||||
<span><input type="text" class="mailpoet_color" size="6" maxlength="6" name="newsletter-color" value="{{ model.wrapper.backgroundColor }}" id="mailpoet_newsletter_background_color"></span>
|
<span><input type="text" class="mailpoet_color" size="6" maxlength="6" name="newsletter-color" value="{{ model.wrapper.backgroundColor }}" id="mailpoet_newsletter_background_color"></span>
|
||||||
</span><label for="mailpoet_newsletter_background_color"><%= __('Newsletter') %></label>
|
</span><%= __('Newsletter') %>
|
||||||
</div>
|
</div>
|
||||||
<div class="mailpoet_form_field">
|
<div class="mailpoet_form_field">
|
||||||
<span>
|
<span>
|
||||||
<span><input type="text" class="mailpoet_color" size="6" maxlength="6" name="background-color" value="{{ model.body.backgroundColor }}" id="mailpoet_background_color"></span>
|
<span><input type="text" class="mailpoet_color" size="6" maxlength="6" name="background-color" value="{{ model.body.backgroundColor }}" id="mailpoet_background_color"></span>
|
||||||
</span><label for="mailpoet_background_color"><%= __('Background') %></label>
|
</span><%= __('Background') %>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
10
views/queue.html
Normal file
10
views/queue.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<% extends 'layout.html' %>
|
||||||
|
|
||||||
|
<% block content %>
|
||||||
|
<div id="queue_container"></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
var queueDaemon = <%= daemon|raw %>
|
||||||
|
</script>
|
||||||
|
<% endblock %>
|
@ -123,7 +123,7 @@
|
|||||||
exportData = {
|
exportData = {
|
||||||
segments: segments.length || null,
|
segments: segments.length || null,
|
||||||
segmentsWithConfirmedSubscribers: segmentsWithConfirmedSubscribers.length || null,
|
segmentsWithConfirmedSubscribers: segmentsWithConfirmedSubscribers.length || null,
|
||||||
exportConfirmedOption: false,
|
exportConfirmedOption: true,
|
||||||
groupBySegmentOption: (segments.length > 1 || segmentsWithConfirmedSubscribers.length > 1) ? true : null
|
groupBySegmentOption: (segments.length > 1 || segmentsWithConfirmedSubscribers.length > 1) ? true : null
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
@ -1,5 +1,4 @@
|
|||||||
<% extends 'layout.html' %>
|
<% extends 'layout.html' %>
|
||||||
|
|
||||||
<% block content %>
|
<% block content %>
|
||||||
<div id="mailpoet_subscribers_import" class="wrap">
|
<div id="mailpoet_subscribers_import" class="wrap">
|
||||||
<h2 class="title">
|
<h2 class="title">
|
||||||
@ -7,11 +6,11 @@
|
|||||||
<a class="add-new-h2" href="?page=mailpoet-subscribers#/"><%= __('Back to list') %></a>
|
<a class="add-new-h2" href="?page=mailpoet-subscribers#/"><%= __('Back to list') %></a>
|
||||||
</h2>
|
</h2>
|
||||||
<!-- STEP 1: method selection -->
|
<!-- STEP 1: method selection -->
|
||||||
<% include 'import/step1.html' %>
|
<% include 'subscribers/importExport/import/step1.html' %>
|
||||||
<!-- STEP 2: subscriber data manipulation -->
|
<!-- STEP 2: subscriber data manipulation -->
|
||||||
<% include 'import/step2.html' %>
|
<% include 'subscribers/importExport/import/step2.html' %>
|
||||||
<!-- STEP 3: results -->
|
<!-- STEP 3: results -->
|
||||||
<% include 'import/step3.html' %>
|
<% include 'subscribers/importExport/import/step3.html' %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= stylesheet('importExport.css') %>
|
<%= stylesheet('importExport.css') %>
|
||||||
@ -64,6 +63,7 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var
|
var
|
||||||
maxPostSize = '<%= maxPostSize %>',
|
maxPostSize = '<%= maxPostSize %>',
|
||||||
|
maxPostSizeBytes = '<%= maxPostSizeBytes %>',
|
||||||
importData = {},
|
importData = {},
|
||||||
mailpoetColumnsSelect2 = <%= subscriberFieldsSelect2|raw %>,
|
mailpoetColumnsSelect2 = <%= subscriberFieldsSelect2|raw %>,
|
||||||
mailpoetColumns = <%= subscriberFields|raw %>,
|
mailpoetColumns = <%= subscriberFields|raw %>,
|
@ -29,7 +29,8 @@ baseConfig = {
|
|||||||
'blob$': 'blob/Blob.js',
|
'blob$': 'blob/Blob.js',
|
||||||
'filesaver$': 'filesaver/FileSaver.js',
|
'filesaver$': 'filesaver/FileSaver.js',
|
||||||
'papaparse': 'papaparse/papaparse.min.js',
|
'papaparse': 'papaparse/papaparse.min.js',
|
||||||
'helpscout': 'helpscout.js'
|
'helpscout': 'helpscout.js',
|
||||||
|
'html2canvas': 'html2canvas/dist/html2canvas.js'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
node: {
|
node: {
|
||||||
@ -73,6 +74,10 @@ baseConfig = {
|
|||||||
include: /helpscout.js$/,
|
include: /helpscout.js$/,
|
||||||
loader: 'exports-loader?window.HS',
|
loader: 'exports-loader?window.HS',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
include: /html2canvas.js$/,
|
||||||
|
loader: 'expose-loader?html2canvas',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -95,9 +100,10 @@ config.push(_.extend({}, baseConfig, {
|
|||||||
'segments/segments.jsx',
|
'segments/segments.jsx',
|
||||||
'forms/forms.jsx',
|
'forms/forms.jsx',
|
||||||
'settings/tabs.js',
|
'settings/tabs.js',
|
||||||
'import/import.js',
|
'subscribers/importExport/import.js',
|
||||||
'export/export.js',
|
'subscribers/importExport/export.js',
|
||||||
'helpscout'
|
'helpscout',
|
||||||
|
'queue.jsx'
|
||||||
],
|
],
|
||||||
form_editor: [
|
form_editor: [
|
||||||
'form_editor/form_editor.js',
|
'form_editor/form_editor.js',
|
||||||
|
Reference in New Issue
Block a user