- Updates Migrator with new column for Segments
- Updates Segmnets tests - Updates MailPoet's Notice.js with additional options - Updates Import's router, WP menu bootstrap logic, client- and server-side logic
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -47,6 +47,8 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
type: 'success',
|
type: 'success',
|
||||||
message: '',
|
message: '',
|
||||||
static: false,
|
static: false,
|
||||||
|
hideClose: false,
|
||||||
|
addCustomClass: false,
|
||||||
scroll: false,
|
scroll: false,
|
||||||
timeout: 2000,
|
timeout: 2000,
|
||||||
onOpen: null,
|
onOpen: null,
|
||||||
@ -60,6 +62,9 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
// clone element
|
// clone element
|
||||||
this.element = jQuery('#mailpoet_notice_'+this.options.type).clone();
|
this.element = jQuery('#mailpoet_notice_'+this.options.type).clone();
|
||||||
|
|
||||||
|
// add custom identifier class to the element
|
||||||
|
if (this.options.addCustomClass) this.element.addClass('mailpoet_'+this.options.addCustomClass);
|
||||||
|
|
||||||
// remove id from clone
|
// remove id from clone
|
||||||
this.element.removeAttr('id');
|
this.element.removeAttr('id');
|
||||||
|
|
||||||
@ -73,7 +78,6 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// listen to remove event
|
// listen to remove event
|
||||||
var element = this.element;
|
|
||||||
jQuery(this.element).on('close', function() {
|
jQuery(this.element).on('close', function() {
|
||||||
jQuery(this).fadeOut(200, function() {
|
jQuery(this).fadeOut(200, function() {
|
||||||
// on close callback
|
// on close callback
|
||||||
@ -148,7 +152,7 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
// if the notice is not static, it has to disappear after a timeout
|
// if the notice is not static, it has to disappear after a timeout
|
||||||
if(this.options.static === false) {
|
if(this.options.static === false) {
|
||||||
this.element.delay(this.options.timeout).trigger('close');
|
this.element.delay(this.options.timeout).trigger('close');
|
||||||
} else {
|
} else if (this.options.hideClose === false) {
|
||||||
this.element.append('<a href="javascript:;" class="mailpoet_notice_close"><span class="dashicons dashicons-dismiss"></span></a>');
|
this.element.append('<a href="javascript:;" class="mailpoet_notice_close"><span class="dashicons dashicons-dismiss"></span></a>');
|
||||||
this.element.find('.mailpoet_notice_close').on('click', function() {
|
this.element.find('.mailpoet_notice_close').on('click', function() {
|
||||||
jQuery(this).trigger('close');
|
jQuery(this).trigger('close');
|
||||||
@ -163,6 +167,14 @@ define('notice', ['mailpoet', 'jquery'], function(MailPoet, jQuery) {
|
|||||||
hide: function(all) {
|
hide: function(all) {
|
||||||
if(all !== undefined && all === true) {
|
if(all !== undefined && all === true) {
|
||||||
jQuery('.mailpoet_notice:not([id])').trigger('close');
|
jQuery('.mailpoet_notice:not([id])').trigger('close');
|
||||||
|
} else if (all !== undefined && jQuery.isArray(all)) {
|
||||||
|
for (var noticeClass in all) {
|
||||||
|
jQuery('.mailpoet_'+all[noticeClass])
|
||||||
|
.trigger('close');
|
||||||
|
}
|
||||||
|
} if (all !== undefined) {
|
||||||
|
jQuery('.mailpoet_'+noticeClass)
|
||||||
|
.trigger('close');
|
||||||
} else {
|
} else {
|
||||||
jQuery('.mailpoet_notice.updated:not([id]), .mailpoet_notice.error:not([id])')
|
jQuery('.mailpoet_notice.updated:not([id]), .mailpoet_notice.error:not([id])')
|
||||||
.trigger('close');
|
.trigger('close');
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace MailPoet\Config;
|
namespace MailPoet\Config;
|
||||||
use MailPoet\Import\Import;
|
use \MailPoet\Import\BootstrapMenu;
|
||||||
use \MailPoet\Models\Segment;
|
use \MailPoet\Models\Segment;
|
||||||
use \MailPoet\Models\Setting;
|
use \MailPoet\Models\Setting;
|
||||||
use \MailPoet\Models\Form;
|
use \MailPoet\Models\Form;
|
||||||
@ -214,13 +214,14 @@ class Menu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function import() {
|
function import() {
|
||||||
$import = new Import();
|
$import = new BootstrapMenu();
|
||||||
$data = $import->bootstrapImportMenu();
|
$data = $import->bootstrap();
|
||||||
echo $this->renderer->render('import.html', $data);
|
echo $this->renderer->render('import.html', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function formEditor() {
|
function formEditor() {
|
||||||
$id = (isset($_GET['id']) ? (int)$_GET['id'] : 0);
|
$id = (isset($_GET['id']) ? (int)$_GET['id'] : 0);
|
||||||
$form = Form::findOne($id);
|
$form = Form::findOne($id);
|
||||||
|
106
lib/Import/BootstrapMenu.php
Normal file
106
lib/Import/BootstrapMenu.php
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<?php namespace MailPoet\Import;
|
||||||
|
|
||||||
|
use MailPoet\Models\CustomField;
|
||||||
|
use MailPoet\Models\Segment;
|
||||||
|
use MailPoet\Util\Helpers;
|
||||||
|
|
||||||
|
class BootstrapMenu {
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
$this->subscriberFields = $this->getSubscriberFields();
|
||||||
|
$this->subscriberCustomFields = $this->getSubscriberCustomFields();
|
||||||
|
$this->segments = $this->getSegments();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSubscriberFields() {
|
||||||
|
return array(
|
||||||
|
'subscriber_email' => __("Email"),
|
||||||
|
'subscriber_firstname' => __("First name"),
|
||||||
|
'subscriber_lastname' => __("Last name"),
|
||||||
|
/* 'subscriber_confirmed_ip' => __("IP address"),
|
||||||
|
'subscriber_confirmed_at' => __("Subscription date"),*/
|
||||||
|
'subscriber_state' => __("Status")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSegments() {
|
||||||
|
return Segment::findArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSubscriberCustomFields() {
|
||||||
|
return CustomField::findArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSubscriberFields() {
|
||||||
|
return array_map(function ($fieldId, $fieldName) {
|
||||||
|
return array(
|
||||||
|
'id' => $fieldId,
|
||||||
|
'name' => $fieldName,
|
||||||
|
'type' => ($fieldId === 'subscriber_confirmed_at') ? 'date' : null,
|
||||||
|
'custom' => false
|
||||||
|
);
|
||||||
|
}, array_keys($this->subscriberFields), $this->subscriberFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSubscriberCustomFields() {
|
||||||
|
return array_map(function ($field) {
|
||||||
|
return array(
|
||||||
|
'id' => $field['id'],
|
||||||
|
'name' => $field['name'],
|
||||||
|
'label' => $field['name'],
|
||||||
|
'type' => $field['type'],
|
||||||
|
'custom' => true
|
||||||
|
);
|
||||||
|
}, $this->subscriberCustomFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSubscriberFieldsSelect2() {
|
||||||
|
$select2Fields = array(
|
||||||
|
array(
|
||||||
|
'name' => __("Actions"),
|
||||||
|
'children' => array(
|
||||||
|
array(
|
||||||
|
'id' => 'ignore',
|
||||||
|
'name' => __("Ignore column..."),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'id' => 'create',
|
||||||
|
'name' => __("Create new column...")
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'name' => __("System columns"),
|
||||||
|
'children' => $this->formatSubscriberFields()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if($this->subscriberCustomFields) {
|
||||||
|
array_push($select2Fields, array(
|
||||||
|
'name' => __("User columns"),
|
||||||
|
'children' => $this->formatSubscriberCustomFields()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return $select2Fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
function bootstrap() {
|
||||||
|
$data['segments'] = array_map(function ($segment) {
|
||||||
|
return array(
|
||||||
|
'id' => $segment['id'],
|
||||||
|
'name' => $segment['name'],
|
||||||
|
);
|
||||||
|
}, $this->getSegments());
|
||||||
|
|
||||||
|
$data['subscriberFields'] = array_merge(
|
||||||
|
$this->formatSubscriberFields(),
|
||||||
|
$this->formatSubscriberCustomFields()
|
||||||
|
);
|
||||||
|
|
||||||
|
$data['subscriberFieldsSelect2'] = $this->formatSubscriberFieldsSelect2();
|
||||||
|
|
||||||
|
$data = array_map('json_encode', $data);
|
||||||
|
$data['maxPostSizeBytes'] = Helpers::getMaxPostSize('bytes');
|
||||||
|
$data['maxPostSize'] = Helpers::getMaxPostSize();
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
@ -1,106 +1,71 @@
|
|||||||
<?php namespace MailPoet\Import;
|
<?php namespace MailPoet\Import;
|
||||||
|
|
||||||
use MailPoet\Models\CustomField;
|
|
||||||
use MailPoet\Models\Segment;
|
|
||||||
use MailPoet\Util\Helpers;
|
|
||||||
|
|
||||||
class Import {
|
class Import {
|
||||||
|
public function __construct($data) {
|
||||||
function getSegments() {
|
$this->subscribersData = $data['subscribers'];
|
||||||
return Segment::findArray();
|
$this->segments = $data['segments'];
|
||||||
|
$this->updateSubscribers = $data['updateSubscribers'];
|
||||||
|
$this->subscriberFields = $this->getSubscriberFields();
|
||||||
|
$this->subscriberCustomFields = $this->getCustomSubscriberFields();
|
||||||
|
$this->currentTime = time();
|
||||||
|
$this->profilerStart = microtime(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSubscriberCustomFields() {
|
function process() {
|
||||||
return CustomField::findArray();
|
// :)
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'count' => count($this->subscribersData['subscriber_email'])
|
||||||
|
);
|
||||||
|
if(in_array('subscriber_status', $subscriberFields)) {
|
||||||
|
$this->subscribersData['subscriber_state'] = $this->filterSubscriberState(
|
||||||
|
$this->subscribersData['subscriber_state']
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSubscriberFields() {
|
function getSubscriberFields() {
|
||||||
return array(
|
|
||||||
'subscriber_email' => __("Email"),
|
|
||||||
'subscriber_firstname' => __("First name"),
|
|
||||||
'subscriber_lastname' => __("Last name"),
|
|
||||||
'subscriber_confirmed_ip' => __("IP address"),
|
|
||||||
'subscriber_confirmed_at' => __("Subscription date"),
|
|
||||||
'subscriber_state' => __("Status")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatSubscriberFields($subscriberFields) {
|
|
||||||
return array_map(function ($fieldId, $fieldName) {
|
|
||||||
return array(
|
|
||||||
'id' => $fieldId,
|
|
||||||
'name' => $fieldName,
|
|
||||||
'type' => ($fieldId === 'subscriber_confirmed_at') ? 'date' : null,
|
|
||||||
'custom' => false
|
|
||||||
);
|
|
||||||
}, array_keys($subscriberFields), $subscriberFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatSubscriberCustomFields($subscriberCustomFields) {
|
|
||||||
return array_map(function ($field) {
|
return array_map(function ($field) {
|
||||||
return array(
|
if(!is_int($field)) return $field;
|
||||||
'id' => $field['id'],
|
}, array_keys($this->subscribersData));
|
||||||
'name' => $field['name'],
|
|
||||||
'label' => $field['name'],
|
|
||||||
'type' => $field['type'],
|
|
||||||
'custom' => true
|
|
||||||
);
|
|
||||||
}, $subscriberCustomFields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatSelect2Fields($subscriberFields, $subscriberCustomFields) {
|
function getCustomSubscriberFields() {
|
||||||
$data = array(
|
return array_map(function ($field) {
|
||||||
array(
|
if(is_int($field)) return $field;
|
||||||
'name' => __("Actions"),
|
}, array_keys($this->subscribersData));
|
||||||
'children' => array(
|
}
|
||||||
array(
|
|
||||||
'id' => 'ignore',
|
function filterSubscriberState($data) {
|
||||||
'name' => __("Ignore column..."),
|
$states = array(
|
||||||
|
'subscribed' => array(
|
||||||
|
'subscribed',
|
||||||
|
'confirmed',
|
||||||
|
1,
|
||||||
|
'1',
|
||||||
|
'true'
|
||||||
),
|
),
|
||||||
array(
|
'unsubscribed' => array(
|
||||||
'id' => 'create',
|
'unsubscribed',
|
||||||
'name' => __("Create new column...")
|
-1,
|
||||||
),
|
'-1',
|
||||||
)
|
'false'
|
||||||
),
|
|
||||||
array(
|
|
||||||
'name' => __("System columns"),
|
|
||||||
'children' => $subscriberFields
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if($subscriberCustomFields) {
|
return array_map(function ($state) use ($states) {
|
||||||
array_push($data, array(
|
if(in_array(strtolower($state), $states['subscribed'])) {
|
||||||
'name' => __("User columns"),
|
return 1;
|
||||||
'children' => $subscriberCustomFields
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
return $data;
|
if(in_array(strtolower($state), $states['unsubscribed'])) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 1; // make "subscribed" a default state
|
||||||
|
}, $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function bootstrapImportMenu() {
|
function timeExecution() {
|
||||||
$data['segments'] = array_map(function ($segment) {
|
$profilerEnd = microtime(true);
|
||||||
return array(
|
return ($profilerEnd - $this->profilerStart) / 60;
|
||||||
'id' => $segment['id'],
|
|
||||||
'name' => $segment['name'],
|
|
||||||
'text' => $segment['name']
|
|
||||||
);
|
|
||||||
}, $this->getSegments());
|
|
||||||
|
|
||||||
$data['subscriberFields'] = $this->formatSubscriberFields(
|
|
||||||
$this->getSubscriberFields()
|
|
||||||
);
|
|
||||||
|
|
||||||
$data['subscriberCustomFields'] = $this->formatSubscriberCustomFields(
|
|
||||||
$this->getSubscriberCustomFields()
|
|
||||||
);
|
|
||||||
|
|
||||||
$data['select2Fields'] = $this->formatSelect2Fields(
|
|
||||||
$data['subscriberFields'],
|
|
||||||
$data['subscriberCustomFields']
|
|
||||||
);
|
|
||||||
|
|
||||||
$data['maximumParseSize'] = Helpers::get_maximum_post_size();
|
|
||||||
return array_map('json_encode', $data);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
155
lib/Import/MailChimp.php
Normal file
155
lib/Import/MailChimp.php
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
<?php
|
||||||
|
namespace MailPoet\Import;
|
||||||
|
|
||||||
|
use MailPoet\Util\Helpers;
|
||||||
|
|
||||||
|
class MailChimp {
|
||||||
|
public function __construct($APIKey, $lists = false) {
|
||||||
|
$this->APIKey = $this->getAPIKey($APIKey);
|
||||||
|
$this->maxPostSize = Helpers::getMaxPostSize('bytes');
|
||||||
|
$this->dataCenter = $this->getDataCenter();
|
||||||
|
$this->lists = $lists;
|
||||||
|
$this->listsURL = 'https://%s.api.mailchimp.com/2.0/lists/list?apikey=%s';
|
||||||
|
$this->exportURL = 'https://%s.api.mailchimp.com/export/1.0/list/?apikey=%s&id=%s';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLists() {
|
||||||
|
if(!$this->APIKey || !$this->dataCenter) {
|
||||||
|
return $this->processError('API');
|
||||||
|
}
|
||||||
|
|
||||||
|
$connection = @fopen(sprintf($this->listsURL, $this->dataCenter, $this->APIKey), 'r');
|
||||||
|
|
||||||
|
if(!$connection) {
|
||||||
|
return $this->processError('connection');
|
||||||
|
} else {
|
||||||
|
$response = '';
|
||||||
|
while (!feof($connection)) {
|
||||||
|
$buffer = fgets($connection, 4096);
|
||||||
|
if(trim($buffer) !== '') {
|
||||||
|
$response .= $buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose($connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = json_decode($response);
|
||||||
|
|
||||||
|
if(!$response) {
|
||||||
|
return $this->processError('API');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($response->data as $list) {
|
||||||
|
$lists[] = array(
|
||||||
|
'id' => $list->id,
|
||||||
|
'name' => $list->name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'data' => $lists
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSubscribers() {
|
||||||
|
if(!$this->APIKey || !$this->dataCenter) {
|
||||||
|
return $this->processError('API');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!is_array($this->lists)) {
|
||||||
|
return $this->processError('lists');
|
||||||
|
}
|
||||||
|
|
||||||
|
$bytesFetched = 0;
|
||||||
|
foreach ($this->lists as $list) {
|
||||||
|
$url = sprintf($this->exportURL, $this->dataCenter, $this->APIKey, $list);
|
||||||
|
$connection = @fopen($url, 'r');
|
||||||
|
if(!$connection) {
|
||||||
|
return $this->processError('connection');
|
||||||
|
} else {
|
||||||
|
$i = 0;
|
||||||
|
$header = array();
|
||||||
|
while (!feof($connection)) {
|
||||||
|
$buffer = fgets($connection, 4096);
|
||||||
|
if(trim($buffer) !== '') {
|
||||||
|
$obj = json_decode($buffer);
|
||||||
|
if($i === 0) {
|
||||||
|
$header = $obj;
|
||||||
|
if(is_object($header) && isset($header->error)) {
|
||||||
|
return $this->processError('API');
|
||||||
|
}
|
||||||
|
if(!isset($headerHash)) {
|
||||||
|
$headerHash = md5(implode(',', $header));
|
||||||
|
} else {
|
||||||
|
if(md5(implode(',', $header) !== $headerHash)) {
|
||||||
|
return $this->processError('headers');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$subscribers[] = $obj;
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$bytesFetched += strlen($buffer);
|
||||||
|
if($bytesFetched > $this->maxPostSize) {
|
||||||
|
return $this->processError('size');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose($connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!count($subscribers)) {
|
||||||
|
return $this->processError('subscribers');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'status' => 'success',
|
||||||
|
'data' => $subscribers,
|
||||||
|
'invalid' => false,
|
||||||
|
'duplicate' => false,
|
||||||
|
'header' => $header,
|
||||||
|
'count' => count($subscribers)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDataCenter() {
|
||||||
|
// double parantheses: http://phpsadness.com/sad/51
|
||||||
|
return ($this->APIKey) ? end((explode('-', $this->APIKey))) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAPIKey($APIKey) {
|
||||||
|
return (preg_match('/[a-zA-Z0-9]{32}-[a-zA-Z0-9]{3,}/', $APIKey)) ? $APIKey : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processError($error) {
|
||||||
|
switch ($error) {
|
||||||
|
case 'API':
|
||||||
|
$message = __('Invalid API key.');
|
||||||
|
break;
|
||||||
|
case 'connection':
|
||||||
|
$message = __('Could not connect to your MailChimp account.');
|
||||||
|
break;
|
||||||
|
case 'headers':
|
||||||
|
$message = __('The selected lists do not have matching columns (headers).');
|
||||||
|
break;
|
||||||
|
case 'size':
|
||||||
|
$message = __('Information received from MailChimp is too large for processing. Please limit the number of lists.');
|
||||||
|
break;
|
||||||
|
case 'subscribers':
|
||||||
|
$message = __('Did not find any active subscribers.');
|
||||||
|
break;
|
||||||
|
case 'lists':
|
||||||
|
$message = __('Did not find any valid lists');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return array(
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => $message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@
|
|||||||
namespace MailPoet\Router;
|
namespace MailPoet\Router;
|
||||||
|
|
||||||
use MailPoet\Import\MailChimp;
|
use MailPoet\Import\MailChimp;
|
||||||
|
use MailPoet\Models\CustomField;
|
||||||
|
use MailPoet\Models\Segment;
|
||||||
|
|
||||||
if(!defined('ABSPATH')) exit;
|
if(!defined('ABSPATH')) exit;
|
||||||
|
|
||||||
@ -15,4 +17,40 @@ class Import {
|
|||||||
$mailChimp = new MailChimp($data['api_key'], $data['lists']);
|
$mailChimp = new MailChimp($data['api_key'], $data['lists']);
|
||||||
wp_send_json($mailChimp->getSubscribers());
|
wp_send_json($mailChimp->getSubscribers());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addSegment($data) {
|
||||||
|
$segment = Segment::createOrUpdate($data, $returnObject = true);
|
||||||
|
wp_send_json(
|
||||||
|
(!is_array($segment)) ?
|
||||||
|
array(
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => $segment
|
||||||
|
) :
|
||||||
|
array(
|
||||||
|
'status' => 'success',
|
||||||
|
'segment' => $segment
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCustomField($data) {
|
||||||
|
$customField = CustomField::create();
|
||||||
|
$customField->hydrate($data);
|
||||||
|
$result = $customField->save();
|
||||||
|
wp_send_json(
|
||||||
|
(!$result) ?
|
||||||
|
array(
|
||||||
|
'status' => 'error'
|
||||||
|
) :
|
||||||
|
array(
|
||||||
|
'status' => 'success',
|
||||||
|
'customField' => $customField->asArray()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function process($data) {
|
||||||
|
$import = new \MailPoet\Import\Import(json_decode($data, true));
|
||||||
|
wp_send_json($import->process());
|
||||||
|
}
|
||||||
}
|
}
|
@ -73,29 +73,23 @@ class Helpers {
|
|||||||
return $jqueryui_format;
|
return $jqueryui_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static function getMaxPostSize($bytes = false) {
|
||||||
* Determine maximum post size in bytes
|
$maxPostSize = ini_get('post_max_size');
|
||||||
*/
|
if (!$bytes) return $maxPostSize;
|
||||||
static function get_maximum_post_size() {
|
$maxPostSizeBytes = (int) $maxPostSize;
|
||||||
$maximum_post_size = ini_get('post_max_size');
|
$unit = strtolower($maxPostSize[strlen($maxPostSize) - 1]);
|
||||||
$maximum_post_size_bytes = (int) $maximum_post_size;
|
|
||||||
$unit = strtolower($maximum_post_size[strlen($maximum_post_size) - 1]);
|
|
||||||
switch ($unit) {
|
switch ($unit) {
|
||||||
case 'g':
|
case 'g':
|
||||||
$maximum_post_size_bytes *= 1024;
|
$maxPostSizeBytes *= 1024;
|
||||||
case 'm':
|
case 'm':
|
||||||
$maximum_post_size_bytes *= 1024;
|
$maxPostSizeBytes *= 1024;
|
||||||
case 'k':
|
case 'k':
|
||||||
$maximum_post_size_bytes *= 1024;
|
$maxPostSizeBytes *= 1024;
|
||||||
|
}
|
||||||
|
return $maxPostSizeBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $maximum_post_size_bytes;
|
static function flattenArray($array) {
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Flatten multidimensional array
|
|
||||||
*/
|
|
||||||
static function flatten_array($array) {
|
|
||||||
return call_user_func_array(
|
return call_user_func_array(
|
||||||
'array_merge_recursive', array_map('array_values', $array)
|
'array_merge_recursive', array_map('array_values', $array)
|
||||||
);
|
);
|
||||||
|
@ -11,6 +11,7 @@ class SegmentCest {
|
|||||||
$this->before_time = time();
|
$this->before_time = time();
|
||||||
$this->data = array(
|
$this->data = array(
|
||||||
'name' => 'some name',
|
'name' => 'some name',
|
||||||
|
'description' => 'some description'
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->segment = Segment::create();
|
$this->segment = Segment::create();
|
||||||
@ -22,6 +23,20 @@ class SegmentCest {
|
|||||||
expect($this->saved)->equals(true);
|
expect($this->saved)->equals(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function itCanHaveName() {
|
||||||
|
expect($this->segment->name)->equals($this->data['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
function nameMustBeUnique() {
|
||||||
|
$segment = Segment::create();
|
||||||
|
$segment->hydrate($this->data);
|
||||||
|
expect($segment->save())->contains('Duplicate');
|
||||||
|
}
|
||||||
|
|
||||||
|
function itCanHaveDescription() {
|
||||||
|
expect($this->segment->description)->equals($this->data['description']);
|
||||||
|
}
|
||||||
|
|
||||||
function itHasToBeValid() {
|
function itHasToBeValid() {
|
||||||
expect($this->saved)->equals(true);
|
expect($this->saved)->equals(true);
|
||||||
$empty_model = Segment::create();
|
$empty_model = Segment::create();
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
<h2 class="title"><%= __('Import') %></h2>
|
<h2 class="title"><%= __('Import') %></h2>
|
||||||
<!-- STEP 1: method selection -->
|
<!-- STEP 1: method selection -->
|
||||||
<% include 'import/step1.html' %>
|
<% include 'import/step1.html' %>
|
||||||
<!-- STEP 2: subscriber manipulation -->
|
<!-- STEP 2: subscriber data manipulation -->
|
||||||
|
<% include 'import/step2.html' %>
|
||||||
<!-- STEP 3: results -->
|
<!-- STEP 3: results -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -15,17 +15,53 @@
|
|||||||
<%= localize({
|
<%= localize({
|
||||||
'noMailChimpLists': __('No active lists found.'),
|
'noMailChimpLists': __('No active lists found.'),
|
||||||
'serverError': __('Server error:'),
|
'serverError': __('Server error:'),
|
||||||
'select': __('Select')
|
'select': __('Select'),
|
||||||
|
'maxPostSizeNotice': __('Your CSV is over %s, and too big to process. Please split the file in two, or more.')|replace({'%s': maxPostSize}),
|
||||||
|
'dataProcessingError': __("Your data couldn't be processed. Please make sure it is in the proper format."),
|
||||||
|
'noValidRecords': __('No valid records were found.'),
|
||||||
|
'importNoticeSkipped': __('%1$s records were skipped due to problems.'),
|
||||||
|
'importNoticeInvalid': __('%1$s emails are not valid : %2$s.'),
|
||||||
|
'importNoticeDuplicate': __('%1$s emails appear more than once in your file : %2$s.'),
|
||||||
|
'hideDetails': __('Hide details.'),
|
||||||
|
'showDetails': __('Show more details.'),
|
||||||
|
'listSelectionRequired': __('You need to select at least one list.'),
|
||||||
|
'addNewList': __('Add new list'),
|
||||||
|
'addNewColumuserColumnsn': __('Add new list'),
|
||||||
|
'userColumns': __('User columns'),
|
||||||
|
'selectedValueAlreadyMatched': __('The selected value is already matched to another column.'),
|
||||||
|
'confirmCorrespondingColumn': __('Can you confirm that this column is corresponding to that field?'),
|
||||||
|
'columnContainInvalidElement': __('One of the columns contains an invalid email. Please fix before continuing.'),
|
||||||
|
'january': __('January'),
|
||||||
|
'february': __('February'),
|
||||||
|
'march': __('March'),
|
||||||
|
'april': __('April'),
|
||||||
|
'may': __('May'),
|
||||||
|
'june': __('June'),
|
||||||
|
'july': __('July'),
|
||||||
|
'august': __('August'),
|
||||||
|
'september': __('September'),
|
||||||
|
'october': __('October'),
|
||||||
|
'november': __('November'),
|
||||||
|
'december': __('December'),
|
||||||
|
'noDateFieldMatch': __("Do not match as a 'date field' if most of the rows for that column return the same error."),
|
||||||
|
'emptyDate': __('Date cannot be empty'),
|
||||||
|
'verifyDateMatch': __('Verify that the date in blue matches the original one'),
|
||||||
|
'pm': __('pm'),
|
||||||
|
'am': __('am'),
|
||||||
|
'dateMatchError': __('Error matching date.'),
|
||||||
|
'columnContainsInvalidDate': __('One of the columns contains an invalid date. Please fix before continuing.'),
|
||||||
|
'listCreateError': __('Error adding a new segment:'),
|
||||||
|
'columnContainsInvalidElement': __('One of the columns contains an invalid email. Please fix before continuing.'),
|
||||||
|
'customFieldCreateError': __('Custom field could not be created.')
|
||||||
}) %>
|
}) %>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var
|
var
|
||||||
maximum_parse_size = <%= maximumParseSize %>,
|
maxPostSize = '<%= maxPostSize %>',
|
||||||
maximum_parse_notice = "<%= __('Your CSV is over %s, and too big to process. Please split the file in two, or more.')|replace({'%s': maximumParseSize}) %>",
|
importData = {},
|
||||||
data_container = {},
|
mailpoet_columns_select2 = <%= subscriberFieldsSelect2|raw %>,
|
||||||
mailpoet_columns_select2 = <%= select2Fields|raw %>,
|
|
||||||
mailpoet_columns = <%= subscriberFields|raw %>,
|
mailpoet_columns = <%= subscriberFields|raw %>,
|
||||||
mailpoet_lists = <%= segments|raw %>,
|
mailpoetLists = <%= segments|raw %>,
|
||||||
email_regex = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-_]{0,61}[a-zA-Z0-9])+.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
emailRegex = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-_]{0,61}[a-zA-Z0-9])+.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
||||||
</script>
|
</script>
|
||||||
<% endblock %>
|
<% endblock %>
|
@ -1,4 +1,4 @@
|
|||||||
<div id="step_1" class="mailpoet_hidden">
|
<div id="step1" class="mailpoet_hidden">
|
||||||
<div class="inside">
|
<div class="inside">
|
||||||
<!-- Method selection -->
|
<!-- Method selection -->
|
||||||
<table class="mailpoet_subscribers form-table">
|
<table class="mailpoet_subscribers form-table">
|
||||||
@ -76,7 +76,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<input type="file" id="file_local">
|
<input type="file" id="file_local">
|
||||||
|
|
||||||
<%= __( 'total max upload file size : %s' )|replace({'%s': maximumParseSize}) %>
|
<%= __( 'total max upload file size : %s' )|replace({'%s': maxPostSize}) %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -109,7 +109,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<select class ="mailchimp_lists_select" multiple="multiple"></select>
|
<select class="mailchimp_lists_select" data-placeholder="<%= __('Select') %>" multiple="multiple"></select>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -143,12 +143,11 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th scope="row">
|
<th scope="row">
|
||||||
<a href="javascript:;"
|
<a href="javascript:;"
|
||||||
class="button-primary wysija mailpoet_process"><%= ('Next step') %> </a>
|
class="button-primary disabled wysija mailpoet_process"><%= ('Next step') %> </a>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
216
views/import/step2.html
Normal file
216
views/import/step2.html
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
<div id="step2" class="mailpoet_hidden">
|
||||||
|
<div id="subscribers_data_parse_results">
|
||||||
|
<!-- Template data -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script id="subscribers_data_parse_results_template" type="text/x-handlebars-template">
|
||||||
|
<div class="notice">
|
||||||
|
<ul>
|
||||||
|
<li>{{{notice}}}</li>
|
||||||
|
<li><a class="mailpoet_subscribers_data_parse_results_details_show"
|
||||||
|
href="javascript:;"><%= __('Show more details.') %></a></li>
|
||||||
|
</ul>
|
||||||
|
<div class="mailpoet_subscribers_data_parse_results_details mailpoet_hidden">
|
||||||
|
<hr>
|
||||||
|
<ul>
|
||||||
|
{{#if duplicate}}
|
||||||
|
<li>{{{duplicate}}}</li>
|
||||||
|
{{/if}}
|
||||||
|
{{#if invalid}}
|
||||||
|
<li>{{{invalid}}}</li>
|
||||||
|
{{/if}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="inside">
|
||||||
|
<br>
|
||||||
|
<!-- Subscribers Data -->
|
||||||
|
<div id="subscribers_data">
|
||||||
|
<table class="mailpoet_subscribers widefat fixed">
|
||||||
|
<!-- Template data -->
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="mailpoet_subscribers form-table">
|
||||||
|
<tbody>
|
||||||
|
<!-- MP3 Segments -->
|
||||||
|
<tr class="mailpoet_segments mailpoet_hidden">
|
||||||
|
<th scope="row">
|
||||||
|
<label>
|
||||||
|
<%= __('Pick one or many segments') %>
|
||||||
|
<p class="description"><%= __('Pick the segments you want to import those subscribers to.') %>
|
||||||
|
</label>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<select id="mailpoet_segments_select" data-placeholder="<%= __('Select') %>" multiple="multiple"></select>
|
||||||
|
<a href="javascript:;" class="mailpoet_create_segment"><%= __('Create new list') %></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="mailpoet_no_segments mailpoet_hidden">
|
||||||
|
<th scope="row">
|
||||||
|
<%=
|
||||||
|
__('To add subscribers to a mailing segment, [link]create a list[/link].')
|
||||||
|
|replace({
|
||||||
|
'[link]': '<a href="javascript:;" class="mailpoet_create_segment">',
|
||||||
|
'[/link]': '</a>'
|
||||||
|
})
|
||||||
|
|raw
|
||||||
|
%>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">
|
||||||
|
<label>
|
||||||
|
<%= __("Update existing subscribers' information") %>
|
||||||
|
</label>
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="subscriber_update_option" value="yes"
|
||||||
|
checked><span><%= __('Yes') %></span>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="subscriber_update_option"
|
||||||
|
value="no"><span><%= __('No') %></span>
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<a href="javascript:;" id="step_2_process"
|
||||||
|
class="button-primary wysija disabled"><%= __('Next step') %> </a>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- subscribers data template -->
|
||||||
|
<script id="subscribers_data_template" type="text/x-handlebars-template">
|
||||||
|
<thead>
|
||||||
|
<th>
|
||||||
|
<%= __('Match data') %>
|
||||||
|
</th>
|
||||||
|
{{#show_and_match_columns .}}
|
||||||
|
{{#.}}
|
||||||
|
<th>
|
||||||
|
<select class="mailpoet_subscribers_column_data_match" data-column-id="{{column_id}}" id="column_{{@index}}">
|
||||||
|
</th>
|
||||||
|
{{/.}}
|
||||||
|
{{/show_and_match_columns}}
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{> subscribers_data_template_partial}}
|
||||||
|
</tbody>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="subscribers_data_template_partial" type="text/x-handlebars-template">
|
||||||
|
{{#if header}}
|
||||||
|
<tr class="mailpoet_header">
|
||||||
|
<td></td>
|
||||||
|
{{#header}}
|
||||||
|
<td>
|
||||||
|
{{this}}
|
||||||
|
</td>
|
||||||
|
{{/header}}
|
||||||
|
</tr>
|
||||||
|
{{/if}}
|
||||||
|
{{#subscribers}}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{show_real_index @index}}
|
||||||
|
</td>
|
||||||
|
{{#.}}
|
||||||
|
<td>
|
||||||
|
{{{this}}}
|
||||||
|
</td>
|
||||||
|
{{/.}}
|
||||||
|
</tr>
|
||||||
|
{{/subscribers}}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- New segment template -->
|
||||||
|
<script id="new_segment_template" type="text/x-handlebars-template">
|
||||||
|
<p>
|
||||||
|
<label><%= __('Name') %>:</label>
|
||||||
|
<input id="new_segment_name" type="text" name="name"/>
|
||||||
|
</p>
|
||||||
|
<p class="mailpoet_validation_error" data-error="segment_name_required">
|
||||||
|
<%= __('You need to specify a name') %>
|
||||||
|
</p>
|
||||||
|
<p class="mailpoet_validation_error" data-error="segment_name_not_unique">
|
||||||
|
<%= __('This name is already taken') %>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<label><%= __('Description') %>:</label>
|
||||||
|
<br/>
|
||||||
|
<textarea id="new_segment_description" cols="40" rows="3" name="description"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<p class="mailpoet_align_right">
|
||||||
|
<input type="submit" value="<%= __('Done') %>" id="new_segment_process"
|
||||||
|
class="button-primary "/>
|
||||||
|
<input type="submit" value="<%= __('Cancel') %>" id="new_segment_cancel"
|
||||||
|
class="button-primary"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- New column template -->
|
||||||
|
<script id="new_column_template" type="text/x-handlebars-template">
|
||||||
|
<p>
|
||||||
|
<label><%= __('Field type') %>:</label>
|
||||||
|
<select id="new_column_type" name="type">
|
||||||
|
<option value="">--</option>
|
||||||
|
<option value="input">
|
||||||
|
<%= __('Text Input') %>
|
||||||
|
</option>
|
||||||
|
<option value="textarea">
|
||||||
|
<%= __('Text Area') %>
|
||||||
|
</option>
|
||||||
|
<option value="radio">
|
||||||
|
<%= __('Radio buttons') %>
|
||||||
|
</option>
|
||||||
|
<option value="checkbox">
|
||||||
|
<%= __('Checkbox') %>
|
||||||
|
</option>
|
||||||
|
<option value="select">
|
||||||
|
<%= __('Select') %>
|
||||||
|
</option>
|
||||||
|
<option value="date">
|
||||||
|
<%= __('Date') %>
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</p>
|
||||||
|
<p class="mailpoet_validation_error" data-error="type_required">
|
||||||
|
<%= __('You need to select a type') %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<label><%= __('Field name') %>:</label>
|
||||||
|
<input id="new_column_name" type="text" name="name" value="{{ name }}"/>
|
||||||
|
</p>
|
||||||
|
<p class="mailpoet_validation_error" data-error="name_required">
|
||||||
|
<%= __('You need to specify a name') %>
|
||||||
|
</p>
|
||||||
|
<p class="mailpoet_validation_error" data-error="name_not_unique">
|
||||||
|
<%= __('This name is already taken') %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<p class="mailpoet_align_right">
|
||||||
|
<input type="submit" value="<%= __('Done') %>" id="new_column_process"
|
||||||
|
class="button-primary "/>
|
||||||
|
<input type="submit" value="<%= __('Cancel') %>" id="new_column_cancel"
|
||||||
|
class="button-primary"/>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
Reference in New Issue
Block a user