Use dynamic segments for sending queue
[PREMIUM-38]
This commit is contained in:
@ -10,6 +10,7 @@ use MailPoet\Models\Newsletter;
|
|||||||
use MailPoet\Models\SendingQueue as SendingQueueModel;
|
use MailPoet\Models\SendingQueue as SendingQueueModel;
|
||||||
use MailPoet\Models\Subscriber;
|
use MailPoet\Models\Subscriber;
|
||||||
use MailPoet\Newsletter\Scheduler\Scheduler;
|
use MailPoet\Newsletter\Scheduler\Scheduler;
|
||||||
|
use MailPoet\Segments\SubscribersFinder;
|
||||||
use MailPoet\Util\Helpers;
|
use MailPoet\Util\Helpers;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
@ -75,10 +76,8 @@ class SendingQueue extends APIEndpoint {
|
|||||||
$queue->count_total = $queue->count_to_process = 0;
|
$queue->count_total = $queue->count_to_process = 0;
|
||||||
} else {
|
} else {
|
||||||
$segments = $newsletter->segments()->findArray();
|
$segments = $newsletter->segments()->findArray();
|
||||||
$segment_ids = array_map(function($segment) {
|
$finder = new SubscribersFinder();
|
||||||
return $segment['id'];
|
$subscribers = $finder->getSubscribersByList($segments);
|
||||||
}, $segments);
|
|
||||||
$subscribers = Subscriber::getSubscribedInSegments($segment_ids)->findArray();
|
|
||||||
$subscribers = Helpers::flattenArray($subscribers);
|
$subscribers = Helpers::flattenArray($subscribers);
|
||||||
if(!count($subscribers)) {
|
if(!count($subscribers)) {
|
||||||
return $this->errorResponse(array(
|
return $this->errorResponse(array(
|
||||||
|
@ -54,6 +54,11 @@ class Subscribers extends APIEndpoint {
|
|||||||
->asArray();
|
->asArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$listing_data['filters']['segment'] = apply_filters(
|
||||||
|
'mailpoet_subscribers_filters_segments_with_subscriber_count',
|
||||||
|
$listing_data['filters']['segment']
|
||||||
|
);
|
||||||
|
|
||||||
return $this->successResponse($data, array(
|
return $this->successResponse($data, array(
|
||||||
'count' => $listing_data['count'],
|
'count' => $listing_data['count'],
|
||||||
'filters' => $listing_data['filters'],
|
'filters' => $listing_data['filters'],
|
||||||
|
@ -462,7 +462,12 @@ class Menu {
|
|||||||
$data = array();
|
$data = array();
|
||||||
|
|
||||||
$data['items_per_page'] = $this->getLimitPerPage('subscribers');
|
$data['items_per_page'] = $this->getLimitPerPage('subscribers');
|
||||||
$data['segments'] = Segment::getSegmentsWithSubscriberCount($type = false);
|
$segments = Segment::getSegmentsWithSubscriberCount($type = false);
|
||||||
|
$segments = apply_filters('mailpoet_segments_with_subscriber_count', $segments);
|
||||||
|
usort($segments, function ($a, $b) {
|
||||||
|
return strcasecmp($a["name"], $b["name"]);
|
||||||
|
});
|
||||||
|
$data['segments'] = $segments;
|
||||||
|
|
||||||
$data['custom_fields'] = array_map(function($field) {
|
$data['custom_fields'] = array_map(function($field) {
|
||||||
$field['params'] = unserialize($field['params']);
|
$field['params'] = unserialize($field['params']);
|
||||||
@ -517,7 +522,7 @@ class Menu {
|
|||||||
|
|
||||||
$data['items_per_page'] = $this->getLimitPerPage('newsletters');
|
$data['items_per_page'] = $this->getLimitPerPage('newsletters');
|
||||||
$segments = Segment::getSegmentsWithSubscriberCount($type = false);
|
$segments = Segment::getSegmentsWithSubscriberCount($type = false);
|
||||||
$segments = apply_filters('mailpoet_newsletters_segments_with_subscriber_count', $segments);
|
$segments = apply_filters('mailpoet_segments_with_subscriber_count', $segments);
|
||||||
usort($segments, function ($a, $b) {
|
usort($segments, function ($a, $b) {
|
||||||
return strcasecmp($a["name"], $b["name"]);
|
return strcasecmp($a["name"], $b["name"]);
|
||||||
});
|
});
|
||||||
|
@ -87,7 +87,7 @@ class Migrator {
|
|||||||
'segment_id int(11) unsigned NOT NULL,',
|
'segment_id int(11) unsigned NOT NULL,',
|
||||||
'created_at TIMESTAMP NULL,',
|
'created_at TIMESTAMP NULL,',
|
||||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||||
'filter_data LONGTEXT,',
|
'filter_data LONGBLOB,',
|
||||||
'PRIMARY KEY (id),',
|
'PRIMARY KEY (id),',
|
||||||
'KEY segment_id (segment_id)',
|
'KEY segment_id (segment_id)',
|
||||||
);
|
);
|
||||||
|
@ -10,6 +10,7 @@ use MailPoet\Models\Newsletter as NewsletterModel;
|
|||||||
use MailPoet\Models\SendingQueue as SendingQueueModel;
|
use MailPoet\Models\SendingQueue as SendingQueueModel;
|
||||||
use MailPoet\Models\StatisticsNewsletters as StatisticsNewslettersModel;
|
use MailPoet\Models\StatisticsNewsletters as StatisticsNewslettersModel;
|
||||||
use MailPoet\Models\Subscriber as SubscriberModel;
|
use MailPoet\Models\Subscriber as SubscriberModel;
|
||||||
|
use MailPoet\Segments\SubscribersFinder;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
@ -51,10 +52,11 @@ class SendingQueue {
|
|||||||
foreach($subscriber_batches as $subscribers_to_process_ids) {
|
foreach($subscriber_batches as $subscribers_to_process_ids) {
|
||||||
if(!empty($newsletter_segments_ids[0])) {
|
if(!empty($newsletter_segments_ids[0])) {
|
||||||
// Check that subscribers are in segments
|
// Check that subscribers are in segments
|
||||||
$found_subscribers = SubscriberModel::findSubscribersInSegments(
|
$finder = new SubscribersFinder();
|
||||||
$subscribers_to_process_ids, $newsletter_segments_ids
|
$found_subscribers_ids = $finder->findSubscribersInSegments($subscribers_to_process_ids, $newsletter_segments_ids);
|
||||||
)->findMany();
|
$found_subscribers = SubscriberModel::whereIn('id', $subscribers_to_process_ids)
|
||||||
$found_subscribers_ids = SubscriberModel::extractSubscribersIds($found_subscribers);
|
->whereNull('deleted_at')
|
||||||
|
->findMany();
|
||||||
} else {
|
} else {
|
||||||
// No segments = Welcome emails
|
// No segments = Welcome emails
|
||||||
$found_subscribers = SubscriberModel::whereIn('id', $subscribers_to_process_ids)
|
$found_subscribers = SubscriberModel::whereIn('id', $subscribers_to_process_ids)
|
||||||
|
@ -213,8 +213,10 @@ class Segment extends Model {
|
|||||||
static function listingQuery(array $data = array()) {
|
static function listingQuery(array $data = array()) {
|
||||||
$query = self::select('*');
|
$query = self::select('*');
|
||||||
$query->whereIn('type', array(Segment::TYPE_WP_USERS, Segment::TYPE_DEFAULT));
|
$query->whereIn('type', array(Segment::TYPE_WP_USERS, Segment::TYPE_DEFAULT));
|
||||||
return $query
|
if (isset($data['group'])) {
|
||||||
->filter('groupBy', $data);
|
$query->filter('groupBy', $data['group']);
|
||||||
|
}
|
||||||
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
static function createOrUpdate($data = array()) {
|
static function createOrUpdate($data = array()) {
|
||||||
|
@ -261,6 +261,7 @@ class Subscriber extends Model {
|
|||||||
|
|
||||||
$segments = Segment::orderByAsc('name')
|
$segments = Segment::orderByAsc('name')
|
||||||
->whereNull('deleted_at')
|
->whereNull('deleted_at')
|
||||||
|
->whereIn('type', array(Segment::TYPE_WP_USERS, Segment::TYPE_DEFAULT))
|
||||||
->findMany();
|
->findMany();
|
||||||
$segment_list = array();
|
$segment_list = array();
|
||||||
$segment_list[] = array(
|
$segment_list[] = array(
|
||||||
|
69
lib/Segments/SubscribersFinder.php
Normal file
69
lib/Segments/SubscribersFinder.php
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace MailPoet\Segments;
|
||||||
|
|
||||||
|
use MailPoet\Models\Segment;
|
||||||
|
use MailPoet\Models\Subscriber;
|
||||||
|
use MailPoet\WP\Hooks;
|
||||||
|
|
||||||
|
class SubscribersFinder {
|
||||||
|
|
||||||
|
function findSubscribersInSegments($subscribers_to_process_ids, $newsletter_segments_ids) {
|
||||||
|
$result = array();
|
||||||
|
foreach ($newsletter_segments_ids as $segment_id) {
|
||||||
|
$segment = Segment::find_one($segment_id)->asArray();
|
||||||
|
$result = array_merge($result, $this->findSubscribersInSegment($segment, $subscribers_to_process_ids));
|
||||||
|
}
|
||||||
|
return $this->unique($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findSubscribersInSegment($segment, $subscribers_to_process_ids) {
|
||||||
|
if ($segment['type'] === Segment::TYPE_DEFAULT || $segment['type'] === Segment::TYPE_WP_USERS) {
|
||||||
|
$subscribers = Subscriber::findSubscribersInSegments($subscribers_to_process_ids, array($segment['id']))->findMany();
|
||||||
|
return Subscriber::extractSubscribersIds($subscribers);
|
||||||
|
}
|
||||||
|
$finders = Hooks::applyFilters('mailpoet_get_subscribers_in_segment_finders', array());
|
||||||
|
foreach($finders as $finder) {
|
||||||
|
$subscribers = $finder->findSubscribersInSegment($segment, $subscribers_to_process_ids);
|
||||||
|
if ($subscribers) {
|
||||||
|
return $subscribers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSubscribersByList($segments) {
|
||||||
|
$result = array();
|
||||||
|
foreach($segments as $segment) {
|
||||||
|
$result = array_merge($result, $this->getSubscribers($segment));
|
||||||
|
}
|
||||||
|
return $this->unique($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSubscribers($segment) {
|
||||||
|
if ($segment['type'] === Segment::TYPE_DEFAULT || $segment['type'] === Segment::TYPE_WP_USERS) {
|
||||||
|
return Subscriber::getSubscribedInSegments(array($segment['id']))->findArray();
|
||||||
|
}
|
||||||
|
$finders = Hooks::applyFilters('mailpoet_get_subscribers_in_segment_finders', array());
|
||||||
|
foreach($finders as $finder) {
|
||||||
|
$subscribers = $finder->getSubscriberIdsInSegment($segment);
|
||||||
|
if ($subscribers) {
|
||||||
|
return $subscribers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function unique($subscribers) {
|
||||||
|
$result = array();
|
||||||
|
foreach($subscribers as $subscriber) {
|
||||||
|
if(is_a($subscriber, 'MailPoet\Models\Model')) {
|
||||||
|
$result[$subscriber->id] = $subscriber;
|
||||||
|
} elseif (is_scalar($subscriber)) {
|
||||||
|
$result[$subscriber] = $subscriber;
|
||||||
|
} else {
|
||||||
|
$result[$subscriber['id']] = $subscriber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,9 +7,9 @@ use MailPoet\Models\Segment;
|
|||||||
|
|
||||||
class SegmentsTest extends \MailPoetTest {
|
class SegmentsTest extends \MailPoetTest {
|
||||||
function _before() {
|
function _before() {
|
||||||
$this->segment_1 = Segment::createOrUpdate(array('name' => 'Segment 1'));
|
$this->segment_1 = Segment::createOrUpdate(array('name' => 'Segment 1', 'type' => 'default'));
|
||||||
$this->segment_2 = Segment::createOrUpdate(array('name' => 'Segment 2'));
|
$this->segment_2 = Segment::createOrUpdate(array('name' => 'Segment 2', 'type' => 'default'));
|
||||||
$this->segment_3 = Segment::createOrUpdate(array('name' => 'Segment 3'));
|
$this->segment_3 = Segment::createOrUpdate(array('name' => 'Segment 3', 'type' => 'default'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function testItCanGetASegment() {
|
function testItCanGetASegment() {
|
||||||
@ -135,6 +135,7 @@ class SegmentsTest extends \MailPoetTest {
|
|||||||
'action' => 'delete',
|
'action' => 'delete',
|
||||||
'listing' => array('group' => 'trash')
|
'listing' => array('group' => 'trash')
|
||||||
));
|
));
|
||||||
|
|
||||||
expect($response->status)->equals(APIResponse::STATUS_OK);
|
expect($response->status)->equals(APIResponse::STATUS_OK);
|
||||||
expect($response->meta['count'])->equals(3);
|
expect($response->meta['count'])->equals(3);
|
||||||
|
|
||||||
|
@ -446,7 +446,7 @@ class SendingQueueTest extends \MailPoetTest {
|
|||||||
array(
|
array(
|
||||||
'to_process' => array(
|
'to_process' => array(
|
||||||
$this->subscriber->id(),
|
$this->subscriber->id(),
|
||||||
123
|
12345645454
|
||||||
),
|
),
|
||||||
'processed' => array()
|
'processed' => array()
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user