- Updates DB query for custom fields

- Updates models and tests for Subscribers and CustomFields
This commit is contained in:
Marco
2015-10-16 15:52:37 +02:00
committed by MrCasual
54 changed files with 3123 additions and 280 deletions

View File

@ -12,3 +12,5 @@
@require 'box'
@require 'breadcrumb'
@require 'form'
@require 'settings'

View File

@ -16,3 +16,11 @@ a:focus
// hide elements
.mailpoet_hidden
display: none
// select 2
.select2-container
width: 25em
@media screen and (max-width: 782px)
.select2-container
width: 100% !important

View File

@ -1,2 +1,2 @@
.mailpoet_form td
vertical-align: top
vertical-align: top !important

View File

@ -180,9 +180,6 @@ handle_icon = '../img/handle.png'
margin: 0
/* edit form name */
h2.title
margin: 0 0 15px 0
#mailpoet_form_name_input
vertical-align: bottom

View File

@ -0,0 +1,70 @@
#mailpoet_settings
// common
.mailpoet_panel
display: none
.form-table th
width:20em
// advanced
#mailpoet_role_permissions
margin-top: 20px;
// sending methods
.mailpoet_sending_methods
margin 25px 0 0 0
li
float left
position relative
padding 15px 15px 0 15px
margin 0 25px 25px 0
width 300px
height 250px
border 1px solid #dedede
background-color #fff
h3
text-align center
height 54px
line-height 54px
font-size 1.5em
.mailpoet_description
line-height 1.5em
font-size 1.1em
.mailpoet_status
background-color #2f2f2f
color #fff
position absolute
bottom 0
left 0
right 0
text-overflow ellipsis
padding 15px
span
visibility hidden
font-weight bold
.mailpoet_active
.mailpoet_status
span
visibility visible
#mailpoet_mta_activate
visibility hidden
.mailpoet_actions
bottom 15px
color #fff
padding 0
position absolute
right 15px
.button-secondary
margin 0 -6px -4px 0
// responsive
@media screen and (max-width: 782px)
.form-table th
width: auto
.mailpoet_sending_methods
li
float none
width: auto
margin-right: 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@ -4,7 +4,8 @@ define([
'form/fields/textarea.jsx',
'form/fields/select.jsx',
'form/fields/radio.jsx',
'form/fields/checkbox.jsx'
'form/fields/checkbox.jsx',
'form/fields/selection.jsx'
],
function(
React,
@ -12,7 +13,8 @@ function(
FormFieldTextarea,
FormFieldSelect,
FormFieldRadio,
FormFieldCheckbox
FormFieldCheckbox,
FormFieldSelection
) {
var FormField = React.createClass({
renderField: function(data, inline = false) {
@ -26,29 +28,33 @@ function(
var field = false;
if(data.field['field'] !== undefined) {
field = data.field.field;
} else{
switch(data.field.type) {
case 'text':
field = (<FormFieldText {...data} />);
break;
data.field = jQuery.merge(data.field, data.field.field);
}
case 'textarea':
field = (<FormFieldTextarea {...data} />);
break;
switch(data.field.type) {
case 'text':
field = (<FormFieldText {...data} />);
break;
case 'select':
field = (<FormFieldSelect {...data} />);
break;
case 'textarea':
field = (<FormFieldTextarea {...data} />);
break;
case 'radio':
field = (<FormFieldRadio {...data} />);
break;
case 'select':
field = (<FormFieldSelect {...data} />);
break;
case 'checkbox':
field = (<FormFieldCheckbox {...data} />);
break;
}
case 'radio':
field = (<FormFieldRadio {...data} />);
break;
case 'checkbox':
field = (<FormFieldCheckbox {...data} />);
break;
case 'selection':
field = (<FormFieldSelection {...data} />);
break;
}
if(inline === true) {
@ -75,7 +81,8 @@ function(
return this.renderField({
index: index,
field: subfield,
item: this.props.item
item: this.props.item,
onValueChange: this.props.onValueChange || false
});
}.bind(this));
} else {

View File

@ -1,6 +1,7 @@
define([
'react',
'jquery'
'jquery',
'select2'
],
function(
React,
@ -9,43 +10,39 @@ function(
var Selection = React.createClass({
getInitialState: function() {
return {
loading: false,
items: [],
selected: []
items: []
}
},
componentWillMount: function() {
this.loadCachedItems();
},
componentDidMount: function() {
if(this.props.select2) {
jQuery('#'+this.props.id).select2({
width: '25em'
});
}
jQuery('#'+this.props.field.id).select2()
.on('change', this.handleChange);
},
loadCachedItems: function() {
if(typeof(window['mailpoet_'+this.props.endpoint]) !== 'undefined') {
var items = window['mailpoet_'+this.props.endpoint];
if(typeof(window['mailpoet_'+this.props.field.endpoint]) !== 'undefined') {
var items = window['mailpoet_'+this.props.field.endpoint];
this.setState({
items: items
});
}
},
handleChange: function() {
this.setState({
selected: jQuery('#'+this.props.id).val()
return this.props.onValueChange({
target: {
value: jQuery('#'+this.props.field.id).select2('val'),
name: this.props.field.name
}
});
},
getSelected: function() {
return this.state.selected;
},
render: function() {
var options = this.state.items.map(function(item, index) {
return (
<option
key={ 'action-' + index }
value={ item.id }>
key={ item.id }
value={ item.id }
>
{ item.name }
</option>
);
@ -54,12 +51,12 @@ function(
return (
<select
ref="selection"
id={ this.props.id || 'mailpoet_field_selection'}
placeholder={ this.props.placeholder }
multiple={ this.props.multiple }
>
{ options }
</select>
id={ this.props.field.id }
placeholder={ this.props.field.placeholder }
multiple={ this.props.field.multiple }
onChange={ this.handleChange }
defaultValue={ this.props.item[this.props.field.name] }
>{ options }</select>
);
}
});

View File

@ -80,7 +80,10 @@ define(
render: function() {
return (
<div>
<h1>Newsletters <Link className="add-new-h2" to="new">New</Link></h1>
<h2 className="title">
Newsletters <Link className="add-new-h2" to="new">New</Link>
</h2>
<Listing
endpoint="newsletters"
onRenderItem={this.renderItem}

View File

@ -24,7 +24,7 @@ define(
var App = React.createClass({
render: function() {
return (
<RouteHandler/>
<RouteHandler />
);
}
});

View File

@ -27,17 +27,14 @@ define(
type: 'text'
},
{
name: 'list',
name: 'segments',
label: 'Lists',
tip: "The subscriber list that will be used for this campaign.",
field: (
<Selection
placeholder="Select a list"
id="mailpoet_segments"
endpoint="segments"
multiple={ true }
select2={ true } />
)
type: 'selection',
placeholder: "Select a list",
id: "mailpoet_segments",
endpoint: "segments",
multiple: true
},
{
name: 'sender',

View File

@ -1,11 +1,13 @@
define(
[
'react',
'react-router',
'mailpoet',
'form/form.jsx'
],
function(
React,
Router,
MailPoet,
Form
) {
@ -27,15 +29,22 @@ define(
}
};
var Link = Router.Link;
var SegmentForm = React.createClass({
render: function() {
return (
<Form
endpoint="segments"
fields={ fields }
params={ this.props.params }
messages={ messages } />
<div>
<h2 className="title">
Segment <Link className="add-new-h2" to="/">Back to list</Link>
</h2>
<Form
endpoint="segments"
fields={ fields }
params={ this.props.params }
messages={ messages } />
</div>
);
}
});

View File

@ -1,11 +1,13 @@
define(
[
'react',
'react-router',
'listing/listing.jsx',
'classnames'
],
function(
React,
Router,
Listing,
classNames
) {
@ -34,6 +36,8 @@ define(
}
];
var Link = Router.Link;
var SegmentList = React.createClass({
renderItem: function(segment, actions) {
var rowClasses = classNames(
@ -61,11 +65,17 @@ define(
},
render: function() {
return (
<Listing
endpoint="segments"
onRenderItem={this.renderItem}
columns={columns}
bulk_actions={ bulk_actions } />
<div>
<h2 className="title">
Segments <Link className="add-new-h2" to="new">New</Link>
</h2>
<Listing
endpoint="segments"
onRenderItem={this.renderItem}
columns={columns}
bulk_actions={ bulk_actions } />
</div>
);
}
});

View File

@ -20,15 +20,7 @@ define(
var App = React.createClass({
render: function() {
return (
<div>
<h1>
{ MailPoetI18n.pageTitle }
&nbsp;
<Link className="add-new-h2" to="new">New</Link>
</h1>
<RouteHandler/>
</div>
<RouteHandler />
);
}
});

View File

@ -1,118 +0,0 @@
define('settings', ['react/addons', 'jquery', 'mailpoet'], function(React, jQuery, MailPoet) {
var SettingsForm = React.createClass({
mixins: [React.addons.LinkedStateMixin],
load: function() {
this.setState({ loading: true });
MailPoet.Ajax.post({
endpoint: 'settings',
action: 'get',
onSuccess: function(response) {
// index settings by key
var settings = {};
jQuery.each(response, function(i, setting) {
settings[setting.name] = setting.value;
});
this.setState({
loading: false,
settings: settings
});
}.bind(this)
});
},
handleSubmit: function(e) {
this.setState({ loading: true });
e.preventDefault();
// format data
var settings = [];
jQuery.each(this.state.settings, function(name, value) {
settings.push({
name: name,
value: value
});
});
MailPoet.Ajax.post({
endpoint: 'settings',
action: 'set',
data: settings,
onSuccess: function(response) {
this.setState({ loading: false });
}.bind(this)
})
},
getInitialState: function() {
return {
loading: false,
settings: {}
};
},
linkSettingValue: function(key) {
return {
value: this.state['settings'][key],
requestChange: function(newValue) {
var settings = this.state.settings;
settings[key] = newValue;
this.setState({ 'settings': settings });
}.bind(this)
};
},
componentDidMount: function() {
this.load();
},
render: function() {
return (
<form onSubmit={this.handleSubmit} className="mailpoet_settings_form">
<p>
<label>
From name:
<input
type="text"
valueLink={this.linkSettingValue('from_name')} />
</label>
</p>
<p>
<label>
From email:
<input
type="text"
valueLink={this.linkSettingValue('from_address')} />
</label>
</p>
<p>
<label>
API key:
<input
type="text"
valueLink={this.linkSettingValue('api_key')} />
</label>
</p>
<input
ref="submit"
type="submit"
className="button button-primary"
disabled={this.state.loading}
value="Save" />
</form>
);
}
});
var element = jQuery('#mailpoet_settings');
if(element.length > 0) {
React.render(
<SettingsForm />,
element[0]
);
}
});

View File

@ -0,0 +1,79 @@
define(
[
'backbone',
'jquery',
'mailpoet'
],
function(
Backbone,
jQuery,
MailPoet
) {
if(jQuery('#mailpoet_settings').length === 0) {
return;
}
MailPoet.Router = new (Backbone.Router.extend({
routes: {
'mta(/:method)': 'sendingMethod',
'(:tab)': 'tabs',
},
sendingMethod: function(method) {
// display mta tab
this.tabs('mta');
// hide all sending methods' settings
jQuery(
'#mailpoet_sending_method_setup, .mailpoet_sending_method'
).hide();
// hide "save settings" button
jQuery('.mailpoet_settings_submit').hide();
if(method === null) {
// show sending methods
jQuery('.mailpoet_sending_methods').fadeIn();
} else {
// hide DKIM option when using MailPoet's API
jQuery('#mailpoet_mta_dkim')[
(method === 'mailpoet')
? 'hide'
: 'show'
]();
// hide sending methods
jQuery('.mailpoet_sending_methods').hide();
// display selected sending method's settings
jQuery('.mailpoet_sending_method[data-method="'+ method +'"]').show();
jQuery('#mailpoet_sending_method_setup').fadeIn();
}
},
tabs: function(tab, section) {
// set default tab
tab = tab || 'basics';
// reset all active tabs
jQuery('.nav-tab-wrapper a').removeClass('nav-tab-active');
// hide panels & sections
jQuery('.mailpoet_panel, .mailpoet_section').hide();
// set active tab
jQuery('a.nav-tab[href="#'+tab+'"]').addClass('nav-tab-active').blur();
// show selected panel
if(jQuery('.mailpoet_panel[data-tab="'+ tab +'"]').length > 0) {
jQuery('.mailpoet_panel[data-tab="'+ tab +'"]').show();
}
// show "save settings" button
jQuery('.mailpoet_settings_submit').show();
}
}));
jQuery(document).ready(function() {
Backbone.history.start();
});
}
);

View File

@ -1,11 +1,13 @@
define(
[
'react',
'react-router',
'mailpoet',
'form/form.jsx'
],
function(
React,
Router,
MailPoet,
Form
) {
@ -47,15 +49,22 @@ define(
}
};
var Link = Router.Link;
var SubscriberForm = React.createClass({
render: function() {
return (
<Form
endpoint="subscribers"
fields={ fields }
params={ this.props.params }
messages={ messages } />
<div>
<h2 className="title">
Subscriber <Link className="add-new-h2" to="/">Back to list</Link>
</h2>
<Form
endpoint="subscribers"
fields={ fields }
params={ this.props.params }
messages={ messages } />
</div>
);
}
});

View File

@ -177,11 +177,17 @@ define(
},
render: function() {
return (
<Listing
endpoint="subscribers"
onRenderItem={ this.renderItem }
columns={ columns }
bulk_actions={ bulk_actions } />
<div>
<h2 className="title">
Subscribers <Link className="add-new-h2" to="new">New</Link>
</h2>
<Listing
endpoint="subscribers"
onRenderItem={ this.renderItem }
columns={ columns }
bulk_actions={ bulk_actions } />
</div>
);
}
});

View File

@ -20,15 +20,7 @@ define(
var App = React.createClass({
render: function() {
return (
<div>
<h1>
{ MailPoetI18n.pageTitle }
&nbsp;
<Link className="add-new-h2" to="new">New</Link>
</h1>
<RouteHandler/>
</div>
<RouteHandler />
);
}
});

20
composer.lock generated
View File

@ -755,16 +755,16 @@
},
{
"name": "guzzlehttp/promises",
"version": "1.0.2",
"version": "1.0.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "97fe7210def29451ec74923b27e552238defd75a"
"reference": "b1e1c0d55f8083c71eda2c28c12a228d708294ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/97fe7210def29451ec74923b27e552238defd75a",
"reference": "97fe7210def29451ec74923b27e552238defd75a",
"url": "https://api.github.com/repos/guzzle/promises/zipball/b1e1c0d55f8083c71eda2c28c12a228d708294ea",
"reference": "b1e1c0d55f8083c71eda2c28c12a228d708294ea",
"shasum": ""
},
"require": {
@ -802,7 +802,7 @@
"keywords": [
"promise"
],
"time": "2015-08-15 19:37:21"
"time": "2015-10-15 22:28:00"
},
{
"name": "guzzlehttp/psr7",
@ -1274,16 +1274,16 @@
},
{
"name": "phpunit/phpunit",
"version": "4.8.12",
"version": "4.8.13",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "00194eb95989190a73198390ceca081ad3441a7f"
"reference": "be067d6105286b74272facefc2697038f8807b77"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/00194eb95989190a73198390ceca081ad3441a7f",
"reference": "00194eb95989190a73198390ceca081ad3441a7f",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/be067d6105286b74272facefc2697038f8807b77",
"reference": "be067d6105286b74272facefc2697038f8807b77",
"shasum": ""
},
"require": {
@ -1342,7 +1342,7 @@
"testing",
"xunit"
],
"time": "2015-10-12 03:36:47"
"time": "2015-10-14 13:49:40"
},
{
"name": "phpunit/phpunit-mock-objects",

View File

@ -22,6 +22,7 @@ class Initializer {
$this->setupMenu();
$this->setupRouter();
$this->setupWidget();
$this->setupPermissions();
}
function setupDB() {
@ -86,4 +87,9 @@ class Initializer {
$widget = new Widget();
$widget->init();
}
function setupPermissions() {
$permissions = new Permissions();
$permissions->init();
}
}

View File

@ -2,6 +2,11 @@
namespace MailPoet\Config;
use \MailPoet\Models\Segment;
use \MailPoet\Models\Setting;
use \MailPoet\Settings\Hosts;
use \MailPoet\Settings\Pages;
use \MailPoet\Settings\Charsets;
use \MailPoet\Util\Permissions;
use \MailPoet\Util\DKIM;
if(!defined('ABSPATH')) exit;
@ -92,7 +97,56 @@ class Menu {
}
function settings() {
$data = array();
// flags (available features on WP install)
$flags = array();
if(is_multisite()) {
// get multisite registration option
$registration = apply_filters(
'wpmu_registration_enabled',
get_site_option('registration', 'all')
);
// check if users can register
$flags['registration_enabled'] =
!(in_array($registration, array('none', 'blog')));
} else {
// check if users can register
$flags['registration_enabled'] =
(bool)get_option('users_can_register', false);
}
$settings = Setting::getAll();
// dkim: check if public/private keys have been generated
if(
empty($settings['dkim'])
or empty($settings['dkim']['public_key'])
or empty($settings['dkim']['private_key'])
) {
// generate public/private keys
$keys = DKIM::generateKeys();
$settings['dkim'] = array(
'public_key' => $keys['public'],
'private_key' => $keys['private'],
'domain' => preg_replace('/^www\./', '', $_SERVER['SERVER_NAME'])
);
}
$data = array(
'settings' => $settings,
'segments' => Segment::findArray(),
'pages' => Pages::getAll(),
'flags' => $flags,
'charsets' => Charsets::getAll(),
'current_user' => wp_get_current_user(),
'permissions' => Permissions::getAll(),
'hosts' => array(
'web' => Hosts::getWebHosts(),
'smtp' => Hosts::getSMTPHosts()
)
);
echo $this->renderer->render('settings.html', $data);
}

View File

@ -139,6 +139,7 @@ class Migrator {
$attributes = array(
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
'name varchar(90) NOT NULL,',
'type varchar(90) NOT NULL,',
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
'PRIMARY KEY (id),',

View File

@ -0,0 +1,43 @@
<?php
namespace MailPoet\Config;
class Permissions {
function __construct() {
}
function init() {
add_action(
'admin_init',
array($this, 'setup')
);
}
function setup() {
// administrative roles
$roles = array('administrator', 'super_admin');
// mailpoet capabilities
$capabilities = array(
'mailpoet_newsletters',
'mailpoet_newsletter_styles',
'mailpoet_subscribers',
'mailpoet_settings',
'mailpoet_statistics'
);
foreach($roles as $role_key){
// get role based on role key
$role = get_role($role_key);
// if the role doesn't exist, skip it
if($role !== null) {
// add capability
foreach($capabilities as $capability) {
if(!$role->has_cap($capability)) {
$role->add_cap($capability);
}
}
}
}
}
}

View File

@ -12,11 +12,15 @@ class Renderer {
$file_system = new TwigFileSystem(Env::$views_path);
$this->renderer = new TwigEnv(
$file_system,
array('cache' => $this->detectCache())
array(
'cache' => $this->detectCache(),
'debug' => WP_DEBUG
)
);
}
function init() {
$this->setupDebug();
$this->setupTranslations();
$this->setupFunctions();
$this->setupHandlebars();
@ -46,7 +50,7 @@ class Renderer {
function setupSyntax() {
$lexer = new TwigLexer($this->renderer, array(
'tag_comment' => array('<%#', '%>'),
'tag_comment' => array('<#', '#>'),
'tag_block' => array('<%', '%>'),
'tag_variable' => array('<%=', '%>'),
'interpolation' => array('%{', '}')
@ -61,4 +65,10 @@ class Renderer {
}
return false;
}
function setupDebug() {
if(WP_DEBUG === true) {
$this->renderer->addExtension(new \Twig_Extension_Debug());
}
}
}

View File

@ -8,10 +8,12 @@ class CustomField extends Model {
function __construct() {
parent::__construct();
$this->addValidations('name', array(
'required' => __('You need to specify a name.')
));
$this->addValidations('type', array(
'required' => __('You need to specify a type.')
));
}
function subscribers() {
@ -20,6 +22,6 @@ class CustomField extends Model {
__NAMESPACE__ . '\SubscriberCustomField',
'custom_field_id',
'subscriber_id'
);
)->select_expr(MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.value');
}
}

View File

@ -107,7 +107,7 @@ class Newsletter extends Model {
$saved = $newsletter->save();
if($saved === true) {
return true;
return $newsletter->id();
} else {
$errors = $newsletter->getValidationErrors();
if(!empty($errors)) {

View File

@ -20,10 +20,29 @@ class Setting extends Model {
if($setting === false) {
return $default;
} else {
return $setting->value;
if(is_serialized($setting->value)) {
return unserialize($setting->value);
} else {
return $setting->value;
}
}
}
public static function getAll() {
$settingsCollection = self::findMany();
$settings = array();
if(!empty($settingsCollection)) {
foreach($settingsCollection as $setting) {
$value = (is_serialized($setting->value)
? unserialize($setting->value)
: $setting->value
);
$settings[$setting->name] = $value;
}
}
return $settings;
}
public static function createOrUpdate($model) {
$exists = self::where('name', $model['name'])
->find_one();

View File

@ -123,6 +123,29 @@ class Subscriber extends Model {
return $orm->where('status', $group);
}
static function withCustomFields($orm) {
$orm = $orm->select(MP_SUBSCRIBERS_TABLE.'.*');
$customFields = CustomField::findArray();
foreach ($customFields as $customField) {
$orm = $orm->select_expr(
'IFNULL(GROUP_CONCAT(CASE WHEN ' .
MP_CUSTOM_FIELDS_TABLE . '.id=' . $customField['id'] . ' THEN ' .
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value END), NULL) as ' .
$customField['name']);
}
$orm = $orm
->left_outer_join(
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE,
array(MP_SUBSCRIBERS_TABLE.'.id', '=',
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.subscriber_id'))
->left_outer_join(
MP_CUSTOM_FIELDS_TABLE,
array(MP_CUSTOM_FIELDS_TABLE.'.id','=',
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.custom_field_id'))
->group_by(MP_SUBSCRIBERS_TABLE.'.id');
return $orm;
}
function segments() {
return $this->has_many_through(
__NAMESPACE__.'\Segment',

View File

@ -8,6 +8,7 @@ use MailPoet\Models\Segment;
use MailPoet\Models\Setting;
use MailPoet\Models\Subscriber;
use MailPoet\Models\NewsletterTemplate;
use MailPoet\Models\NewsletterSegment;
use MailPoet\Newsletter\Renderer\Renderer;
if(!defined('ABSPATH')) exit;
@ -22,7 +23,12 @@ class Newsletters {
if($newsletter === false) {
wp_send_json(false);
} else {
wp_send_json($newsletter->asArray());
$segments = $newsletter->segments()->findArray();
$newsletter = $newsletter->asArray();
$newsletter['segments'] = array_map(function($segment) {
return $segment['id'];
}, $segments);
wp_send_json($newsletter);
}
}
@ -32,12 +38,26 @@ class Newsletters {
}
function save($data = array()) {
$result = Newsletter::createOrUpdate($data);
if($result !== true) {
wp_send_json($result);
} else {
wp_send_json(true);
if(isset($data['segments'])) {
$segment_ids = $data['segments'];
unset($data['segments']);
}
$newsletter_id = Newsletter::createOrUpdate($data);
if($newsletter_id !== false && !empty($segment_ids)) {
// remove previous relationships with segments
NewsletterSegment::where('newsletter_id', $newsletter_id)->deleteMany();
// create relationship with segments
foreach($segment_ids as $segment_id) {
$relation = NewsletterSegment::create();
$relation->segment_id = $segment_id;
$relation->newsletter_id = $newsletter_id;
$relation->save();
}
}
wp_send_json(($newsletter_id !== false));
}
function delete($id) {

View File

@ -0,0 +1,14 @@
<?php
namespace MailPoet\Router;
if(!defined('ABSPATH')) exit;
class Permissions {
function __construct() {
}
function set($permissions = array()) {
$result = \MailPoet\Util\Permissions::set($permissions);
wp_send_json($result);
}
}

View File

@ -9,16 +9,24 @@ class Settings {
}
function get() {
$settings = Setting::find_array();
$settings = Setting::getAll();
wp_send_json($settings);
}
function set($args) {
$save = function($setting) {
Setting::createOrUpdate($setting);
};
$results = array_map($save, $args);
wp_send_json(in_array(false, $results));
function set($settings = array()) {
if(empty($settings)) {
wp_send_json(false);
} else {
foreach($settings as $name => $value) {
if(is_array($value)) {
$value = serialize($value);
}
Setting::createOrUpdate(array(
'name' => $name,
'value' => $value
));
}
wp_send_json(true);
}
}
}

15
lib/Settings/Charsets.php Normal file
View File

@ -0,0 +1,15 @@
<?php
namespace MailPoet\Settings;
class Charsets {
static function getAll() {
return array(
'UTF-8', 'UTF-7', 'BIG5', 'ISO-2022-JP',
'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3',
'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6',
'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9',
'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14',
'ISO-8859-15', 'Windows-1251', 'Windows-1252'
);
}
}

222
lib/Settings/Hosts.php Normal file
View File

@ -0,0 +1,222 @@
<?php
namespace MailPoet\Settings;
class Hosts {
private static $_smtp = array(
'amazon' => array(
'name' => 'Amazon SES',
'api' => false,
'emails' => 100,
'interval' => 5
),
'elasticemail' => array(
'name' => 'ElasticEmail',
'api' => true,
'emails' => 100,
'interval' => 5
),
'mailgun' => array(
'name' => 'MailGun',
'api' => false,
'emails' => 100,
'interval' => 5
),
'sendgrid' => array(
'name' => 'SendGrid',
'api' => true,
'emails' => 100,
'interval' => 5
)
);
private static $_web = array(
'1and1' => array(
'name' => '1and1',
'emails' => 30,
'interval' => 5,
),
'bluehost' => array(
'name' => 'BlueHost',
'emails' => 70,
'interval' => 30,
),
'df' => array(
'name' => 'Df.eu',
'emails' => 115,
'interval' => 15,
),
'dreamhost' => array(
'name' => 'DreamHost',
'emails' => 25,
'interval' => 15,
),
'free' => array(
'name' => 'Free.fr',
'emails' => 18,
'interval' => 15,
),
'froghost' => array(
'name' => 'FrogHost.com',
'emails' => 490,
'interval' => 30,
),
'godaddy' => array(
'name' => 'GoDaddy',
'emails' => 5,
'interval' => 30,
),
'goneo' => array(
'name' => 'Goneo',
'emails' => 60,
'interval' => 15,
),
'googleapps' => array(
'name' => 'Google Apps',
'emails' => 20,
'interval' => 60,
),
'greengeeks' => array(
'name' => 'GreenGeeks',
'emails' => 45,
'interval' => 30,
),
'hawkhost' => array(
'name' => 'Hawkhost.com',
'emails' => 500,
'interval' => 15,
),
'hivetec' => array(
'name' => 'Hivetec',
'emails' => 20,
'interval' => 15,
),
'hostgator' => array(
'name' => 'Host Gator',
'emails' => 115,
'interval' => 15,
),
'hosting2go' => array(
'name' => 'Hosting 2GO',
'emails' => 45,
'interval' => 15,
),
'hostmonster' => array(
'name' => 'Host Monster',
'emails' => 115,
'interval' => 15,
),
'infomaniak' => array(
'name' => 'Infomaniak',
'emails' => 20,
'interval' => 15,
),
'justhost' => array(
'name' => 'JustHost',
'emails' => 70,
'interval' => 30,
),
'laughingsquid' => array(
'name' => 'Laughing Squid',
'emails' => 20,
'interval' => 15,
),
'lunarpages' => array(
'name' => 'Lunarpages',
'emails' => 19,
'interval' => 15,
),
'mediatemple' => array(
'name' => 'Media Temple',
'emails' => 115,
'interval' => 15,
),
'netfirms' => array(
'name' => 'Netfirms',
'emails' => 200,
'interval' => 60,
),
'netissime' => array(
'name' => 'Netissime',
'emails' => 100,
'interval' => 15,
),
'one' => array(
'name' => 'One.com',
'emails' => 100,
'interval' => 15,
),
'ovh' => array(
'name' => 'OVH',
'emails' => 50,
'interval' => 15,
),
'phpnet' => array(
'name' => 'PHPNet',
'emails' => 15,
'interval' => 15,
),
'planethoster' => array(
'name' => 'PlanetHoster',
'emails' => 90,
'interval' => 30,
),
'rochen' => array(
'name' => 'Rochen',
'emails' => 40,
'interval' => 15,
),
'site5' => array(
'name' => 'Site5',
'emails' => 40,
'interval' => 15,
),
'siteground' => array(
'name' => 'Siteground',
'emails' => 95,
'interval' => 15,
),
'synthesis' => array(
'name' => 'Synthesis',
'emails' => 250,
'interval' => 15,
),
'techark' => array(
'name' => 'Techark',
'emails' => 60,
'interval' => 15,
),
'vexxhost' => array(
'name' => 'Vexxhost',
'emails' => 60,
'interval' => 15,
),
'vps' => array(
'name' => 'VPS.net',
'emails' => 90,
'interval' => 30,
),
'webcity' => array(
'name' => 'Webcity',
'emails' => 19,
'interval' => 15,
),
'westhost' => array(
'name' => 'Westhost',
'emails' => 225,
'interval' => 15,
),
'wpwebhost' => array(
'name' => 'Wpwebhost.com',
'emails' => 95,
'interval' => 30,
)
);
static function getWebHosts() {
return static::$_web;
}
static function getSMTPHosts() {
return static::$_smtp;
}
}

23
lib/Settings/Pages.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace MailPoet\Settings;
class Pages {
static function getAll() {
$mailpoet_pages = get_posts(array(
'post_type' => 'mailpoet_page'
));
$pages = array();
foreach(array_merge($mailpoet_pages, get_pages()) as $page) {
$pages[] = array(
'id' => $page->ID,
'title' => $page->post_title,
'preview_url' => get_permalink($page->ID),
'edit_url' => get_edit_post_link($page->ID)
);
}
return $pages;
}
}

View File

@ -36,10 +36,56 @@ class Functions extends \Twig_Extension {
'admin_url',
'admin_url',
array('is_safe' => array('all'))
),
new \Twig_SimpleFunction(
'get_option',
'get_option',
array('is_safe' => array('all'))
),
new \Twig_SimpleFunction(
'sending_frequency',
array($this, 'getSendingFrequency'),
array('is_safe' => array('all'))
)
);
}
function getSendingFrequency() {
$args = func_get_args();
$value = (int)array_shift($args);
$label = null;
$labels = array(
'minute' => __('every minute'),
'minutes' => __('every %1$d minutes'),
'hour' => __('every hour'),
'hours' => __('every %1$d hours')
);
if($value >= 60) {
// we're dealing with hours
if($value === 60) {
$label = $labels['hour'];
} else {
$label = $labels['hours'];
}
$value /= 60;
} else {
// we're dealing with minutes
if($value === 1) {
$label = $labels['minute'];
} else {
$label = $labels['minutes'];
}
}
if($label !== null) {
return sprintf($label, $value);
} else {
return $value;
}
}
function params($key = null) {
$args = stripslashes_deep($_GET);
if(array_key_exists($key, $args)) {

View File

@ -1,10 +1,8 @@
<?php
namespace MailPoet\Util;
class DKIM {
public static function generateKeys() {
static function generateKeys() {
try {
$certificate = openssl_pkey_new(array('private_bits' => 1024));
@ -14,12 +12,24 @@ class DKIM {
openssl_pkey_export($certificate, $keys['private']);
// get public key
$details = openssl_pkey_get_details($certificate);
$keys['public'] = $details['key'];
$public = openssl_pkey_get_details($certificate);
// trim keys by removing BEGIN/END lines
$keys['public'] = self::trimKey($public['key']);
$keys['private'] = self::trimKey($keys['private']);
return $keys;
} catch(Exception $e) {
return false;
}
}
private static function trimKey($key) {
$lines = explode("\n", trim($key));
// remove first line
array_shift($lines);
// remove last line
array_pop($lines);
return join('', $lines);
}
}

97
lib/Util/Permissions.php Normal file
View File

@ -0,0 +1,97 @@
<?php
namespace MailPoet\Util;
class Permissions {
static function getCapabilities() {
$capabilities = array(
'mailpoet_newsletters' =>
__('Who can create newsletters?'),
'mailpoet_newsletter_styles' =>
__('Who can see the styles tab in the visual editor?'),
'mailpoet_subscribers' =>
__('Who can manage subscribers?'),
'mailpoet_settings' =>
__("Who can change MailPoet's settings?")
);
$capabilities = apply_filters('mailpoet_capabilities', $capabilities);
return $capabilities;
}
static function getRoles() {
$roles = array();
global $wp_roles;
$editable_roles = apply_filters('editable_roles', $wp_roles->roles);
foreach($editable_roles as $role => $role_data) {
$roles[$role] = translate_user_role($role_data['name']);
}
return $roles;
}
static function getAll() {
$roles = static::getRoles();
$capabilities = static::getCapabilities();
// go over each capability
foreach($capabilities as $capability => $label) {
$capability_roles = array();
// go over each role and check permission
foreach($roles as $role_key => $role_data) {
// get role object based on role key
$role = get_role($role_key);
// assign role capability
$capability_roles[$role_key] = array(
'capability' => $capability,
'is_capable' => (
in_array($role_key, array('administrator', 'super_admin'))
|| ($role->has_cap($capability))
),
'is_disabled' =>(
in_array($role_key, array('administrator', 'super_admin'))
)
);
}
$capabilities[$capability] = array(
'label' => $label,
'roles' => $capability_roles
);
}
return array(
'roles' => $roles,
'capabilities' => $capabilities
);
}
static function set($permissions = array()) {
if(empty($permissions)) {
return false;
}
foreach($permissions as $permission) {
// ignore administrator & superadmin roles
if(in_array(
$permission['role'],
array('administrator', 'superadmin'))
) {
continue;
}
// get role
$role = get_role($permission['role']);
if((bool)$permission['is_capable'] === true) {
// add capability to role
$role->add_cap($permission['capability']);
} else {
// remove capability to role
if($role->has_cap($permission['capability'])) {
$role->remove_cap($permission['capability']);
}
}
}
return true;
}
}

View File

@ -22,12 +22,12 @@
"moment": "^2.10.3",
"napa": "^1.2.0",
"papaparse": "4.1.1",
"react": "^0.13.3",
"react-checkbox-group": "^0.2.0",
"react-infinity": "^1.2.2",
"react-prefixr": "^0.1.0",
"react-router": "^0.13.3",
"react-waypoint": "^1.0.2",
"react": "0.14.0",
"react-checkbox-group": "0.2.2",
"react-infinity": "1.2.2",
"react-prefixr": "0.1.0",
"react-router": "1.0.0-rc3",
"react-waypoint": "1.0.4",
"select2": "3.5.1",
"spectrum-colorpicker": "^1.6.2",
"tinymce": "4.1.10",

View File

@ -8,7 +8,8 @@ class CustomFieldCest {
function _before() {
$this->before_time = time();
$this->data = array(
'name' => 'city',
'name' => 'DOB',
'type' => 'date',
);
$this->customField = CustomField::create();
$this->customField->hydrate($this->data);
@ -31,12 +32,24 @@ class CustomFieldCest {
expect($this->saved)->equals(true);
}
function itHasName() {
$customField = CustomField::where('name', $this->data['name'])
->findOne();
expect($customField->name)->equals($this->data['name']);
}
function itHasType() {
$customField = CustomField::where('name', $this->data['name'])
->findOne();
expect($customField->type)->equals($this->data['type']);
}
function itHasToBeValid() {
expect($this->saved)->equals(true);
$empty_model = CustomField::create();
expect($empty_model->save())->notEquals(true);
$validations = $empty_model->getValidationErrors();
expect(count($validations))->equals(1);
expect(count($validations))->equals(2);
}
function itHasACreatedAtOnCreation() {
@ -95,7 +108,7 @@ class CustomFieldCest {
$association = SubscriberCustomField::create();
$association->subscriber_id = $subscriber->id;
$association->custom_field_id = $this->customField->id;
$association->value = 'test';
$association->value = '12/12/2012';
$association->save();
$customField = CustomField::findOne($this->customField->id);
$subscriber = $customField->subscribers()

View File

@ -76,7 +76,8 @@ class NewsletterCest {
'subject' => 'new newsletter',
'body' => 'body'
));
expect($is_created)->equals(true);
expect($is_created)->notEquals(false);
expect($is_created)->greaterThan(0);
$newsletter = Newsletter::where('subject', 'new newsletter')
->findOne();

View File

@ -120,9 +120,10 @@ class SubscriberCest {
expect($subscriberSegment->id)->equals($segment->id);
}
function itCanHaveCustomField() {
function itCanHaveCustomFields() {
$customFieldData = array(
'name' => 'city'
'name' => 'DOB',
'type' => 'date',
);
$customField = CustomField::create();
$customField->hydrate($customFieldData);
@ -130,11 +131,11 @@ class SubscriberCest {
$association = SubscriberCustomField::create();
$association->subscriber_id = $this->subscriber->id;
$association->custom_field_id = $customField->id;
$association->value = '12/12/2012';
$association->save();
$subscriber = Subscriber::findOne($this->subscriber->id);
$subscriberCustomField = $subscriber->customFields()
->findOne();
expect($subscriberCustomField->id)->equals($customField->id);
$subscriber = Subscriber::filter('withCustomFields')
->findOne($this->subscriber->id);
expect($subscriber->DOB)->equals($association->value);
}
function itCanCreateOrUpdate() {

View File

@ -0,0 +1,10 @@
<?php
use \MailPoet\Settings\Charsets;
class CharsetsCest {
function itReturnsAListOfCharsets() {
$charsets = Charsets::getAll();
expect($charsets)->notEmpty();
expect($charsets[0])->equals('UTF-8');
}
}

View File

@ -0,0 +1,24 @@
<?php
use \MailPoet\Settings\Hosts;
class HostsCest {
function itReturnsAListOfWebHosts() {
$web_hosts = Hosts::getWebHosts();
expect($web_hosts)->notEmpty();
foreach($web_hosts as $host) {
expect($host['interval'])->greaterThan(0);
expect($host['emails'])->greaterThan(0);
}
}
function itReturnsAListOfSMTPHosts() {
$smtp_hosts = Hosts::getSMTPHosts();
expect($smtp_hosts)->notEmpty();
foreach($smtp_hosts as $host) {
expect($host['interval'])->greaterThan(0);
expect($host['emails'])->greaterThan(0);
}
}
}

View File

@ -0,0 +1,15 @@
<?php
use \MailPoet\Settings\Pages;
class PagesCest {
function itReturnsAListOfPages() {
$pages = Pages::getAll();
expect($pages)->notEmpty();
foreach($pages as $page) {
expect($page['id'])->greaterThan(0);
expect($page['title'])->notEmpty();
expect($page['preview_url'])->notEmpty();
}
}
}

View File

@ -11,7 +11,7 @@ class UtilDKIMCest {
expect($keys['public'])->notEmpty();
expect($keys['private'])->notEmpty();
expect($keys['public'])->contains($public_header);
expect($keys['private'])->contains($private_header);
expect($keys['public'])->notContains($public_header);
expect($keys['private'])->notContains($private_header);
}
}

View File

@ -1,7 +1,157 @@
<% extends 'layout.html' %>
<% block content %>
<h1><%= __('Settings') %></h1>
<div id="mailpoet_settings">
<div id="mailpoet_settings"></div>
<h2 class="title"><%= __('Settings') %></h2>
<!-- settings form -->
<form
id="mailpoet_settings_form"
name="mailpoet_settings_form"
class="mailpoet_form"
autocomplete="off"
novalidate
>
<!-- tabs -->
<h2 class="nav-tab-wrapper" id="mailpoet_settings_tabs">
<a class="nav-tab" href="#basics"><%= __('Basics') %></a>
<a class="nav-tab" href="#signup"><%= __('Signup Confirmation') %></a>
<a class="nav-tab" href="#mta"><%= __('Send With...') %></a>
<a class="nav-tab" href="#advanced"><%= __('Advanced') %></a>
<a class="nav-tab" href="#bounce"><%= __('Bounce Handling') %></a>
</h2>
<!-- basics -->
<div data-tab="basics" class="mailpoet_panel">
<% include 'settings/basics.html' %>
</div>
<!-- signup confirmation -->
<div data-tab="signup" class="mailpoet_panel">
<% include 'settings/signup.html' %>
</div>
<!-- sending method -->
<div data-tab="mta" class="mailpoet_panel">
<% include 'settings/mta.html' %>
</div>
<!-- advanced -->
<div data-tab="advanced" class="mailpoet_panel">
<% include 'settings/advanced.html' %>
</div>
<!-- bounce -->
<div data-tab="bounce" class="mailpoet_panel">
<% include 'settings/bounce.html' %>
</div>
<p class="submit mailpoet_settings_submit">
<input
type="submit"
class="button button-primary"
name="submit"
value="<%= ('Save settings') %>"
/>
</p>
</form>
</div>
<script type="text/javascript">
jQuery(function($) {
// on dom loaded
$(function() {
// save settings
$('.mailpoet_settings_submit').on('click', function(e) {
e.preventDefault();
// serialize form data
var settings_data = $('#mailpoet_settings_form').serializeObject(),
permissions = $('.mailpoet_role_permission'),
permissions_data = []
// format permissions
for(var i = permissions.length - 1; i >= 0; i--) {
var permission = $(permissions[i]);
permissions_data.push({
role: permission.data('role'),
capability: permission.data('capability'),
is_capable: (permission.is(':checked') ? 1 : 0)
});
};
// show loading screen
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
endpoint: 'settings',
action: 'set',
data: settings_data
}).done(function(response) {
if(response === true) {
MailPoet.Ajax.post({
endpoint: 'permissions',
action: 'set',
data: permissions_data
});
MailPoet.Notice.success(
"<%= __('Settings saved.') %>",
{ scroll: true }
);
} else {
MailPoet.Notice.error(
"<%= __('Settings could not be saved.') %>",
{ scroll: true }
);
}
MailPoet.Modal.loading(false);
}).error(function(errors) {
MailPoet.Notice.error(
"<%= __('An error occurred. Check your settings.') %>",
{ scroll: true }
);
MailPoet.Modal.loading(false);
});
});
// setup toggle checkboxes
function toggleContent() {
$('#'+$(this).data('toggle'))[
($(this).is(':checked'))
? 'show'
: 'hide'
]();
}
$(document).on('click', 'input[data-toggle]', toggleContent);
$('input[data-toggle]').each(toggleContent);
// page preview
$('.mailpoet_page_preview').on('click', function() {
var selection = $(this).siblings('.mailpoet_page_selection');
if(selection.length > 0) {
$(this).attr('href', $(selection).find('option[value="'+$(selection).val()+'"]').data('preview-url'));
$(this).attr('target', '_blank');
} else {
$(this).attr('href', 'javascript:;');
$(this).removeAttr('target');
}
});
// page edit
$('.mailpoet_page_edit').on('click', function() {
var selection = $(this).siblings('.mailpoet_page_selection');
if(selection.length > 0) {
$(this).attr('href', $(selection).find('option[value="'+$(selection).val()+'"]').data('edit-url'));
$(this).attr('target', '_blank');
} else {
$(this).attr('href', 'javascript:;');
$(this).removeAttr('target');
}
});
});
});
</script>
<% endblock %>

View File

@ -0,0 +1,184 @@
<table id="mailpoet_role_permissions" class="widefat fixed">
<thead>
<tr>
<th class="manage-column">
<%= __('Roles and permissions') %>
</th>
<% for role in permissions.roles %>
<th class="manage-column">
<%= role %>
</th>
<% endfor %>
</tr>
</thead>
<tbody>
<% for capability in permissions.capabilities %>
<tr class="<%= cycle(['alternate', ''], loop.index0) %>">
<td>
<%= capability.label %>
</td>
<% for role_key, role in capability.roles %>
<td>
<input
class="mailpoet_role_permission"
type="checkbox"
data-role="<%= role_key %>"
data-capability="<%= role.capability %>"
value="1"
<% if(role.is_capable) %>
checked="checked"
<% endif %>
<% if(role.is_disabled) %>
disabled="disabled"
<% endif %>
/>
</td>
<% endfor %>
</tr>
<% endfor %>
</tbody>
</table>
<table class="form-table">
<tbody>
<!-- bounce email -->
<tr>
<th scope="row">
<label for="settings[bounce_email]">
<%= __('Bounce email') %>
<p class="description">
<%= __('To which address should all the bounced emails go?') %>
</p>
</th>
<td>
<p>
<input type="text"
id="settings[bounce_email]"
name="bounce[address]"
value="<%= settings.bounce.address %>"
placeholder="bounce@mydomain.com"
/>
</p>
</td>
</tr>
<!-- share anonymous data? -->
<tr>
<th scope="row">
<label>
<%= __('Share anonymous data') %>
<p class="description">
<%= __('Share anonymous data and help us improve the plugin.') %>
<a
href="http://support.mailpoet.com/knowledgebase/share-your-data/?utm_source=wpadmin&utm_campaign=advanced_settings"
target="_blank"
><%= __('Read more.') %></a>
</p>
</label>
</th>
<td>
<p>
<label>
<input
type="radio"
name="analytics[enabled]"
value="1"
<% if(settings.analytics.enabled) %>
checked="checked"
<% endif %>
/><%= __('Yes') %>
</label>
&nbsp;
<label>
<input
type="radio"
name="analytics[enabled]"
value=""
<% if not(settings.analytics.enabled) %>
checked="checked"
<% endif %>
/><%= __('No') %>
</label>
</p>
</td>
</tr>
<!-- charset -->
<tr>
<th scope="row">
<label for="settings[charset]">
<%= __('Charset') %>
<p class="description">
<%= __('Squares or weird characters are displayed in your emails? Select the encoding for your language.') %>
</p>
</label>
</th>
<td>
<p>
<select
id="settings[charset]"
name="charset"
>
<% for charset in charsets %>
<option
value="<%= charset %>"
<% if(settings.charset == charset) %>
selected="selected"
<% endif %>
><%= charset %></option>
<% endfor %>
</select>
</p>
</td>
</tr>
<!-- debug mode -->
<tr>
<th scope="row">
<label>
<%= __('Debug mode') %>
<p class="description">
<%= __("Enable this to show MailPoet's errors. Our support might ask you to enable this if you seek their help.") %>
</p>
</label>
</th>
<td>
<p>
<label>
<input
type="radio"
name="debug[enabled]"
value="1"
<% if(settings.debug.enabled) %>
checked="checked"
<% endif %>
/><%= __('Yes') %>
</label>
&nbsp;
<label>
<input
type="radio"
name="debug[enabled]"
value=""
<% if not(settings.debug.enabled) %>
checked="checked"
<% endif %>
/><%= __('No') %>
</label>
</p>
</td>
</tr>
<!-- reinstall -->
<tr>
<th scope="row">
<label><%= __('Reinstall from scratch') %>
<p class="description"><%= __('Want to start all over again? This will wipe out MailPoet and reinstall anew.') %></p>
</th>
<td>
<p>
<a
id="mailpoet_reinstall"
class="button"
href="javascript:;"><%= __('Reinstall now...') %></a>
</p>
</td>
</tr>
</tbody>
</table>

363
views/settings/basics.html Normal file
View File

@ -0,0 +1,363 @@
<table class="form-table">
<tbody>
<!-- email addresses receiving notifications -->
<tr>
<th scope="row">
<label for="settings[notification_email]">
<%= __("Email notifications") %>
<p class="description">
<%= __('Enter the email addresses that should receive notifications (separate by comma).') %>
</p>
</label>
</th>
<td>
<p>
<input type="text"
id="settings[notification_email]"
name="notification[address]"
value="<%= settings.notification.address %>"
placeholder="notification@mydomain.com"
class="regular-text" />
</p>
<p>
<label for="settings[notification_on_subscribe]">
<input type="checkbox" id="settings[notification_on_subscribe]"
name="notification[on_subscribe]"
value="1"
<% if(settings.notification.on_subscribe) %>checked="checked"<% endif %> />
<%= __('When someone subscribes') %>
</label>
</p>
<p>
<label for="settings[notification_on_unsubscribe]">
<input type="checkbox"
id="settings[notification_on_unsubscribe]"
name="notification[on_unsubscribe]"
value="1"
<% if(settings.notification.on_unsubscribe) %>checked="checked"<% endif %> />
<%= __('When someone unsubscribes') %>
</label>
</p>
<p>
<label for="settings[notification_daily_report]">
<input type="checkbox"
id="settings[notification_daily_report]"
name="notification[daily_report]"
value="1"
<% if(settings.notification.daily_report) %>checked="checked"<% endif %> />
<%= __('Daily summary of emails sent') %>
</label>
</p>
<!-- email notification: from name & email -->
<p>
<label for="settings[from_name]"><%= __('From') %></label>
<input type="text"
id="settings[from_name]"
name="sender[name]"
value="<%= settings.sender.name %>"
placeholder="<%= __('Your name') %>" />
<input type="text"
id="settings[from_email]"
name="sender[address]"
value="<%= settings.sender.address %>"
placeholder="info@mydomain.com" />
</p>
<!-- email notification: reply_to name & email -->
<p>
<label for="settings[notification_reply_name]"><%= __('Reply-to') %></label>
<input type="text"
id="settings[notification_reply_name]"
name="notification[reply_to][name]"
value="<%= settings.notification.reply_to.name %>"
placeholder="<%= __('Your name') %>" />
<input type="text"
id="settings[notification_reply_email]"
name="notification[reply_to][address]"
value="<%= settings.notification.reply_to.address %>"
placeholder="info@mydomain.com" />
</p>
</td>
</tr>
<!-- ability to subscribe in comments -->
<!-- TODO: Check if registration is enabled (if not, display a message and disable setting) -->
<tr>
<th scope="row">
<label for="settings[subscribe_on_comment]">
<%= __('Subscribe in comments') %>
<p class="description"><%= __('Visitors who submit a comment on a post can click on a checkbox to subscribe.') %></p>
</label>
</th>
<td>
<p>
<input
data-toggle="mailpoet_subscribe_on_comment"
type="checkbox"
value="1"
id="settings[subscribe_on_comment]"
name="subscribe[on_comment][enabled]"
<% if(settings.subscribe.on_comment.enabled) %>checked="checked"<% endif %>
/>
</p>
<div id="mailpoet_subscribe_on_comment">
<p>
<input
type="text"
id="settings[subscribe_on_comment_label]"
name="subscribe[on_comment][label]"
class="regular-text"
<%if(settings.subscribe.on_comment.label) %>
value="<%= settings.subscribe.on_comment.label %>"
<% else %>
value="<%= __('Yes, add me to your mailing list.') %>"
<% endif %>
/>
</p>
<p>
<select
id="mailpoet_subscribe_on_comment_lists"
name="subscribe[on_comment][lists][]"
placeholder="<%= __('Choose a list') %>"
multiple
>
<% for segment in segments %>
<option
value="<%= segment.id %>"
<% if(segment.id in settings.subscribe.on_comment.lists) %>
selected="selected"
<% endif %>
><%= segment.name %></option>
<% endfor %>
</select>
</p>
</div>
</td>
</tr>
<!-- ability to subscribe when registering -->
<!-- TODO: Only available for the main site of a multisite! -->
<!-- TODO: Check if registration is enabled (if not, display a message and disable setting) -->
<tr>
<th scope="row">
<label for="settings[subscribe_on_register]">
<%= __('Subscribe in registration form') %>
<p class="description">
<%= __('Allow users who register to your site to subscribe on a list of your choice.') %>
</p>
</label>
</th>
<td>
<% if(flags.registration_enabled == true) %>
<p>
<input
data-toggle="mailpoet_subscribe_in_form"
type="checkbox"
value="1"
id="settings[subscribe_on_register]"
name="subscribe[on_register][enabled]"
<% if(settings.subscribe.on_register.enabled) %>
checked="checked"
<% endif %>
/>
</p>
<div id="mailpoet_subscribe_in_form">
<p>
<input
type="text"
id="settings[subscribe_on_register_label]"
name="subscribe[on_register][label]"
class="regular-text"
<%if(settings.subscribe.on_register.label) %>
value="<%= settings.subscribe.on_register.label %>"
<% else %>
value="<%= __('Yes, add me to your mailing list.') %>"
<% endif %>
/>
</p>
<p>
<select
id="mailpoet_subscribe_on_register_lists"
name="subscribe[on_register][lists][]"
placeholder="<%= __('Choose a list') %>"
multiple
>
<% for segment in segments %>
<option
value="<%= segment.id %>"
<% if(segment.id in settings.subscribe.on_register.lists) %>
selected="selected"
<% endif %>
><%= segment.name %></option>
<% endfor %>
</select>
</p>
</div>
<% else %>
<p>
<em><%= __('Registration is disabled on this site.') %></em>
</p>
<% endif %>
</td>
</tr>
<!-- manage subscriptions-->
<tr>
<th scope="row">
<label for="settings[subscription_edit]">
<%= __('Unsubscribe & Manage Subscription page') %>
<p class="description">
<%= __('The page your subscribers see when they click to
"Unsubscribe" or "Manage your subscription" in your emails.') %>
</p>
</label>
</th>
<td>
<p>
<select
class="mailpoet_page_selection"
name="subscription[page]"
>
<% for page in pages %>
<option
value="<%= page.id %>"
data-preview-url="<%= page.preview_url|raw %>"
data-edit-url="<%= page.edit_url|raw %>"
<% if(page.id == settings.subscription.page) %>
selected="selected"
<% endif %>
><%= page.title %></option>
<% endfor %>
</select>
<a
class="mailpoet_page_preview"
href="javascript:;"
title="<%= __('Preview page') %>"
><%= __('Preview') %></a>&nbsp;|&nbsp;<a
class="mailpoet_page_edit"
href="javascript:;"
title="<%= __('Edit page') %>"
><%= __('Edit') %></a>
</p>
<p>
<label><%= __('Subscribers can choose from these lists :') %></label>
</p>
<p>
<select
id="mailpoet_subscription_edit_lists"
name="subscription[lists][]"
placeholder="<%= __('Leave empty to show all lists') %>"
multiple
>
<% for segment in segments %>
<option
value="<%= segment.id %>"
<% if(segment.id in settings.subscription.lists) %>
selected="selected"
<% endif %>
><%= segment.name %></option>
<% endfor %>
</select>
</p>
</td>
</tr>
<!-- shortcode: archive page -->
<tr>
<th scope="row">
<label>
<%= __('Archive page shortcode') %>
<p class="description">
<%= __('Paste this shortcode in a page to display a list of past newsletters.') %>
</p>
</label>
</th>
<td>
<p>
<input
type="text"
class="regular-text"
id="mailpoet_shortcode_archives"
value="[mailpoet_archive]"
onClick="this.focus();this.select();"
readonly="readonly"
/>
</p>
<p>
<select
id="mailpoet_shortcode_archives_list"
data-shortcode="mailpoet_archive"
data-output="mailpoet_shortcode_archives"
placeholder="<%= __('Leave empty to show all lists') %>"
multiple
>
<% for segment in segments %>
<option value="<%= segment.id %>"><%= segment.name %></option>
<% endfor %>
</select>
</p>
</td>
</tr>
<!-- shortcode: total number of subscribers -->
<tr>
<th scope="row">
<label>
<%= __('Shortcode to display total number of subscribers') %>
<p class="description">
<%= __('Paste this shortcode to display the number of confirmed subscribers in post or page.') %>
</p>
</label>
</th>
<td>
<p>
<input
type="text"
class="regular-text"
id="mailpoet_shortcode_subscribers"
value="[mailpoet_subscribers_count]"
onClick="this.focus();this.select();"
readonly="readonly"
/>
</p>
<p>
<select
id="mailpoet_shortcode_subscribers_list"
data-shortcode="mailpoet_subscribers_count"
data-output="mailpoet_shortcode_subscribers"
placeholder="<%= __('Leave empty to show all lists') %>"
multiple
>
<% for segment in segments %>
<option value="<%= segment.id %>"><%= segment.name %></option>
<% endfor %>
</select>
</p>
</td>
</tr>
</tbody>
</table>
<script type="text/javascript">
jQuery(function($) {
// on dom loaded
$(function() {
// select2 instances
$('#mailpoet_subscribe_on_comment_lists').select2();
$('#mailpoet_subscribe_on_register_lists').select2();
$('#mailpoet_subscription_edit_lists').select2();
$('#mailpoet_shortcode_archives_list').select2();
$('#mailpoet_shortcode_subscribers_list').select2();
// shortcodes
$('#mailpoet_shortcode_archives_list, #mailpoet_shortcode_subscribers_list')
.on('change', function() {
var shortcode = $(this).data('shortcode'),
values = $(this).val() || [];
if(values.length > 0) {
shortcode += ' list_id="';
shortcode += values.join(',');
shortcode += '"';
}
$('#' + $(this).data('output')).val('[' + shortcode + ']');
});
});
});
</script>

283
views/settings/bounce.html Normal file
View File

@ -0,0 +1,283 @@
<h3><%= __('How does it work?') %></h3>
<ol>
<li>
<%= __('Create an email account dedicated solely to bounce handling.') %>
</li>
<li>
<%= __('Fill out the form below so we can connect to it.') %>
</li>
<li>
<%= __('Take it easy, the plugin does the rest.') %>
</li>
</ol>
<p class="description">
<%=
__('Need help? Check out %1$sour guide%2$s on how to fill out the form.')
| format(
'<a target="_blank" href="#todo/automated-bounce-handling-install-guide/">',
'</a>'
)
| raw
%>
</p>
<hr />
<!-- bounce: settings -->
<table class="form-table">
<tbody>
<!-- bounce: host -->
<tr>
<th scope="row">
<label for="settings[bounce_host]">
<%= __('Hostname') %>
</label>
</th>
<td>
<p>
<input
type="text"
id="settings[bounce_host]"
name="bounce[host]"
value="<%= settings.bounce.host %>"
/>
</p>
</td>
</tr>
<!-- bounce: login -->
<tr>
<th scope="row">
<label for="settings[bounce_login]">
<%= __('Login') %>
</label>
</th>
<td>
<p>
<input type="text"
id="settings[bounce_login]"
name="bounce[login]"
value="<%= settings.bounce.login %>"
placeholder="" />
</p>
</td>
</tr>
<!-- bounce: password -->
<tr>
<th scope="row">
<label for="settings[bounce_password]">
<%= __('Password') %>
</label>
</th>
<td>
<p>
<input type="password"
id="settings[bounce_password]"
name="bounce[password]"
value="<%= settings.bounce.password %>"
/>
</p>
</td>
</tr>
<!-- bounce: protocol -->
<tr>
<th scope="row">
<label for="settings[bounce_protocol]">
<%= __('Connection method') %>
</label>
</th>
<td>
<p>
<select
id="settings[bounce_protocol]"
name="bounce[protocol]"
>
<option
value="pop3"
<% if(settings.bounce.protocol == 'pop3') %>
selected="selected"
<% endif %>
>POP3</option>
<option
value="imap"
<% if(settings.bounce.protocol == 'imap') %>
selected="selected"
<% endif %>
>IMAP</option>
<option
value="pear"
<% if(settings.bounce.protocol == 'pear') %>
selected="selected"
<% endif %>
><%= __('POP3 without imap extension') %></option>
<option
value="nntp"
<% if(settings.bounce.protocol == 'nntp') %>
selected="selected"
<% endif %>
>NNTP</option>
</select>
</p>
</td>
</tr>
<!-- bounce: port -->
<tr>
<th scope="row">
<label for="settings[bounce_port]">
<%= __('Port') %>
</label>
</th>
<td>
<p>
<input type="text"
id="settings[bounce_port]"
name="bounce[port]"
value="<%= settings.bounce.port %>"
size="3"
/>
</p>
</td>
</tr>
<!-- bounce: SSL -->
<tr>
<th scope="row">
<label for="settings[bounce_secure]">
<%= __('Secure connection') %>
</label>
</th>
<td>
<select id="settings[bounce_secure]" name="bounce[secure]">
<option value=""><%= __('No') %></option>
<option
value="ssl"
<% if(settings.bounce.secure == 'ssl') %>
selected="selected"
<% endif %>
>SSL</option>
<option
value="tls"
<% if(settings.bounce.secure == 'tls') %>
selected="selected"
<% endif %>
>TLS</option>
</select>
</td>
</tr>
<!-- bounce: self-signed certificate -->
<tr>
<th scope="row">
<label><%= __('Self-signed certificate') %></label>
</th>
<td>
<label>
<input
type="radio"
name="bounce[authenticate]"
value=""
<% if not(settings.bounce.authenticate) %>
checked="checked"
<% endif %>
/>
<%= __('No') %>
</label>
<label>
<input
type="radio"
name="bounce[authenticate]"
value="1"
<% if(settings.bounce.authenticate) %>
checked="checked"
<% endif %>
/>
<%= __('Yes') %>
</label>
</td>
</tr>
<!-- bounce: activation & frequency -->
<tr>
<th scope="row">
<label for="settings[bounce_enabled]">
<%= __('Activate bounce and check every...') %>
</label>
</th>
<td>
<div>
<p>
<input type="checkbox"
data-toggle="mailpoet_bounce_frequency"
id="settings[bounce_enabled]"
name="bounce[enabled]"
value="1"
<% if(settings.bounce.enabled) %>
checked="checked"
<% endif %>
/>
<select
id="mailpoet_bounce_frequency"
name="bounce[frequency]"
>
<option
value="15"
<% if(settings.bounce.frequency == "15") %>
selected="selected"
<% endif %>
><%= __('15 minutes') %></option>
<option
value="30"
<% if(settings.bounce.frequency == "30") %>
selected="selected"
<% endif %>
><%= __('30 minutes') %></option>
<option
value="60"
<% if(settings.bounce.frequency == "60") %>
selected="selected"
<% endif %>
><%= __('1 hour') %></option>
<option
value="120"
<% if(settings.bounce.frequency == "120") %>
selected="selected"
<% endif %>
><%= __('2 hours') %></option>
<option
value="720"
<% if(settings.bounce.frequency == "720") %>
selected="selected"
<% endif %>
><%= __('Twice daily') %></option>
<option
value="1440"
<% if(settings.bounce.frequency == "1440") %>
selected="selected"
<% endif %>
><%= __('Day') %></option>
</select>
</p>
</div>
</td>
</tr>
<!-- bounce: test connection -->
<tr>
<th scope="row">
<label>
<a
id="mailpoet_bounce_test"
class="button-secondary"
href="javascript:;"
><%= __('Does it work? Try to connect.') %></a>
</label>
</th>
<td id="mailpoet_bounce_test_result"></td>
</tr>
</tbody>
</table>
<script type="text/javascript">
jQuery(function($) {
// om dom loaded
$(function() {
$('#mailpoet_bounce_test').on('click', function() {
alert('[TODO] bounce -> test connection');
});
});
});
</script>

893
views/settings/mta.html Normal file
View File

@ -0,0 +1,893 @@
<% set intervals = [1, 2, 5, 10, 15, 30, 60] %>
<% set default_frequency = {
'website': {
'emails': 25,
'interval': 15
},
'smtp': {
'emails': 100,
'interval': 5
}
} %>
<!-- smtp: method -->
<input
type="hidden"
id="mta_method"
name="mta[method]"
value="<%= settings.mta.method %>"
/>
<!-- mta: sending frequency -->
<input
type="hidden"
id="mta_frequency_emails"
name="mta[frequency][emails]"
value="<%= settings.mta.frequency.emails %>"
/>
<input
type="hidden"
id="mta_frequency_interval"
name="mta[frequency][interval]"
value="<%= settings.mta.frequency.interval %>"
/>
<!-- dkim: public / private keys -->
<input
type="hidden"
name="dkim[public_key]"
value="<%= settings.dkim.public_key %>"
/>
<input
type="hidden"
name="dkim[private_key]"
value="<%= settings.dkim.private_key %>"
/>
<!-- dkim: domain -->
<input
type="hidden"
name="dkim[domain]"
value="<%= settings.dkim.domain %>"
/>
<!-- smtp: available sending methods -->
<ul class="mailpoet_sending_methods clearfix">
<li
data-method="mailpoet"
<% if(settings.mta.method == 'mailpoet') %>class="mailpoet_active"<% endif %>
>
<h3>
<img
src="<%= assets_url %>/img/mailpoet_logo.png"
alt="MailPoet"
width="222"
height="54"
/>
</h3>
<p class="mailpoet_description">
<%= __('Send to 500 subscribers per month for <strong>free</strong>. Enjoy great deliverability, and speed.') %>
<br /><br />
<a href="#todo"><%= __('See pricing for more.') %></a>
</p>
<div class="mailpoet_status">
<span><%= __('Activated') %></span>
</div>
<div class="mailpoet_actions">
<a
class="button-secondary"
href="#mta/mailpoet"><%= __('Configure') %></a>
</div>
</li>
<li
data-method="website"
<% if(settings.mta.method == 'website') %>class="mailpoet_active"<% endif %>
>
<h3><%= __('Your own website') %></h3>
<p class="mailpoet_description">
<%= __('The simplest solution for small lists. Your web host sets a daily email limit.') %>
</p>
<div class="mailpoet_status">
<span><%= __('Activated') %></span>
</div>
<div class="mailpoet_actions">
<a
class="button-secondary"
href="#mta/website"><%= __('Configure') %></a>
</div>
</li>
<li
data-method="smtp"
<% if(settings.mta.method == 'smtp') %>class="mailpoet_active"<% endif %>
>
<h3><%= __('Third party') %></h3>
<p class="mailpoet_description">
<%= __('Send with an alternate email provider. Usually not free.') %>
</p>
<div class="mailpoet_status">
<span><%= __('Activated') %></span>
</div>
<div class="mailpoet_actions">
<a
class="button-secondary"
href="#mta/smtp"><%= __('Configure') %></a>
</div>
</li>
</ul>
<div id="mailpoet_sending_method_setup">
<!-- Sending Method: MailPoet -->
<div
class="mailpoet_sending_method"
data-method="mailpoet"
style="display:none;"
>
<h3><%= __('Open a free account with MailPoet, and get:') %></h3>
<ol>
<li>
<%=
__('Send up to 4000 emails with good deliverability for free. %1$sNeed more?%2$s')
| format('<a href="#todo">', '</a>')
| raw
%>
</li>
<li>
<%= __("Test your campaign's spam score") %>
</li>
<li>
<%= __('Send on time, without delay, without setting up your own "cron"') %>
</li>
</ol>
<a class="button-secondary">
<%=- __('Create a free account to get a key') -%>
</a>
<hr />
<h3><%= __('Already have a key?') %></h3>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="mailpoet_api_key">
<%= __('Your key') %>
</label>
</th>
<td>
<input
type="text"
id="mailpoet_api_key"
size="40"
name="api_key"
value="<%= settings.api_key %>"
/>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Sending Method: Website -->
<div
class="mailpoet_sending_method"
data-method="website"
style="display:none;"
>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="mailpoet_mta_local_method">
<%= __('Delivery method') %>
</label>
</th>
<td>
<!-- local sending method: mail / sendmail / wp_mail -->
<p>
<label>
<input type="radio"
name="mta[local_method]"
value="mail"
<%
if not(settings.mta.local_method)
or (settings.mta.local_method == 'mail')
%>checked="checked"<% endif %>
/>PHP Mail
</label>
</p>
<p class="description"><%= __('This email engine works on 95&#37; of servers.') %></p>
<p>
<label>
<input type="radio"
name="mta[local_method]"
value="sendmail"
<%
if(settings.mta.local_method == 'sendmail')
%>checked="checked"<% endif %>
/>Sendmail
</label>
</p>
<p class="description"><%= __('This method works on 5&#37; of servers.') %></p>
<p>
<label>
<input type="radio"
name="mta[local_method]"
value="wp_mail"
<%
if(settings.mta.local_method == 'wp_mail')
%>checked="checked"<% endif %>
/>WP Mail
</label>
</p>
</td>
</tr>
<tr>
<th scope="row">
<label for="mailpoet_web_host">
<%= __('Sending frequency') %>
</label>
</th>
<td>
<p>
<!-- sending frequency -->
<select
id="mailpoet_web_host"
name="web_host"
>
<option value="auto">
<%= __('Safe default values') %>
</option>
<option
value="manual"
<% if(settings.web_host == 'manual') %>
selected="selected"
<% endif %>
>
<%= __("I'll set my own frequency") %>
</option>
<!-- web hosts -->
<optgroup
label="<%= __('Select your host recommended frequency') %>"
>
<% for host_key, host in hosts.web %>
<option
value="<%= host_key %>"
data-emails="<%= host.emails %>"
data-interval="<%= host.interval %>"
<% if(settings.web_host == host_key) %>
selected="selected"
<% endif %>
><%= host.name %></option>
<% endfor %>
</optgroup>
</select>
&nbsp;
<!-- website: sending frequency -->
<span id="mailpoet_website_sending_frequency"></span>
</p>
<!-- website: manual sending frequency -->
<div id="mailpoet_sending_frequency_manual" style="display:none;">
<p>
<input
id="website_frequency_emails"
type="number"
min="1"
max="1000"
value="<%=
settings.mta.frequency.emails
| default(default_frequency.website.emails)
%>"
/>
<%= __('emails') %>
<select id="website_frequency_interval">
<% for interval in intervals %>
<option
value="<%= interval %>"
<%
if not(settings.mta.frequency.interval)
and (interval == default_frequency.website.interval)
%>
selected="selected"
<% endif %>
<% if(settings.mta.frequency.interval == interval) %>
selected="selected"
<% endif %>
>
<%= sending_frequency(interval) %>
<% if(interval == 15) %>
(<%= __('recommended') %>)
<% endif %>
</option>
<% endfor %>
</select>
<span id="mailpoet_website_daily_emails"></span>
</p>
<br />
<p>
<%= __('<strong>Warning!</strong> Sending more than the recommended amount of emails might break the terms of your host or provider.') %>
<br />
<%= __('Double check with them what maximum number of emails you can send daily.') %>
</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Sending Method: SMTP -->
<div class="mailpoet_sending_method" data-method="smtp" style="display:none;">
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<label for="mailpoet_smtp_provider">
<%= __('Provider') %>
</label>
</th>
<td>
<!-- smtp provider -->
<select
id="mailpoet_smtp_provider"
name="smtp_provider"
>
<option data-interval="5" data-emails="100" value="manual">
<%= __('Custom SMTP') %>
</option>
<!-- providers -->
<optgroup label="<%= __('Select your prodivder') %>">
<% for host_key, host in hosts.smtp %>
<option
value="<%= host_key %>"
data-emails="<%= host.emails %>"
data-interval="<%= host.interval %>"
<% if(settings.smtp_provider == host_key) %>
selected="selected"
<% endif %>
><%= host.name %></option>
<% endfor %>
</optgroup>
</select>
</td>
</tr>
<tr>
<th scope="row">
<label for="mailpoet_smtp_provider">
<%= __('Sending frequency') %>
</label>
</th>
<td>
<!-- smtp: sending frequency -->
<p>
<input
id="smtp_frequency_emails"
type="number"
min="1"
max="1000"
value="<%=
settings.mta.frequency.emails
| default(default_frequency.smtp.emails)
%>"
/>
<%= __('emails') %>
<select id="smtp_frequency_interval">
<% for interval in intervals %>
<option
value="<%= interval %>"
<%
if not(settings.mta.frequency.interval)
and (interval == default_frequency.smtp.interval)
%>
selected="selected"
<% endif %>
<% if(settings.mta.frequency.interval == interval) %>
selected="selected"
<% endif %>
>
<%= sending_frequency(interval) %>
<% if(interval == 15) %>
(<%= __('recommended') %>)
<% endif %>
</option>
<% endfor %>
</select>
<span id="mailpoet_smtp_daily_emails"></span>
</p>
<br />
<p>
<%= __('<strong>Warning!</strong> Sending more than the recommended amount of emails might break the terms of your host or provider.') %>
<br />
<%= __('Double check with them what maximum number of emails you can send daily.') %>
</p>
</td>
</tr>
<!-- smtp: host -->
<tr class="mailpoet_smtp_field">
<th scope="row">
<label for="settings[mta_smtp_host]">
<%= __('SMTP Hostname') %>
<p class="description">
<%= __('e.g.:smtp.mydomain.com') %>
</p>
</label>
</th>
<td>
<input
type="text"
id="settings[mta_smtp_host]"
name="mta[smtp][host]"
value="<%= settings.mta.smtp.host %>" />
</td>
</tr>
<!-- smtp: login -->
<tr id="mta_smtp_login" class="mailpoet_smtp_field">
<th scope="row">
<label for="settings[mta_smtp_login]">
<%= __('Login') %>
</label>
</th>
<td>
<input
type="text"
id="settings[mta_smtp_login]"
name="mta[smtp][login]"
value="<%= settings.mta.smtp.login %>"
/>
</td>
</tr>
<!-- smtp: password -->
<tr id="mta_smtp_password" class="mailpoet_smtp_field">
<th scope="row">
<label for="settings[mta_smtp_password]">
<%= __('Password / API key') %>
</label>
</th>
<td>
<input
type="password"
id="settings[mta_smtp_password]"
name="mta[smtp][password]"
value="<%= settings.mta.smtp.password %>"
/>
</td>
</tr>
<!-- smtp: port -->
<tr class="mailpoet_smtp_field">
<th scope="row">
<label for="settings[mta_smtp_port]">
<%= __('SMTP Port') %>
</label>
</th>
<td>
<input
type="text"
id="settings[mta_smtp_port]"
name="mta[smtp][port]"
value="<%= settings.mta.smtp.port %>"
/>
</td>
</tr>
<!-- smtp: security protocol -->
<tr class="mailpoet_smtp_field">
<th scope="row">
<label for="settings[mta_smtp_secure]">
<%= __('Secure connection') %>
</label>
</th>
<td>
<select id="settings[mta_smtp_secure]" name="mta[smtp][secure]">
<option value=""><%= __('No') %></option>
<option
value="ssl"
<% if(settings.mta.smtp.secure == 'ssl') %>
selected="selected"
<% endif %>
>SSL</option>
<option
value="tls"
<% if(settings.mta.smtp.secure == 'tls') %>
selected="selected"
<% endif %>
>TLS</option>
</select>
</td>
</tr>
<!-- smtp: authentication -->
<tr class="mailpoet_smtp_field">
<th scope="row">
<label>
<%= __('Authentication') %>
<p class="description">
<%= __('Leave this option to Yes. Only a tiny portion of SMTP services ask Authentication to be turned off.') %>
</p>
</label>
</th>
<td>
<label>
<input
type="radio"
value="1"
name="mta[smtp][authenticate]"
<% if(settings.mta.smtp.authenticate) %>
checked="checked"
<% endif %>
/><%= __('Yes') %>
</label>
&nbsp;
<label>
<input
type="radio"
value=""
name="mta[smtp][authenticate]"
<% if not(settings.mta.smtp.authenticate) %>
checked="checked"
<% endif %>
/><%= __('No') %>
</label>
</td>
</tr>
</tbody>
</table>
</div>
<table class="form-table">
<tbody>
<!-- dkim -->
<tr id="mailpoet_mta_dkim">
<th scope="row">
<label for="settings[dkim_enabled]">
<%= __('DKIM signature') %>
<p class="description">
<%= __('Improve your spam score. Mailpoet can sign all your emails with DKIM.') %>
<a
href="#todo/guide-to-dkim-in-wysija/"
target="_blank"
title=""
><%= __('Read more.') %></a>
</p>
</label>
</th>
<td>
<p>
<input
data-toggle="mailpoet_mta_dkim_content"
type="checkbox"
value="1"
id="settings[dkim_enabled]"
name="dkim[enabled]"
<% if(settings.dkim.enabled) %>checked="checked"<% endif %>
/>
</p>
<div id="mailpoet_mta_dkim_content">
<fieldset style="border: 1px solid #ccc;margin: 0;padding: 10px;">
<legend>
<%= __('Configure your DNS by adding a key/value record in TXT as shown below.') %>
<a
href="http://support.mailpoet.com/knowledgebase/guide-to-dkim-in-wysija/?utm_source=wpadmin&utm_campaign=settings"
target="_blank"
><%= __('Read more.') %></a>
</legend>
<p>
<label>
<%= __('Key') %>
<input
type="text"
onClick="this.focus();this.select();"
readonly="readonly"
value="wys._domainkey"
size="12"
/>
</label>
&nbsp;
<label>
<%= __('Value') %>
<input
type="text"
size="40"
onClick="this.focus();this.select();"
readonly="readonly"
value="v=DKIM1;s=email;t=s;p=<%= settings.dkim.public_key %>"
/>
</label>
</p>
</fieldset>
</div>
</td>
</tr>
<!-- test method -->
<tr>
<th scope="row">
<label for="mailpoet_mta_test_email">
<%= __('Test sending') %>
</label>
</th>
<td>
<p>
<input
id="mailpoet_mta_test_email"
type="text"
value="<%= current_user.user_email %>"
/>
<a
id="mailpoet_mta_test"
class="button-secondary"
><%= __('Send a test email') %></a>
</p>
</td>
</tr>
<!-- activate or cancel -->
<tr>
<th scope="row">
<p>
<a
href="javascript:;"
class="mailpoet_mta_setup_save button button-primary"
><%= __('Activate') %></a>
&nbsp;
<a
href="javascript:;"
class="mailpoet_mta_setup_cancel"
><%= __('or cancel.') %></a>
</p>
</th>
<td></td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript">
jQuery(function($) {
var sending_frequency_template =
Handlebars.compile($('#mailpoet_sending_frequency_template').html());
// om dom loaded
$(function() {
// testing sending method
$('#mailpoet_mta_test').on('click', function() {
// get form data
var data = $('#mailpoet_settings_form').serializeObject();
// get test email and include it in data
var recipient = $('#mailpoet_mta_test_email').val();
// get currently selected method
var mta_method = (
$('.mailpoet_sending_method:visible').data('method') !== undefined
)
? $('.mailpoet_sending_method:visible').data('method')
: $('#mta_method').val();
alert(
'Sending a test email to: '+recipient+
' using sending method: '+mta_method
);
});
// sending frequency update based on selected provider
$('#mailpoet_smtp_provider').on('change keyup', setProviderForm);
$('#mailpoet_web_host').on('change keyup', renderHostSendingFrequency);
// update manual sending frequency when values are changed
$('#website_frequency_emails').on('change keyup', function() {
updateSendingFrequency('website');
});
$('#website_frequency_interval').on('change keyup', function() {
updateSendingFrequency('website');
});
$('#smtp_frequency_emails').on('change keyup', function() {
updateSendingFrequency('smtp');
});
$('#smtp_frequency_interval').on('change keyup', function() {
updateSendingFrequency('smtp');
});
// save configuration of a sending method
$('.mailpoet_mta_setup_save').on('click', function() {
// get selected method
var method = $('.mailpoet_sending_method:visible').data('method'),
emails = $('#'+method+'_frequency_emails').val(),
interval = $('#'+method+'_frequency_interval').val();
// set sending method
if(method === undefined) {
MailPoet.Notice.error(
"<%= __('You have selected an invalid sending method.') %>"
);
} else {
if(
method === 'mailpoet'
&& $('#mailpoet_api_key').val().trim().length === 0
) {
MailPoet.Notice.error(
"<%= __('You need to specify a MailPoet account key') %>"
);
return false;
}
// set new sending method active
setSendingMethod(method);
// update sending frequency values
$('#mta_frequency_emails').val(emails);
$('#mta_frequency_interval').val(interval);
// back to selection of sending methods
MailPoet.Router.navigate('mta', { trigger: true });
// save settings
$('.mailpoet_settings_submit').trigger('click');
}
});
function setSendingMethod(method) {
// deactivate other sending methods
$('.mailpoet_sending_methods .mailpoet_active')
.removeClass('mailpoet_active');
// set active sending method
$('.mailpoet_sending_methods li[data-method="'+method+'"]')
.addClass('mailpoet_active');
// set smtp method value
$('#mta_method').val(method);
}
// cancel configuration of a sending method
$('.mailpoet_mta_setup_cancel').on('click', function() {
// back to selection of sending methods
MailPoet.Router.navigate('mta', { trigger: true });
});
// render sending frequency form
$('#mailpoet_smtp_provider').trigger('change');
$('#mailpoet_web_host').trigger('change');
});
function setProviderForm() {
// check provider
var provider = $(this).find('option:selected').first();
if(provider.val() === 'sendgrid') {
$('.mailpoet_smtp_field').hide();
// show only login & password fields
$('#mta_smtp_login, #mta_smtp_password').show();
} else if(provider.val() === 'elasticemail') {
$('.mailpoet_smtp_field').hide();
// show only password field
$('#mta_smtp_password').show();
} else {
// display all fields
$('.mailpoet_smtp_field').show();
}
// update sending frequency
renderSMTPSendingFrequency(provider);
}
function renderSMTPSendingFrequency() {
// set sending frequency
setSendingFrequency({
output: '#mailpoet_smtp_daily_emails',
only_daily: true,
emails: $('#smtp_frequency_emails').val(),
interval: $('#smtp_frequency_interval').val()
});
}
function renderHostSendingFrequency() {
var host = $(this).find('option:selected').first();
var emails =
host.data('emails') || <%= default_frequency.website.emails %>;
var interval =
host.data('interval') || <%= default_frequency.website.interval %>;
if(host.val() === 'manual' ) {
// hide sending frequency
$('#mailpoet_website_sending_frequency').hide();
// show manual sending frequency form
$('#mailpoet_sending_frequency_manual').slideDown(200);
// set sending frequency
setSendingFrequency({
output: '#mailpoet_website_daily_emails',
only_daily: true,
emails: $('#website_frequency_emails').val(),
interval: $('#website_frequency_interval').val()
});
} else {
$('#mailpoet_sending_frequency_manual').slideUp(200, function() {
$('#mailpoet_website_sending_frequency').show();
$('#website_frequency_emails').val(emails);
$('#website_frequency_interval').val(interval);
});
// set sending frequency
setSendingFrequency({
output: '#mailpoet_website_sending_frequency',
emails: emails,
interval: interval
});
}
}
function updateSendingFrequency(method) {
// get emails
var options = {
only_daily: true,
emails: $('#'+method+'_frequency_emails').val(),
interval: $('#'+method+'_frequency_interval').val()
};
options.daily_emails = ~~((1440 / options.interval) * options.emails);
$('#mailpoet_'+method+'_daily_emails').html(
sending_frequency_template(options)
);
// update actual sending frequency values
$('#mta_frequency_emails').val(options.emails);
$('#mta_frequency_interval').val(options.interval);
}
function setSendingFrequency(options) {
options.daily_emails = ~~((1440 / options.interval) * options.emails);
$(options.output).html(
sending_frequency_template(options)
);
}
Handlebars.registerHelper('format_time', function(value, block) {
var label = null;
var labels = {
minute: "<%= __('every minute') %>",
minutes: "<%= __('every %1$d minutes') %>",
hour: "<%= __('every hour') %>",
hours: "<%= __('every %1$d hours') %>"
};
// cast time as int
value = parseInt(value, 10);
// format time depending on the value
if(value >= 60) {
// we're dealing with hours
if(value === 60) {
label = labels.hour;
} else {
label = labels.hours;
}
value /= 60;
} else {
// we're dealing with minutes
if(value === 1) {
label = labels.minute;
} else {
label = labels.minutes;
}
}
if(label !== null) {
return label.replace('%1$d', value);
} else {
return value;
}
});
});
</script>
<%= partial(
'mailpoet_sending_frequency_template',
'settings/templates/sending_frequency.hbs'
) %>

219
views/settings/signup.html Normal file
View File

@ -0,0 +1,219 @@
<table class="form-table">
<tbody>
<!-- enable signup confirmation -->
<tr>
<th scope="row">
<label>
<%= __('Enable signup confirmation') %>
<p class="description">
<%= __('Prevent people from being subscribed to your list unwillingly,this option ensures you to keep a clean list.') %>
<a href="#TODO" target="_blank"><%= __('Learn more.') %></a>
</p>
</label>
</th>
<td>
<p>
<label>
<input
type="radio"
class="mailpoet_signup_confirmation"
name="signup_confirmation[enabled]"
value="1"
<% if(settings.signup_confirmation.enabled) %>
checked="checked"
<% endif %>
/><%= __('Yes') %>
</label>
&nbsp;
<label>
<input
type="radio"
class="mailpoet_signup_confirmation"
name="signup_confirmation[enabled]"
value=""
<% if not(settings.signup_confirmation.enabled) %>
checked="checked"
<% endif %>
/><%= __('No') %>
</label>
</p>
</td>
</tr>
</tbody>
</table>
<table id="mailpoet_signup_options" class="form-table">
<tbody>
<!-- signup confirmation: from name & email -->
<tr>
<th scope="row">
<label for="settings[signup_confirmation_from_name]">
<%= __('From') %>
</label>
</th>
<td>
<p>
<input
type="text"
id="settings[signup_confirmation_from_name]"
name="signup_confirmation[from][name]"
value="<%= settings.signup_confirmation.from.name %>"
placeholder="<%= __('Your name') %>"
/>
<input
type="text"
id="settings[signup_confirmation_from_email]"
name="signup_confirmation[from][address]"
value="<%= settings.signup_confirmation.from.address %>"
placeholder="confirmation@mydomain.com"
size="28"
/>
</p>
</td>
</tr>
<!-- signup confirmation: reply_to name & email -->
<tr>
<th scope="row">
<label for="settings[signup_confirmation_reply_name]">
<%= __('Reply-to') %>
</label>
</th>
<td>
<p>
<input
type="text"
id="settings[signup_confirmation_reply_name]"
name="signup_confirmation[reply_to][name]"
value="<%= settings.signup_confirmation.reply_to.name %>"
placeholder="<%= __('Your name') %>"
/>
<input
type="text"
id="settings[signup_confirmation_reply_email]"
name="signup_confirmation[reply_to][address]"
value="<%= settings.signup_confirmation.reply_to.address %>"
placeholder="confirmation@mydomain.com"
size="28"
/>
</p>
</td>
</tr>
<!-- confirmation email: title -->
<tr>
<th scope="row">
<label for="settings[signup_confirmation_email_subject]">
<%= __('Email subject') %>
</label>
</th>
<td>
<input
size="52"
type="text"
id="settings[signup_confirmation_email_subject]"
name="signup_confirmation[subject]"
<% if(settings.signup_confirmation.subject) %>
value="<%= settings.signup_confirmation.subject %>"
<% else %>
value="<%=
__('Confirm your subscription to %1$s')
| format(get_option('blogname'))
%>"
<% endif %>
/>
</td>
</tr>
<!-- confirmation email: body -->
<tr>
<th scope="row">
<label for="settings[signup_confirmation_email_body]">
<%= __('Email content') %>
<p class="description">
<%= __("Don't forget to include:<br /><br />[activation_link]Confirm your subscription.[/activation_link].<br /><br />Optional: [lists_to_confirm].") %>
</p>
</label>
</th>
<td>
<textarea
cols="50"
rows="15"
id="settings[signup_confirmation_email_body]"
name="signup_confirmation[body]"
><% if(settings.signup_confirmation.body) %>
<%=- settings.signup_confirmation.body -%>
<% else %>
<%=- __("Hello!\n\nHurray! You've subscribed to our site.\nWe need you to activate your subscription to the list(s): [lists_to_confirm] by clicking the link below: \n\n[activation_link]Click here to confirm your subscription.[/activation_link]\n\nThank you,\n\nThe team!") -%>
<% endif %></textarea>
</td>
</tr>
<!-- signup confirmation: confirmation page -->
<tr>
<th scope="row">
<label>
<%= __('Confirmation page') %>
<p class="description">
<%= __('When subscribers click on the activation link, they are redirected to a page of your choice.') %>
</p>
</label>
</th>
<td>
<p>
<select
class="mailpoet_page_selection"
name="signup_confirmation[page]"
>
<% for page in pages %>
<option
value="<%= page.id %>"
data-preview-url="<%= page.preview_url|raw %>"
data-edit-url="<%= page.edit_url|raw %>"
<% if(page.id == settings.signup_confirmation.page) %>
selected="selected"
<% endif %>
><%= page.title %></option>
<% endfor %>
</select>
<a
class="mailpoet_page_preview"
href="javascript:;"
title="<%= __('Preview page') %>"
><%= __('Preview') %></a>&nbsp;|&nbsp;<a
class="mailpoet_page_edit"
href="javascript:;"
title="<%= __('Edit page') %>"
><%= __('Edit') %></a>
</p>
</td>
</tr>
</tbody>
</table>
<script type="text/javascript">
jQuery(function($) {
// om dom loaded
$(function() {
// double optin toggling
toggleSignupOptions();
$('.mailpoet_signup_confirmation').on('click', function() {
var result = false;
if(parseInt($(this).val(), 10) === 1) {
result = confirm("<%= __('Subscribers will now need to activate their subscription by email in order to receive your newsletters. This is recommended.') %>");
} else {
result = confirm("<%= __('Unconfirmed subscribers will receive your newsletters from now on without the need to activate their subscriptions.') %>");
}
// if the user confirmed changing the signup confirmation (yes/no)
if(result === true) {
// toggle signup options depending on the currently selected value
toggleSignupOptions();
}
return result;
});
function toggleSignupOptions() {
var is_enabled =
(parseInt($('.mailpoet_signup_confirmation:checked').val(), 10) === 1);
$('#mailpoet_signup_options')[(is_enabled) ? 'show' : 'hide']();
}
});
});
</script>

View File

@ -0,0 +1,14 @@
{{#unless only_daily}}
<!-- number of emails & frequency -->
<%=
__('%1$s emails')
| format('{{ emails }}')
%> {{ format_time interval }}.
{{/unless}}
<!-- number of emails per day -->
<%=
__("That's <strong>%1$s emails</strong> per day.")
| format('{{ daily_emails }}')
| raw
%>

View File

@ -66,10 +66,10 @@ config.push(_.extend({}, baseConfig, {
'jquery.serialize_object'
],
admin: [
'settings.jsx',
'subscribers/subscribers.jsx',
'newsletters/newsletters.jsx',
'segments/segments.jsx'
'segments/segments.jsx',
'settings/tabs.js'
],
newsletter_editor: [
'underscore',