Conditional display of statistics column (for standard)
- improved duplicate action (for standard) - moved STATUS_COMPLETED constant from worker to SendingQueue model where it belongs
This commit is contained in:
@ -676,6 +676,12 @@ define(
|
|||||||
sort_by = this.state.sort_by,
|
sort_by = this.state.sort_by,
|
||||||
sort_order = this.state.sort_order;
|
sort_order = this.state.sort_order;
|
||||||
|
|
||||||
|
// columns
|
||||||
|
var columns = this.props.columns || [];
|
||||||
|
columns = columns.filter(function(column) {
|
||||||
|
return (column.display === undefined || !!(column.display) === true);
|
||||||
|
});
|
||||||
|
|
||||||
// bulk actions
|
// bulk actions
|
||||||
var bulk_actions = this.props.bulk_actions || [];
|
var bulk_actions = this.props.bulk_actions || [];
|
||||||
|
|
||||||
@ -761,7 +767,7 @@ define(
|
|||||||
selection={ this.state.selection }
|
selection={ this.state.selection }
|
||||||
sort_by={ sort_by }
|
sort_by={ sort_by }
|
||||||
sort_order={ sort_order }
|
sort_order={ sort_order }
|
||||||
columns={ this.props.columns }
|
columns={ columns }
|
||||||
is_selectable={ bulk_actions.length > 0 } />
|
is_selectable={ bulk_actions.length > 0 } />
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
@ -771,7 +777,7 @@ define(
|
|||||||
onRestoreItem={ this.handleRestoreItem }
|
onRestoreItem={ this.handleRestoreItem }
|
||||||
onTrashItem={ this.handleTrashItem }
|
onTrashItem={ this.handleTrashItem }
|
||||||
onRefreshItems={ this.handleRefreshItems }
|
onRefreshItems={ this.handleRefreshItems }
|
||||||
columns={ this.props.columns }
|
columns={ columns }
|
||||||
is_selectable={ bulk_actions.length > 0 }
|
is_selectable={ bulk_actions.length > 0 }
|
||||||
onSelectItem={ this.handleSelectItem }
|
onSelectItem={ this.handleSelectItem }
|
||||||
onSelectAll={ this.handleSelectAll }
|
onSelectAll={ this.handleSelectAll }
|
||||||
@ -791,7 +797,7 @@ define(
|
|||||||
selection={ this.state.selection }
|
selection={ this.state.selection }
|
||||||
sort_by={ sort_by }
|
sort_by={ sort_by }
|
||||||
sort_order={ sort_order }
|
sort_order={ sort_order }
|
||||||
columns={ this.props.columns }
|
columns={ columns }
|
||||||
is_selectable={ bulk_actions.length > 0 } />
|
is_selectable={ bulk_actions.length > 0 } />
|
||||||
</tfoot>
|
</tfoot>
|
||||||
|
|
||||||
|
@ -68,17 +68,12 @@ var columns = [
|
|||||||
label: MailPoet.I18n.t('status')
|
label: MailPoet.I18n.t('status')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'segments',
|
name: 'settings',
|
||||||
label: MailPoet.I18n.t('lists')
|
label: MailPoet.I18n.t('settings')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'statistics',
|
name: 'history',
|
||||||
label: MailPoet.I18n.t('statistics')
|
label: MailPoet.I18n.t('history')
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'created_at',
|
|
||||||
label: MailPoet.I18n.t('createdOn'),
|
|
||||||
sortable: true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'updated_at',
|
name: 'updated_at',
|
||||||
@ -96,6 +91,16 @@ var bulk_actions = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
var newsletter_actions = [
|
var newsletter_actions = [
|
||||||
|
{
|
||||||
|
name: 'view',
|
||||||
|
link: function(newsletter) {
|
||||||
|
return (
|
||||||
|
<a href={ newsletter.preview_url } target="_blank">
|
||||||
|
{MailPoet.I18n.t('preview')}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'edit',
|
name: 'edit',
|
||||||
link: function(newsletter) {
|
link: function(newsletter) {
|
||||||
@ -106,6 +111,26 @@ var newsletter_actions = [
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'duplicate',
|
||||||
|
label: MailPoet.I18n.t('duplicate'),
|
||||||
|
onClick: function(newsletter, refresh) {
|
||||||
|
return MailPoet.Ajax.post({
|
||||||
|
endpoint: 'newsletters',
|
||||||
|
action: 'duplicate',
|
||||||
|
data: newsletter.id
|
||||||
|
}).done(function(response) {
|
||||||
|
if (response !== false && response.subject !== undefined) {
|
||||||
|
MailPoet.Notice.success(
|
||||||
|
(MailPoet.I18n.t('newsletterDuplicated')).replace(
|
||||||
|
'%$1s', response.subject
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'trash'
|
name: 'trash'
|
||||||
}
|
}
|
||||||
@ -158,31 +183,6 @@ const NewsletterListNotification = React.createClass({
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
renderStatistics: function(newsletter) {
|
|
||||||
if (!newsletter.statistics || !newsletter.queue || newsletter.queue.count_processed == 0 || newsletter.queue.status === 'scheduled') {
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
{MailPoet.I18n.t('notSentYet')}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var percentage_clicked = Math.round(
|
|
||||||
(newsletter.statistics.clicked * 100) / (newsletter.queue.count_processed)
|
|
||||||
);
|
|
||||||
var percentage_opened = Math.round(
|
|
||||||
(newsletter.statistics.opened * 100) / (newsletter.queue.count_processed)
|
|
||||||
);
|
|
||||||
var percentage_unsubscribed = Math.round(
|
|
||||||
(newsletter.statistics.unsubscribed * 100) / (newsletter.queue.count_processed)
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
{ percentage_opened }%, { percentage_clicked }%, { percentage_unsubscribed }%
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
renderItem: function(newsletter, actions) {
|
renderItem: function(newsletter, actions) {
|
||||||
var rowClasses = classNames(
|
var rowClasses = classNames(
|
||||||
'manage-column',
|
'manage-column',
|
||||||
@ -190,10 +190,6 @@ const NewsletterListNotification = React.createClass({
|
|||||||
'has-row-actions'
|
'has-row-actions'
|
||||||
);
|
);
|
||||||
|
|
||||||
var segments = newsletter.segments.map(function(segment) {
|
|
||||||
return segment.name
|
|
||||||
}).join(', ');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<td className={ rowClasses }>
|
<td className={ rowClasses }>
|
||||||
@ -207,14 +203,11 @@ const NewsletterListNotification = React.createClass({
|
|||||||
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
|
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
|
||||||
{ this.renderStatus(newsletter) }
|
{ this.renderStatus(newsletter) }
|
||||||
</td>
|
</td>
|
||||||
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
|
<td className="column" data-colname={ MailPoet.I18n.t('settings') }>
|
||||||
{ segments }
|
{ this.renderSettings(newsletter) }
|
||||||
</td>
|
</td>
|
||||||
<td className="column" data-colname={ MailPoet.I18n.t('statistics') }>
|
<td className="column" data-colname={ MailPoet.I18n.t('history') }>
|
||||||
{ this.renderStatistics(newsletter) }
|
<a href="#TODO">{ MailPoet.I18n.t('viewHistory') }</a>
|
||||||
</td>
|
|
||||||
<td className="column-date" data-colname={ MailPoet.I18n.t('createdOn') }>
|
|
||||||
<abbr>{ MailPoet.Date.format(newsletter.created_at) }</abbr>
|
|
||||||
</td>
|
</td>
|
||||||
<td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }>
|
<td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }>
|
||||||
<abbr>{ MailPoet.Date.format(newsletter.updated_at) }</abbr>
|
<abbr>{ MailPoet.Date.format(newsletter.updated_at) }</abbr>
|
||||||
|
@ -9,6 +9,8 @@ import classNames from 'classnames'
|
|||||||
import jQuery from 'jquery'
|
import jQuery from 'jquery'
|
||||||
import MailPoet from 'mailpoet'
|
import MailPoet from 'mailpoet'
|
||||||
|
|
||||||
|
const mailpoet_tracking_enabled = (!!(window['mailpoet_tracking_enabled']));
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
onTrash(response) {
|
onTrash(response) {
|
||||||
const count = ~~response;
|
const count = ~~response;
|
||||||
@ -73,7 +75,8 @@ var columns = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'statistics',
|
name: 'statistics',
|
||||||
label: MailPoet.I18n.t('statistics')
|
label: MailPoet.I18n.t('statistics'),
|
||||||
|
display: mailpoet_tracking_enabled
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'updated_at',
|
name: 'updated_at',
|
||||||
@ -82,6 +85,7 @@ var columns = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
var bulk_actions = [
|
var bulk_actions = [
|
||||||
{
|
{
|
||||||
name: 'trash',
|
name: 'trash',
|
||||||
@ -231,30 +235,33 @@ const NewsletterListStandard = React.createClass({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderStatistics: function(item) {
|
renderStatistics: function(newsletter) {
|
||||||
if(!item.statistics || !item.queue || item.queue.count_processed == 0 || item.queue.status === 'scheduled') {
|
if (mailpoet_tracking_enabled === false) {
|
||||||
return (
|
return;
|
||||||
<span>
|
|
||||||
{MailPoet.I18n.t('notSentYet')}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var percentage_clicked = Math.round(
|
if(newsletter.statistics && newsletter.queue && newsletter.queue.status !== 'scheduled') {
|
||||||
(item.statistics.clicked * 100) / (item.queue.count_processed)
|
const total_sent = ~~(newsletter.queue.count_processed);
|
||||||
);
|
const percentage_clicked = Math.round(
|
||||||
var percentage_opened = Math.round(
|
(~~(newsletter.statistics.clicked) * 100) / total_sent
|
||||||
(item.statistics.opened * 100) / (item.queue.count_processed)
|
);
|
||||||
);
|
const percentage_opened = Math.round(
|
||||||
var percentage_unsubscribed = Math.round(
|
(~~(newsletter.statistics.opened) * 100) / total_sent
|
||||||
(item.statistics.unsubscribed * 100) / (item.queue.count_processed)
|
);
|
||||||
);
|
const percentage_unsubscribed = Math.round(
|
||||||
|
(~~(newsletter.statistics.unsubscribed) * 100) / total_sent
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{ percentage_opened }%, { percentage_clicked }%, { percentage_unsubscribed }%
|
{ percentage_opened }%, { percentage_clicked }%, { percentage_unsubscribed }%
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<span>{MailPoet.I18n.t('notSentYet')}</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
renderItem: function(newsletter, actions) {
|
renderItem: function(newsletter, actions) {
|
||||||
var rowClasses = classNames(
|
var rowClasses = classNames(
|
||||||
@ -283,9 +290,11 @@ const NewsletterListStandard = React.createClass({
|
|||||||
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
|
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
|
||||||
{ segments }
|
{ segments }
|
||||||
</td>
|
</td>
|
||||||
<td className="column" data-colname={ MailPoet.I18n.t('statistics') }>
|
{(mailpoet_tracking_enabled === true) ? (
|
||||||
{ this.renderStatistics(newsletter) }
|
<td className="column" data-colname={ MailPoet.I18n.t('statistics') }>
|
||||||
</td>
|
{ this.renderStatistics(newsletter) }
|
||||||
|
</td>
|
||||||
|
) : null }
|
||||||
<td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }>
|
<td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }>
|
||||||
<abbr>{ MailPoet.Date.format(newsletter.updated_at) }</abbr>
|
<abbr>{ MailPoet.Date.format(newsletter.updated_at) }</abbr>
|
||||||
</td>
|
</td>
|
||||||
|
@ -8,6 +8,7 @@ import ListingTabs from 'newsletters/listings/tabs.jsx'
|
|||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import jQuery from 'jquery'
|
import jQuery from 'jquery'
|
||||||
import MailPoet from 'mailpoet'
|
import MailPoet from 'mailpoet'
|
||||||
|
import _ from 'underscore'
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
onTrash(response) {
|
onTrash(response) {
|
||||||
@ -165,21 +166,48 @@ const NewsletterListWelcome = React.createClass({
|
|||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
renderStatus: function(newsletter) {
|
renderStatus: function(newsletter) {
|
||||||
|
let total_sent;
|
||||||
|
total_sent = (
|
||||||
|
MailPoet.I18n.t('sentToXSubscribers')
|
||||||
|
.replace('%$1d', newsletter.total_sent)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<select
|
<div>
|
||||||
data-id={ newsletter.id }
|
<select
|
||||||
defaultValue={ newsletter.status }
|
data-id={ newsletter.id }
|
||||||
onChange={ this.updateStatus }
|
defaultValue={ newsletter.status }
|
||||||
>
|
onChange={ this.updateStatus }
|
||||||
<option value="active">{ MailPoet.I18n.t('active') }</option>
|
>
|
||||||
<option value="draft">{ MailPoet.I18n.t('inactive') }</option>
|
<option value="active">{ MailPoet.I18n.t('active') }</option>
|
||||||
</select>
|
<option value="draft">{ MailPoet.I18n.t('inactive') }</option>
|
||||||
|
</select>
|
||||||
|
<p>{ total_sent }</p>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
renderSettings: function(newsletter) {
|
renderSettings: function(newsletter) {
|
||||||
|
let settings;
|
||||||
|
|
||||||
|
switch (newsletter.options.event) {
|
||||||
|
case 'user':
|
||||||
|
// WP User
|
||||||
|
settings = MailPoet.I18n.t('onWordpressUserRegistration');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'segment':
|
||||||
|
// get segment
|
||||||
|
const segment = _.find(mailpoet_segments, function(segment) {
|
||||||
|
return (~~(segment.id) === ~~(newsletter.options.segment));
|
||||||
|
});
|
||||||
|
|
||||||
|
settings = MailPoet.I18n.t('onSubscriptionToList') + ' ' +segment.name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
Settings...
|
{ settings }
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -413,6 +413,8 @@ class Menu {
|
|||||||
24
|
24
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$data['tracking_enabled'] = Setting::getValue('tracking.enabled');
|
||||||
|
|
||||||
wp_enqueue_script('jquery-ui');
|
wp_enqueue_script('jquery-ui');
|
||||||
wp_enqueue_script('jquery-ui-datepicker');
|
wp_enqueue_script('jquery-ui-datepicker');
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ namespace MailPoet\Cron\Workers;
|
|||||||
use MailPoet\Cron\CronHelper;
|
use MailPoet\Cron\CronHelper;
|
||||||
use MailPoet\Mailer\Mailer;
|
use MailPoet\Mailer\Mailer;
|
||||||
use MailPoet\Models\Newsletter;
|
use MailPoet\Models\Newsletter;
|
||||||
|
use MailPoet\Models\SendingQueue as SendingQueueModel;
|
||||||
use MailPoet\Models\NewsletterPost;
|
use MailPoet\Models\NewsletterPost;
|
||||||
use MailPoet\Models\Setting;
|
use MailPoet\Models\Setting;
|
||||||
use MailPoet\Models\StatisticsNewsletters;
|
use MailPoet\Models\StatisticsNewsletters;
|
||||||
@ -23,7 +24,6 @@ class SendingQueue {
|
|||||||
private $timer;
|
private $timer;
|
||||||
const BATCH_SIZE = 50;
|
const BATCH_SIZE = 50;
|
||||||
const DIVIDER = '***MailPoet***';
|
const DIVIDER = '***MailPoet***';
|
||||||
const STATUS_COMPLETED = 'completed';
|
|
||||||
|
|
||||||
function __construct($timer = false) {
|
function __construct($timer = false) {
|
||||||
$this->mta_config = $this->getMailerConfig();
|
$this->mta_config = $this->getMailerConfig();
|
||||||
@ -295,7 +295,7 @@ class SendingQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getQueues() {
|
function getQueues() {
|
||||||
return \MailPoet\Models\SendingQueue::orderByDesc('priority')
|
return SendingQueueModel::orderByDesc('priority')
|
||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
->whereNull('status')
|
->whereNull('status')
|
||||||
->findResultSet();
|
->findResultSet();
|
||||||
@ -321,7 +321,7 @@ class SendingQueue {
|
|||||||
$queue->count_processed + $queue->count_to_process;
|
$queue->count_processed + $queue->count_to_process;
|
||||||
if(!$queue->count_to_process) {
|
if(!$queue->count_to_process) {
|
||||||
$queue->processed_at = current_time('mysql');
|
$queue->processed_at = current_time('mysql');
|
||||||
$queue->status = self::STATUS_COMPLETED;
|
$queue->status = SendingQueueModel::STATUS_COMPLETED;
|
||||||
}
|
}
|
||||||
$queue->subscribers = serialize((array) $queue->subscribers);
|
$queue->subscribers = serialize((array) $queue->subscribers);
|
||||||
$queue->save();
|
$queue->save();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Models;
|
namespace MailPoet\Models;
|
||||||
|
use MailPoet\Util\Helpers;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
@ -55,11 +56,19 @@ class Newsletter extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function duplicate($data = array()) {
|
function duplicate($data = array()) {
|
||||||
$data = $this->asArray();
|
// get current newsletter's data as an array
|
||||||
unset($data['id']);
|
$newsletter_data = $this->asArray();
|
||||||
|
|
||||||
$duplicate = self::create();
|
// remove id so that it creates a new record
|
||||||
|
unset($newsletter_data['id']);
|
||||||
|
|
||||||
|
// merge data with newsletter data (allows override)
|
||||||
|
$data = array_merge($newsletter_data, $data);
|
||||||
|
|
||||||
|
$duplicate = self::create();
|
||||||
$duplicate->hydrate($data);
|
$duplicate->hydrate($data);
|
||||||
|
|
||||||
|
// reset timestamps
|
||||||
$duplicate->set_expr('created_at', 'NOW()');
|
$duplicate->set_expr('created_at', 'NOW()');
|
||||||
$duplicate->set_expr('updated_at', 'NOW()');
|
$duplicate->set_expr('updated_at', 'NOW()');
|
||||||
$duplicate->set_expr('deleted_at', 'NULL');
|
$duplicate->set_expr('deleted_at', 'NULL');
|
||||||
@ -67,15 +76,25 @@ class Newsletter extends Model {
|
|||||||
// reset status
|
// reset status
|
||||||
$duplicate->set('status', self::STATUS_DRAFT);
|
$duplicate->set('status', self::STATUS_DRAFT);
|
||||||
|
|
||||||
// TODO: duplicate segments linked (if need be)
|
$duplicate->save();
|
||||||
|
|
||||||
// TODO: duplicate options (if need be)
|
if($duplicate->getErrors() === false) {
|
||||||
|
// create relationships between duplicate and segments
|
||||||
|
$segments = $this->segments()->findArray();
|
||||||
|
|
||||||
if($duplicate->save()) {
|
if(!empty($segments)) {
|
||||||
return $duplicate;
|
foreach($segments as $segment) {
|
||||||
} else {
|
$relation = NewsletterSegment::create();
|
||||||
return false;
|
$relation->segment_id = $segment['id'];
|
||||||
|
$relation->newsletter_id = $duplicate->id();
|
||||||
|
$result = $relation->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: duplicate options (if need be)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $duplicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
function asArray() {
|
function asArray() {
|
||||||
@ -133,6 +152,24 @@ class Newsletter extends Model {
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function withOptions() {
|
||||||
|
$options = $this->options()->findArray();
|
||||||
|
if(empty($options)) {
|
||||||
|
$this->options = array();
|
||||||
|
} else {
|
||||||
|
$this->options = Helpers::arrayColumn($options, 'value', 'name');
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
function withTotalSent() {
|
||||||
|
// total of subscribers who received the email
|
||||||
|
$this->total_sent = (int)SendingQueue::where('newsletter_id', $this->id)
|
||||||
|
->where('status', SendingQueue::STATUS_COMPLETED)
|
||||||
|
->sum('count_processed');
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
function withStatistics() {
|
function withStatistics() {
|
||||||
$statistics = $this->getStatistics();
|
$statistics = $this->getStatistics();
|
||||||
if($statistics === false) {
|
if($statistics === false) {
|
||||||
@ -140,6 +177,7 @@ class Newsletter extends Model {
|
|||||||
} else {
|
} else {
|
||||||
$this->statistics = $statistics->asArray();
|
$this->statistics = $statistics->asArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,9 +187,9 @@ class Newsletter extends Model {
|
|||||||
}
|
}
|
||||||
return SendingQueue::tableAlias('queues')
|
return SendingQueue::tableAlias('queues')
|
||||||
->selectExpr(
|
->selectExpr(
|
||||||
'count(DISTINCT(clicks.subscriber_id)) as clicked, ' .
|
'COUNT(DISTINCT(clicks.subscriber_id)) as clicked, ' .
|
||||||
'count(DISTINCT(opens.subscriber_id)) as opened, ' .
|
'COUNT(DISTINCT(opens.subscriber_id)) as opened, ' .
|
||||||
'count(DISTINCT(unsubscribes.subscriber_id)) as unsubscribed '
|
'COUNT(DISTINCT(unsubscribes.subscriber_id)) as unsubscribed '
|
||||||
)
|
)
|
||||||
->leftOuterJoin(
|
->leftOuterJoin(
|
||||||
MP_STATISTICS_CLICKS_TABLE,
|
MP_STATISTICS_CLICKS_TABLE,
|
||||||
@ -299,14 +337,6 @@ class Newsletter extends Model {
|
|||||||
case self::TYPE_WELCOME:
|
case self::TYPE_WELCOME:
|
||||||
case self::TYPE_NOTIFICATION:
|
case self::TYPE_NOTIFICATION:
|
||||||
$groups = array_merge($groups, array(
|
$groups = array_merge($groups, array(
|
||||||
array(
|
|
||||||
'name' => self::STATUS_DRAFT,
|
|
||||||
'label' => __('Not active'),
|
|
||||||
'count' => Newsletter::getPublished()
|
|
||||||
->filter('filterType', $type)
|
|
||||||
->filter('filterStatus', self::STATUS_DRAFT)
|
|
||||||
->count()
|
|
||||||
),
|
|
||||||
array(
|
array(
|
||||||
'name' => self::STATUS_ACTIVE,
|
'name' => self::STATUS_ACTIVE,
|
||||||
'label' => __('Active'),
|
'label' => __('Active'),
|
||||||
@ -314,6 +344,14 @@ class Newsletter extends Model {
|
|||||||
->filter('filterType', $type)
|
->filter('filterType', $type)
|
||||||
->filter('filterStatus', self::STATUS_ACTIVE)
|
->filter('filterStatus', self::STATUS_ACTIVE)
|
||||||
->count()
|
->count()
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => self::STATUS_DRAFT,
|
||||||
|
'label' => __('Not active'),
|
||||||
|
'count' => Newsletter::getPublished()
|
||||||
|
->filter('filterType', $type)
|
||||||
|
->filter('filterStatus', self::STATUS_DRAFT)
|
||||||
|
->count()
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
@ -379,7 +417,15 @@ class Newsletter extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static function listingQuery($data = array()) {
|
static function listingQuery($data = array()) {
|
||||||
return self::filter('filterType', $data['tab'])
|
return self::select(array(
|
||||||
|
'id',
|
||||||
|
'subject',
|
||||||
|
'type',
|
||||||
|
'status',
|
||||||
|
'updated_at',
|
||||||
|
'deleted_at'
|
||||||
|
))
|
||||||
|
->filter('filterType', $data['tab'])
|
||||||
->filter('filterBy', $data)
|
->filter('filterBy', $data)
|
||||||
->filter('groupBy', $data)
|
->filter('groupBy', $data)
|
||||||
->filter('search', $data['search']);
|
->filter('search', $data['search']);
|
||||||
|
@ -6,6 +6,8 @@ if(!defined('ABSPATH')) exit;
|
|||||||
class SendingQueue extends Model {
|
class SendingQueue extends Model {
|
||||||
public static $_table = MP_SENDING_QUEUES_TABLE;
|
public static $_table = MP_SENDING_QUEUES_TABLE;
|
||||||
|
|
||||||
|
const STATUS_COMPLETED = 'completed';
|
||||||
|
|
||||||
function __construct() {
|
function __construct() {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
@ -150,9 +150,13 @@ class Newsletters {
|
|||||||
|
|
||||||
$newsletter = Newsletter::findOne($id);
|
$newsletter = Newsletter::findOne($id);
|
||||||
if($newsletter !== false) {
|
if($newsletter !== false) {
|
||||||
$result = $newsletter->duplicate(array(
|
$duplicate = $newsletter->duplicate(array(
|
||||||
'subject' => sprintf(__('Copy of %s'), $newsletter->subject)
|
'subject' => sprintf(__('Copy of %s'), $newsletter->subject)
|
||||||
))->asArray();
|
));
|
||||||
|
|
||||||
|
if($duplicate !== false && $duplicate->getErrors() === false) {
|
||||||
|
$result = $newsletter->asArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
@ -256,7 +260,13 @@ class Newsletters {
|
|||||||
->withStatistics();
|
->withStatistics();
|
||||||
} else if($newsletter->type === Newsletter::TYPE_WELCOME) {
|
} else if($newsletter->type === Newsletter::TYPE_WELCOME) {
|
||||||
$newsletter
|
$newsletter
|
||||||
|
->withOptions()
|
||||||
|
->withTotalSent()
|
||||||
->withStatistics();
|
->withStatistics();
|
||||||
|
|
||||||
|
$options = $newsletter->options()->findArray();
|
||||||
|
$newsletter->options = Helpers::arrayColumn($options, 'value', 'name');
|
||||||
|
|
||||||
} else if($newsletter->type === Newsletter::TYPE_NOTIFICATION) {
|
} else if($newsletter->type === Newsletter::TYPE_NOTIFICATION) {
|
||||||
$newsletter
|
$newsletter
|
||||||
->withSegments()
|
->withSegments()
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
var mailpoet_schedule_time_of_day = <%= json_encode(schedule_time_of_day) %>;
|
var mailpoet_schedule_time_of_day = <%= json_encode(schedule_time_of_day) %>;
|
||||||
var mailpoet_date_display_format = "<%= wp_date_format() %>";
|
var mailpoet_date_display_format = "<%= wp_date_format() %>";
|
||||||
var mailpoet_date_storage_format = "Y-m-d";
|
var mailpoet_date_storage_format = "Y-m-d";
|
||||||
|
var mailpoet_tracking_enabled = <%= json_encode(tracking_enabled) %>;
|
||||||
</script>
|
</script>
|
||||||
<% endblock %>
|
<% endblock %>
|
||||||
|
|
||||||
@ -61,6 +62,8 @@
|
|||||||
'statistics': __('Opened, Clicked, Unsubscribed'),
|
'statistics': __('Opened, Clicked, Unsubscribed'),
|
||||||
'lists': __('Lists'),
|
'lists': __('Lists'),
|
||||||
'settings': __('Settings'),
|
'settings': __('Settings'),
|
||||||
|
'history': __('History'),
|
||||||
|
'viewHistory': __('View history'),
|
||||||
'createdOn': __('Created on'),
|
'createdOn': __('Created on'),
|
||||||
'lastModifiedOn': __('Last modified on'),
|
'lastModifiedOn': __('Last modified on'),
|
||||||
'oneNewsletterTrashed': __('1 newsletter was moved to the trash.'),
|
'oneNewsletterTrashed': __('1 newsletter was moved to the trash.'),
|
||||||
@ -79,6 +82,7 @@
|
|||||||
'active': __('Active'),
|
'active': __('Active'),
|
||||||
'inactive': __('Not Active'),
|
'inactive': __('Not Active'),
|
||||||
'newsletterQueueCompleted': __('Sent to %$1d of %$2d.'),
|
'newsletterQueueCompleted': __('Sent to %$1d of %$2d.'),
|
||||||
|
'sentToXSubscribers': __('Sent to %$1d subscribers.'),
|
||||||
'resume': __('Resume'),
|
'resume': __('Resume'),
|
||||||
'pause': __('Pause'),
|
'pause': __('Pause'),
|
||||||
'new': __('New'),
|
'new': __('New'),
|
||||||
@ -133,7 +137,7 @@
|
|||||||
'selectEventToSendWelcomeEmail': __('Select an event to send this welcome email'),
|
'selectEventToSendWelcomeEmail': __('Select an event to send this welcome email'),
|
||||||
|
|
||||||
'onSubscriptionToList': __('When someone subscribes to the list...'),
|
'onSubscriptionToList': __('When someone subscribes to the list...'),
|
||||||
'onWordpressUserRegistration': __('When a new Wordrpess user is added to your site...'),
|
'onWordpressUserRegistration': __('When a new WordPress user is added to your site...'),
|
||||||
'delayImmediately': __('immediately'),
|
'delayImmediately': __('immediately'),
|
||||||
'delayHoursAfter': __('hour(s) after'),
|
'delayHoursAfter': __('hour(s) after'),
|
||||||
'delayDaysAfter': __('day(s) after'),
|
'delayDaysAfter': __('day(s) after'),
|
||||||
|
Reference in New Issue
Block a user