Merge pull request #391 from mailpoet/scheduled_sending
Scheduled sending
This commit is contained in:
@ -53,13 +53,13 @@ define(
|
|||||||
var weekDayField = {
|
var weekDayField = {
|
||||||
name: 'weekDay',
|
name: 'weekDay',
|
||||||
values: {
|
values: {
|
||||||
0: 'Monday',
|
0: 'Sunday',
|
||||||
1: 'Tuesday',
|
1: 'Monday',
|
||||||
2: 'Wednesday',
|
2: 'Tuesday',
|
||||||
3: 'Thursday',
|
3: 'Wednesday',
|
||||||
4: 'Friday',
|
4: 'Thursday',
|
||||||
5: 'Saturday',
|
5: 'Friday',
|
||||||
6: 'Sunday',
|
6: 'Saturday'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -84,10 +84,10 @@ define(
|
|||||||
var nthWeekDayField = {
|
var nthWeekDayField = {
|
||||||
name: 'nthWeekDay',
|
name: 'nthWeekDay',
|
||||||
values: {
|
values: {
|
||||||
'0': '1st',
|
'1': '1st',
|
||||||
'1': '2nd',
|
'2': '2nd',
|
||||||
'2': '3rd',
|
'3': '3rd',
|
||||||
'3': 'last',
|
'L': 'last',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -99,9 +99,9 @@ define(
|
|||||||
return {
|
return {
|
||||||
intervalType: 'immediate', // 'immediate'|'daily'|'weekly'|'monthly'
|
intervalType: 'immediate', // 'immediate'|'daily'|'weekly'|'monthly'
|
||||||
timeOfDay: 0,
|
timeOfDay: 0,
|
||||||
weekDay: 0,
|
weekDay: 1,
|
||||||
monthDay: 0,
|
monthDay: 0,
|
||||||
nthWeekDay: 0,
|
nthWeekDay: 1,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
handleIntervalChange: function(event) {
|
handleIntervalChange: function(event) {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"j4mie/paris": "1.5.4",
|
"j4mie/paris": "1.5.4",
|
||||||
"swiftmailer/swiftmailer": "^5.4",
|
"swiftmailer/swiftmailer": "^5.4",
|
||||||
"phpseclib/phpseclib": "*",
|
"phpseclib/phpseclib": "*",
|
||||||
"mtdowling/cron-expression": "^1.0",
|
"mtdowling/cron-expression": "^1.1",
|
||||||
"nesbot/carbon": "^1.21",
|
"nesbot/carbon": "^1.21",
|
||||||
"soundasleep/html2text": "^0.3.0"
|
"soundasleep/html2text": "^0.3.0"
|
||||||
},
|
},
|
||||||
|
10
composer.lock
generated
10
composer.lock
generated
@ -4,8 +4,8 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"hash": "db2edea5fb720fcb8013ac470e924c19",
|
"hash": "2bed8395d84740d7c0ae644a6c6216fd",
|
||||||
"content-hash": "85119d1ccd5193b6b08fda305a2427e7",
|
"content-hash": "7b66e221814f3d5839ed4faabd2f50ad",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "cerdic/css-tidy",
|
"name": "cerdic/css-tidy",
|
||||||
@ -2294,7 +2294,7 @@
|
|||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/config/zipball/41ee6c70758f40fa1dbf90d019ae0a66c4a09e74",
|
"url": "https://api.github.com/repos/symfony/config/zipball/ee4cdda66aff834c8125e8f2c15932461667c521",
|
||||||
"reference": "41ee6c70758f40fa1dbf90d019ae0a66c4a09e74",
|
"reference": "41ee6c70758f40fa1dbf90d019ae0a66c4a09e74",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
@ -2671,7 +2671,7 @@
|
|||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/form/zipball/7fd5e4034cb8e215887136f5e176430bbf5ef085",
|
"url": "https://api.github.com/repos/symfony/form/zipball/b629051c77a4f37c625651d03002760385df4575",
|
||||||
"reference": "7fd5e4034cb8e215887136f5e176430bbf5ef085",
|
"reference": "7fd5e4034cb8e215887136f5e176430bbf5ef085",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
@ -2929,7 +2929,7 @@
|
|||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/process/zipball/6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac",
|
"url": "https://api.github.com/repos/symfony/process/zipball/d9d21cfcc3e202ee34777d6da38897695d4d208d",
|
||||||
"reference": "6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac",
|
"reference": "6f1979c3b0f4c22c77a8a8971afaa7dd07f082ac",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
|
@ -221,6 +221,7 @@ class Migrator {
|
|||||||
'count_processed mediumint(9) NOT NULL DEFAULT 0,',
|
'count_processed mediumint(9) NOT NULL DEFAULT 0,',
|
||||||
'count_to_process mediumint(9) NOT NULL DEFAULT 0,',
|
'count_to_process mediumint(9) NOT NULL DEFAULT 0,',
|
||||||
'count_failed mediumint(9) NOT NULL DEFAULT 0,',
|
'count_failed mediumint(9) NOT NULL DEFAULT 0,',
|
||||||
|
'scheduled_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||||
'processed_at TIMESTAMP NOT NULL DEFAULT 0,',
|
'processed_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||||
|
@ -180,6 +180,14 @@ class Populator {
|
|||||||
'name' => 'nthWeekDay',
|
'name' => 'nthWeekDay',
|
||||||
'newsletter_type' => 'notification',
|
'newsletter_type' => 'notification',
|
||||||
),
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'schedule',
|
||||||
|
'newsletter_type' => 'notification',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => 'lastSentData',
|
||||||
|
'newsletter_type' => 'notification',
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Models;
|
namespace MailPoet\Models;
|
||||||
use MailPoet\Mailer\Mailer;
|
use MailPoet\Mailer\Mailer;
|
||||||
|
use MailPoet\Newsletter\Scheduler\Scheduler;
|
||||||
use MailPoet\Util\Helpers;
|
use MailPoet\Util\Helpers;
|
||||||
use MailPoet\Subscription;
|
use MailPoet\Subscription;
|
||||||
|
|
||||||
@ -173,6 +174,7 @@ class Subscriber extends Model {
|
|||||||
|
|
||||||
if($subscriber->save()) {
|
if($subscriber->save()) {
|
||||||
$subscriber->addToSegments($segment_ids);
|
$subscriber->addToSegments($segment_ids);
|
||||||
|
Scheduler::welcomeForSegmentSubscription($subscriber->id, $segment_ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
114
lib/Newsletter/Scheduler/Scheduler.php
Normal file
114
lib/Newsletter/Scheduler/Scheduler.php
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Newsletter\Scheduler;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use MailPoet\Models\Newsletter;
|
||||||
|
use MailPoet\Models\NewsletterOption;
|
||||||
|
use MailPoet\Models\NewsletterOptionField;
|
||||||
|
use MailPoet\Models\SendingQueue;
|
||||||
|
|
||||||
|
class Scheduler {
|
||||||
|
const seconds_in_hour = 3600;
|
||||||
|
const last_weekday_format = 'L';
|
||||||
|
|
||||||
|
static function postNotification($newsletter_id) {
|
||||||
|
$newsletter = Newsletter::filter('filterWithOptions')
|
||||||
|
->findOne($newsletter_id)
|
||||||
|
->asArray();
|
||||||
|
$interval_type = $newsletter['intervalType'];
|
||||||
|
$hour = (int) $newsletter['timeOfDay'] / self::seconds_in_hour;
|
||||||
|
$week_day = $newsletter['weekDay'];
|
||||||
|
$month_day = $newsletter['monthDay'];
|
||||||
|
$nth_week_day = ($newsletter['nthWeekDay'] === self::last_weekday_format) ?
|
||||||
|
$newsletter['nthWeekDay'] :
|
||||||
|
'#' . $newsletter['nthWeekDay'];
|
||||||
|
switch($interval_type) {
|
||||||
|
case 'immediately':
|
||||||
|
$cron = '* * * * *';
|
||||||
|
break;
|
||||||
|
case 'immediate': //daily
|
||||||
|
$cron = sprintf('0 %s * * *', $hour);
|
||||||
|
break;
|
||||||
|
case 'weekly':
|
||||||
|
$cron = sprintf('0 %s * * %s', $hour, $week_day);
|
||||||
|
break;
|
||||||
|
case 'monthly':
|
||||||
|
$cron = sprintf('0 %s %s * *', $hour, $month_day);
|
||||||
|
break;
|
||||||
|
case 'nthWeekDay':
|
||||||
|
$cron = sprintf('0 %s ? * %s%s', $hour, $week_day, $nth_week_day);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$option_field = NewsletterOptionField::where('name', 'schedule')
|
||||||
|
->findOne()
|
||||||
|
->asArray();
|
||||||
|
$relation = NewsletterOption::create();
|
||||||
|
$relation->newsletter_id = $newsletter['id'];
|
||||||
|
$relation->option_field_id = $option_field['id'];
|
||||||
|
$relation->value = $cron;
|
||||||
|
$relation->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
static function welcomeForSegmentSubscription($subscriber_id, array $segments) {
|
||||||
|
$newsletters = self::getWelcomeNewsletters();
|
||||||
|
if(!count($newsletters)) return;
|
||||||
|
foreach($newsletters as $newsletter) {
|
||||||
|
if($newsletter['event'] === 'segment' &&
|
||||||
|
in_array($newsletter['segment'], $segments)
|
||||||
|
) {
|
||||||
|
self::createSendingQueueEntry($newsletter, $subscriber_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function welcomeForNewWPUser($subscriber_id, array $wp_user) {
|
||||||
|
$newsletters = self::getWelcomeNewsletters();
|
||||||
|
if(!count($newsletters)) return;
|
||||||
|
foreach($newsletters as $newsletter) {
|
||||||
|
if($newsletter['event'] === 'user' &&
|
||||||
|
in_array($newsletter['role'], $wp_user['roles'])
|
||||||
|
) {
|
||||||
|
self::createSendingQueueEntry($newsletter, $subscriber_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getWelcomeNewsletters() {
|
||||||
|
return Newsletter::where('type', 'welcome')
|
||||||
|
->filter('filterWithOptions')
|
||||||
|
->findArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function createSendingQueueEntry($newsletter, $subscriber_id) {
|
||||||
|
$queue = SendingQueue::create();
|
||||||
|
$queue->newsletter_id = $newsletter['id'];
|
||||||
|
$queue->subscribers = serialize(
|
||||||
|
array(
|
||||||
|
'to_process' => array($subscriber_id)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$queue->count_total = $queue->count_to_process = 1;
|
||||||
|
$after_time_type = $newsletter['afterTimeType'];
|
||||||
|
$after_time_number = $newsletter['afterTimeNumber'];
|
||||||
|
$scheduled_at = null;
|
||||||
|
switch($after_time_type) {
|
||||||
|
case 'hours':
|
||||||
|
$scheduled_at = Carbon::now()
|
||||||
|
->addHours($after_time_number);
|
||||||
|
break;
|
||||||
|
case 'days':
|
||||||
|
$scheduled_at = Carbon::now()
|
||||||
|
->addDays($after_time_number);
|
||||||
|
break;
|
||||||
|
case 'weeks':
|
||||||
|
$scheduled_at = Carbon::now()
|
||||||
|
->addWeeks($after_time_number);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if($scheduled_at) {
|
||||||
|
$queue->status = 'scheduled';
|
||||||
|
$queue->scheduled_at = $scheduled_at;
|
||||||
|
}
|
||||||
|
$queue->save();
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,7 @@ use MailPoet\Models\NewsletterOptionField;
|
|||||||
use MailPoet\Models\NewsletterOption;
|
use MailPoet\Models\NewsletterOption;
|
||||||
use MailPoet\Newsletter\Renderer\Renderer;
|
use MailPoet\Newsletter\Renderer\Renderer;
|
||||||
use MailPoet\Models\SendingQueue;
|
use MailPoet\Models\SendingQueue;
|
||||||
|
use MailPoet\Newsletter\Scheduler\Scheduler;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
@ -265,6 +266,12 @@ class Newsletters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(!isset($data['id']) &&
|
||||||
|
isset($data['type']) &&
|
||||||
|
$data['type'] === 'notification'
|
||||||
|
) {
|
||||||
|
Scheduler::postNotification($newsletter->id);
|
||||||
|
}
|
||||||
return array(
|
return array(
|
||||||
'result' => true,
|
'result' => true,
|
||||||
'newsletter' => $newsletter->asArray()
|
'newsletter' => $newsletter->asArray()
|
||||||
|
@ -2,17 +2,15 @@
|
|||||||
namespace MailPoet\Segments;
|
namespace MailPoet\Segments;
|
||||||
use \MailPoet\Models\Subscriber;
|
use \MailPoet\Models\Subscriber;
|
||||||
use \MailPoet\Models\Segment;
|
use \MailPoet\Models\Segment;
|
||||||
|
use MailPoet\Newsletter\Scheduler\Scheduler;
|
||||||
|
|
||||||
class WP {
|
class WP {
|
||||||
static function synchronizeUser($wp_user_id) {
|
static function synchronizeUser($wp_user_id) {
|
||||||
$wpUser = \get_userdata($wp_user_id);
|
$wp_user = \get_userdata($wp_user_id);
|
||||||
$segment = Segment::getWPUsers();
|
$segment = Segment::getWPUsers();
|
||||||
|
if($wp_user === false or $segment === false) return;
|
||||||
if($wpUser === false or $segment === false) return;
|
$subscriber = Subscriber::where('wp_user_id', $wp_user->ID)
|
||||||
|
|
||||||
$subscriber = Subscriber::where('wp_user_id', $wpUser->ID)
|
|
||||||
->findOne();
|
->findOne();
|
||||||
|
|
||||||
switch(current_filter()) {
|
switch(current_filter()) {
|
||||||
case 'delete_user':
|
case 'delete_user':
|
||||||
case 'deleted_user':
|
case 'deleted_user':
|
||||||
@ -20,23 +18,22 @@ class WP {
|
|||||||
if($subscriber !== false && $subscriber->id()) {
|
if($subscriber !== false && $subscriber->id()) {
|
||||||
$subscriber->delete();
|
$subscriber->delete();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'user_register':
|
case 'user_register':
|
||||||
|
$new_user = (!$subscriber) ? true : false;
|
||||||
case 'added_existing_user':
|
case 'added_existing_user':
|
||||||
case 'profile_update':
|
case 'profile_update':
|
||||||
default:
|
default:
|
||||||
// get first name & last name
|
// get first name & last name
|
||||||
$first_name = $wpUser->first_name;
|
$first_name = $wp_user->first_name;
|
||||||
$last_name = $wpUser->last_name;
|
$last_name = $wp_user->last_name;
|
||||||
if(empty($wpUser->first_name) && empty($wpUser->last_name)) {
|
if(empty($wp_user->first_name) && empty($wp_user->last_name)) {
|
||||||
$first_name = $wpUser->display_name;
|
$first_name = $wp_user->display_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscriber data
|
// subscriber data
|
||||||
$data = array(
|
$data = array(
|
||||||
'wp_user_id'=> $wpUser->ID,
|
'wp_user_id' => $wp_user->ID,
|
||||||
'email' => $wpUser->user_email,
|
'email' => $wp_user->user_email,
|
||||||
'first_name' => $first_name,
|
'first_name' => $first_name,
|
||||||
'last_name' => $last_name,
|
'last_name' => $last_name,
|
||||||
'status' => 'subscribed'
|
'status' => 'subscribed'
|
||||||
@ -46,13 +43,18 @@ class WP {
|
|||||||
$data['id'] = $subscriber->id();
|
$data['id'] = $subscriber->id();
|
||||||
}
|
}
|
||||||
$subscriber = Subscriber::createOrUpdate($data);
|
$subscriber = Subscriber::createOrUpdate($data);
|
||||||
|
|
||||||
if($subscriber->getErrors() === false && $subscriber->id > 0) {
|
if($subscriber->getErrors() === false && $subscriber->id > 0) {
|
||||||
if($segment !== false) {
|
if($segment !== false) {
|
||||||
$segment->addSubscriber($subscriber->id);
|
$segment->addSubscriber($subscriber->id);
|
||||||
}
|
}
|
||||||
|
if(isset($new_user) && $new_user === true) {
|
||||||
|
Scheduler::welcomeForNewWPUser(
|
||||||
|
$subscriber->id,
|
||||||
|
(array) $wp_user
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user