List selection & subscribe

- fixed list selection widget (form editor & rendered form)
- ajax subscription works (minus sending the confirmation email)
- bug fixes / polishing / refactoring / cleanup
This commit is contained in:
Jonathan Labreuille
2015-11-05 14:16:44 +01:00
parent a31dce6226
commit 5473f94e24
16 changed files with 287 additions and 405 deletions

View File

@ -402,7 +402,10 @@ var WysijaForm = {
});
// hide list selection if a list widget has been dragged into the editor
$('mailpoet_settings_segment_selection')[(($$('#' + WysijaForm.options.editor + ' [wysija_field="segment"]').length > 0) === true) ? 'hide' : 'show']();
$('mailpoet_settings_segment_selection')[
(($$('#' + WysijaForm.options.editor + ' [wysija_field="segments"]').length > 0) === true)
? 'hide' : 'show'
]();
},
setBlockPositions: function(event, target) {
// release dragging lock
@ -865,11 +868,10 @@ WysijaForm.Block.create = function(block, target) {
if(block.type === 'segment') {
if(block.params.values === undefined) {
var settings_segments = jQuery('#mailpoet_form_segments').val();
if(settings_segments.length > 0){
mailpoet_segments.filter(function(segment) {
if(settings_segments !== null && settings_segments.length > 0){
block.params.values = mailpoet_segments.filter(function(segment) {
return (settings_segments.indexOf(segment.id) !== -1);
});
block.params.values = mailpoet_segments;
}
}
}

View File

@ -505,7 +505,7 @@ define(
MailPoet.Ajax.post({
endpoint: this.props.endpoint,
action: 'bulk_action',
action: 'bulkAction',
data: data
}).done(function(response) {
this.getItems();

View File

@ -8,31 +8,12 @@ define('public', ['mailpoet', 'jquery', 'jquery-validation'],
return (window.location.hostname === link.hostname);
}
function formatData(raw) {
var data = {};
$.each(raw, function(index, value) {
if(value.name.endsWith('[]')) {
var value_name = value.name.substr(0, value.name.length - 2);
// it's an array
if(data[value_name] === undefined) {
data[value_name] = [];
}
data[value_name].push(value.value);
} else {
data[value.name] = value.value;
}
});
return data;
}
$(function() {
// setup form validation
$('form.mailpoet_form').each(function() {
$(this).validate({
submitHandler: function(form) {
var data = $(form).serializeArray() || {};
var data = $(form).serializeObject() || {};
// clear messages
$(form).find('.mailpoet_message').html('');
@ -47,12 +28,12 @@ define('public', ['mailpoet', 'jquery', 'jquery-validation'],
url: MailPoetForm.ajax_url,
token: MailPoetForm.token,
endpoint: 'subscribers',
action: 'save',
data: formatData(data),
action: 'subscribe',
data: data,
onSuccess: function(response) {
if(response !== true) {
if(response.result !== true) {
// errors
$.each(response, function(index, error) {
$.each(response.errors, function(index, error) {
$(form)
.find('.mailpoet_message')
.append('<p class="mailpoet_validate_error">'+

View File

@ -11,22 +11,28 @@ if(!defined('ABSPATH')) exit;
class Widget extends \WP_Widget {
function __construct () {
add_action(
'wp_ajax_mailpoet_form_subscribe',
array($this, 'subscribe')
);
add_action(
'wp_ajax_nopriv_mailpoet_form_subscribe',
array($this, 'subscribe')
);
add_action(
'admin_post_nopriv_mailpoet_form_subscribe',
array($this, 'subscribe')
);
add_action(
'admin_post_mailpoet_form_subscribe',
array($this, 'subscribe')
);
// add_action(
// 'wp_ajax_mailpoet_form_subscribe',
// array($this, 'subscribe')
// );
// add_action(
// 'wp_ajax_nopriv_mailpoet_form_subscribe',
// array($this, 'subscribe')
// );
// add_action(
// 'admin_post_nopriv_mailpoet_form_subscribe',
// array($this, 'subscribe')
// );
// add_action(
// 'admin_post_mailpoet_form_subscribe',
// array($this, 'subscribe')
// );
// add_action(
// 'init',
// array($this, 'subscribe')
// );
return parent::__construct(
'mailpoet_form',
__("MailPoet Subscription Form"),
@ -190,249 +196,6 @@ class Widget extends \WP_Widget {
}
}
}
static function subscribe() {
// check to see if we're in an ajax request or post request
$doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX);
if(isset($_GET['action']) && $_GET['action'] === 'mailpoet_form_subscribe') {
// input data
$data = array();
// output errors
$errors = array();
// get posted data
// ajax data
$data = json_decode(file_get_contents('php://input'), true);
// -or- post data
if($data === NULL && !empty($_POST)) { $data = $_POST; }
// create or update subscriber
$subscriber = Subscriber::where('email', $data['email'])->findOne();
// is signup confirmation enabled?
$signup_confirmation = Setting::getValue('signup_confirmation');
if($subscriber === false) {
// create new subscriber
$data['status'] = (
($signup_confirmation['enabled'] === true)
? 'unconfirmed' : 'subscribed'
);
// // set custom fields
// $meta_fields = $mailpoet->getOption('mailpoet_subscriber_meta', array());
// if(!empty($meta_fields)) {
// // loop through data to see if any meta field has been passed
// foreach($meta_fields as $field => $field_data) {
// // check if it's a mandatory field
// $is_required = (isset($field_data['params']['required']) && (bool)$field_data['params']['required'] === true);
// if(array_key_exists($field, $data)) {
// // check if it's a mandatory field
// if($is_required === true && empty($data[$field])) {
// // if it's missing, throw an error
// $errors[] = sprintf(__('&quot;%s&quot; is required'), $field_data['name']);
// } else {
// // assign field to subscriber
// $subscriber[$field] = $data[$field];
// }
// }
// }
// }
if(empty($errors)) {
// insert new subscriber
$subscriber = Subscriber::createOrUpdate($data);
if($subscriber === false || !$subscriber->id()) {
$errors = array_merge($errors, $subscriber->getValidationErrors());
}
}
} else {
// restore deleted subscriber
if($subscriber->deleted_at !== NULL) {
// reset subscriber state (depends whether signup confirmation is enabled)
$subscriber
->set('status', array(
($signup_confirmation['enabled'] === true)
? 'unconfirmed' : 'subscribed'
))
->setExpr('deleted_at', 'NULL');
if(!$subscriber->save()) {
$errors[] = __('An error occurred. Please try again later.');
}
}
}
// check if form id has been passed
if(isset($data['form']) && (int)$data['form'] > 0) {
// get form id
$form_id = (int)$data['form'];
// get form
$form = Form::findOne($form_id);
if($form === false || !$form->id()) {
$errors[] = __('This form does not exist. Please check your forms.');
} else {
// set subscriptions
if(empty($data['segments'])) {
$errors[] = __('You need to select a list');
} else {
// get segments
$segments = Segment::whereIn('id', $data['segments'])->findMany();
$segments_subscribed = array();
foreach($segments as $segment) {
if($segment->addSubscriber($subscriber->id())) {
$segments_subscribed[] = $segment->id;
}
}
// if signup confirmation is enabled and the subscriber is unconfirmed
if($signup_confirmation['enabled'] === true
&& !empty($segments_subscribed)
&& $subscriber->status !== 'subscribed'
) {
// TODO: send confirmation email
// resend confirmation email
$is_sent = static::sendSignupConfirmation(
$subscriber->asArray(),
$segments->asArray()
);
// error message if the email could not be sent
if($is_sent === false) {
$errors[] = __('The signup confirmation email could not be sent. Please check your settings.');
}
}
}
}
// get success message to display after subscription
$form_settings = (
isset($form->settings)
? unserialize($form->settings) : null
);
if($subscriber !== null && empty($errors)) {
$success = true;
$message = $form_settings['success_message'];
} else {
$success = false;
$message = join('<br />', $errors);
}
if($form_settings !== null) {
// url params for non ajax requests
if($doing_ajax === false) {
// get referer
$referer = (wp_get_referer() !== false) ? wp_get_referer() : $_SERVER['HTTP_REFERER'];
// redirection parameters
$params = array(
'mailpoet_form' => (int)$data['form']
);
// handle success/error messages
if($success === false) {
$params['mailpoet_error'] = urlencode($message);
} else {
$params['mailpoet_success'] = urlencode($message);
}
}
switch ($form_settings['on_success']) {
case 'page':
// response depending on context
if($doing_ajax === true) {
echo json_encode(array(
'success' => $success,
'page' => get_permalink($form_settings['success_page']),
'message' => $message
));
} else {
$redirect_to = ($success === false) ? $referer : get_permalink($form_settings['success_page']);
wp_redirect(add_query_arg($params, $redirect_to));
}
break;
case 'message':
default:
// response depending on context
if($doing_ajax === true) {
echo json_encode(array(
'success' => $success,
'message' => $message
));
} else {
// redirect to previous page
wp_redirect(add_query_arg($params, $referer));
}
break;
}
}
}
exit();
}
}
static function sendSignupConfirmation(array $subscriber, array $segments) {
print "<pre>";
print_r($subscriber);
print_r($segments);
print "</pre>";
//$mailer = new MailPoetMailer($mailpoet->settings()->getAll());
$signup_confirmation = Setting::getValue('signup_confirmation');
$body = (
!empty($signup_confirmation['body'])
? $signup_confirmation['body'] : ''
);
// check for lists_to_confirm tag
if(strpos($body, '[lists_to_confirm]') !== FALSE) {
// gather all names from lists
$segment_names = array_map(function($segment) { return $segment['list_name']; }, $segments);
// replace shortcode by list names in email's body
$body = str_replace('[lists_to_confirm]', join(', ', $segment_names), $body);
}
// check for activation_link tags
if(strpos($body, '[activation_link]') !== FALSE && strpos($body, '[/activation_link]') !== FALSE) {
// get confirmation page id
$confirmation_page_id = $mailpoet->settings()->get('signup_confirmation_page');
// generate confirmation link
$confirmation_link = add_query_arg(array(
'mailpoet_key' => $subscriber['subscriber_digest']
), get_permalink($confirmation_page_id));
// we have both tags
$body = str_replace(
array('[activation_link]', '[/activation_link]'),
array('<a href="'.$confirmation_link.'">', '</a>'),
$body
);
} else {
// no activation link tags detected
// TODO...
}
// send confirmation email
return $mailer->send(array(
'from_email' => $mailpoet->settings()->get('signup_confirmation_from_email'),
'from_name' => $mailpoet->settings()->get('signup_confirmation_from_name'),
'reply_email' => $mailpoet->settings()->get('signup_confirmation_reply_email'),
'reply_name' => $mailpoet->settings()->get('signup_confirmation_reply_name'),
'subject' => $signup_confirmation['subject'],
'html' => nl2br($signup_confirmation['body']),
// 'text' => '',
'to_email' => $subscriber['subscriber_email'],
'to_name' => $subscriber['subscriber_email'],
));
}
}
// mailpoet shortcodes
@ -453,13 +216,6 @@ function mailpoet_form_shortcode($params = array()) {
}
}
/*
add_action(
'init',
array(__NAMESPACE__.'\Widget', 'subscribe')
);
*/
// set the content filter to replace the shortcode
if(isset($_GET['mailpoet_page']) && strlen(trim($_GET['mailpoet_page'])) > 0) {
switch($_GET['mailpoet_page']) {

View File

@ -1,36 +0,0 @@
<?php
namespace MailPoet\Listing;
if(!defined('ABSPATH')) exit;
class ItemAction {
private $model = null;
private $action = null;
private $data = null;
function __construct($model_class, $data) {
$id = (int)$data['id'];
unset($data['id']);
$this->action = $data['action'];
unset($data['action']);
$this->model = $model_class::findOne($id);
if(!empty($data)) {
$this->data = $data;
}
return $this;
}
function apply() {
if($this->data === null) {
return call_user_func_array(
array($this->model, $this->action),
array()
);
} else {
return call_user_func_array(
array($this->model, $this->action),
array($this->data)
);
}
}
}

View File

@ -79,33 +79,6 @@ class Form extends Model {
$form = self::findOne((int)$data['id']);
}
// check if the user gets to pick his own lists
// or if it's selected by the admin
$has_segment_selection = false;
if(!empty($body)) {
foreach ($body as $i => $block) {
if($block['type'] === 'segment') {
$has_segment_selection = true;
if(!empty($block['params']['values'])) {
$list_selection = array_map(function($segment) {
if(!empty($segment)) {
return (int)$segment['id'];
}
}, $block['params']['values']);
}
break;
}
}
}
// check list selectio
if($has_segment_selection === true) {
$settings['segments_selected_by'] = 'user';
} else {
$settings['segments_selected_by'] = 'admin';
}
if($form === false) {
$form = self::create();
$form->hydrate($data);

View File

@ -109,16 +109,7 @@ class Segment extends Model {
$segment->set($data);
}
$saved = $segment->save();
if($saved === true) {
return true;
} else {
$errors = $segment->getValidationErrors();
if(!empty($errors)) {
return $errors;
}
}
return false;
$segment->save();
return $segment;
}
}

View File

@ -117,6 +117,8 @@ class Subscriber extends Model {
static function groupBy($orm, $group = null) {
if($group === 'trash') {
return $orm->whereNotNull('deleted_at');
} else if($group === 'all') {
return $orm->whereNull('deleted_at');
} else {
return $orm->filter($group);
}
@ -158,13 +160,13 @@ class Subscriber extends Model {
if(isset($data['id']) && (int)$data['id'] > 0) {
$subscriber = self::findOne((int)$data['id']);
unset($data['id']);
}
if($subscriber === false) {
$subscriber = self::create();
$subscriber->hydrate($data);
} else {
unset($data['id']);
$subscriber->set($data);
}

View File

@ -34,7 +34,11 @@ class Forms {
// fetch segments relations for each returned item
foreach($listing_data['items'] as &$item) {
// form's segments
$form_settings = unserialize($item['settings']);
$form_settings = (
(is_serialized($item['settings']))
? unserialize($item['settings'])
: array()
);
$item['segments'] = (
!empty($form_settings['segments'])
@ -128,7 +132,7 @@ class Forms {
}
}
function save_editor($data = array()) {
function saveEditor($data = array()) {
$form_id = (isset($data['id']) ? (int)$data['id'] : 0);
$body = (isset($data['body']) ? $data['body'] : array());
$settings = (isset($data['settings']) ? $data['settings'] : array());
@ -149,6 +153,31 @@ class Forms {
}
}
}
// check if the user gets to pick his own lists
// or if it's selected by the admin
$has_segment_selection = false;
foreach ($body as $i => $block) {
if($block['type'] === 'segment') {
$has_segment_selection = true;
if(!empty($block['params']['values'])) {
$list_selection = array_map(function($segment) {
if(!empty($segment)) {
return (int)$segment['id'];
}
}, $block['params']['values']);
}
break;
}
}
// check list selectio
if($has_segment_selection === true) {
$settings['segments_selected_by'] = 'user';
} else {
$settings['segments_selected_by'] = 'admin';
}
}
$form = Form::createOrUpdate(array(
@ -213,7 +242,7 @@ class Forms {
wp_send_json($result);
}
function item_action($data = array()) {
function itemAction($data = array()) {
$item_action = new Listing\ItemAction(
'\MailPoet\Models\Form',
$data
@ -222,7 +251,7 @@ class Forms {
wp_send_json($item_action->apply());
}
function bulk_action($data = array()) {
function bulkAction($data = array()) {
$bulk_action = new Listing\BulkAction(
'\MailPoet\Models\Form',
$data

View File

@ -204,7 +204,15 @@ class Newsletters {
wp_send_json($listing_data);
}
function bulk_action($data = array()) {
function itemAction($data = array()) {
$item_action = new Listing\ItemAction(
'\MailPoet\Models\Newsletter',
$data
);
wp_send_json($item_action->apply());
}
function bulkAction($data = array()) {
$bulk_action = new Listing\BulkAction(
'\MailPoet\Models\Newsletter',
$data

View File

@ -128,16 +128,7 @@ class Segments {
wp_send_json($result);
}
function item_action($data = array()) {
$item_action = new Listing\ItemAction(
'\MailPoet\Models\Segment',
$data
);
wp_send_json($item_action->apply());
}
function bulk_action($data = array()) {
function bulkAction($data = array()) {
$bulk_action = new Listing\BulkAction(
'\MailPoet\Models\Segment',
$data

View File

@ -4,6 +4,9 @@ namespace MailPoet\Router;
use MailPoet\Listing;
use MailPoet\Models\Subscriber;
use MailPoet\Models\SubscriberSegment;
use MailPoet\Models\Segment;
use MailPoet\Models\Setting;
use MailPoet\Models\Form;
if(!defined('ABSPATH')) exit;
@ -55,10 +58,188 @@ class Subscribers {
}
function save($data = array()) {
$result = Subscriber::createOrUpdate($data);
$result = false;
$subscriber = Subscriber::createOrUpdate($data);
if($subscriber !== false && !$subscriber->id()) {
$result = array(
'errors' => $subscriber->getValidationErrors()
);
} else {
$result = true;
}
wp_send_json($result);
}
function subscribe($data = array()) {
$doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX);
$errors = array();
$form = Form::findOne($data['form_id']);
unset($data['form_id']);
if($form === false || !$form->id()) {
$errors[] = __('This form does not exist.');
}
$segments = Segment::whereIn('id', (array)$data['segments'])->findMany();
unset($data['segments']);
if(empty($segments)) {
$errors[] = __('You need to select a list');
}
if(!empty($errors)) {
wp_send_json(array('errors' => $errors));
} else {
$subscriber = Subscriber::where('email', $data['email'])->findOne();
}
$signup_confirmation = Setting::getValue('signup_confirmation', array());
if($subscriber === false) {
// create new subscriber
$data['status'] = (
(!empty($signup_confirmation['enabled']))
? 'unconfirmed' : 'subscribed'
);
// // set custom fields
// $meta_fields = $mailpoet->getOption('mailpoet_subscriber_meta', array());
// if(!empty($meta_fields)) {
// // loop through data to see if any meta field has been passed
// foreach($meta_fields as $field => $field_data) {
// // check if it's a mandatory field
// $is_required = (isset($field_data['params']['required']) && (bool)$field_data['params']['required'] === true);
// if(array_key_exists($field, $data)) {
// // check if it's a mandatory field
// if($is_required === true && empty($data[$field])) {
// // if it's missing, throw an error
// $errors[] = sprintf(__('&quot;%s&quot; is required'), $field_data['name']);
// } else {
// // assign field to subscriber
// $subscriber[$field] = $data[$field];
// }
// }
// }
// }
// insert new subscriber
$subscriber = Subscriber::createOrUpdate($data);
if($subscriber === false || !$subscriber->id()) {
$errors = array_merge($errors, $subscriber->getValidationErrors());
}
} else {
$subscriber->set('status', (
!empty($signup_confirmation['enabled'])
? 'unconfirmed' : 'subscribed'
));
// restore deleted subscriber
if($subscriber->deleted_at !== NULL) {
$subscriber->setExpr('deleted_at', 'NULL');
}
if(!$subscriber->save()) {
$errors[] = __('An error occurred. Please try again later.');
}
}
// get segments
// IDEA: $subscriptions->addToSegments($data['segments']);
$segments_subscribed = array();
foreach($segments as $segment) {
if($segment->addSubscriber($subscriber->id())) {
$segments_subscribed[] = $segment->id;
}
}
// if signup confirmation is enabled and the subscriber is unconfirmed
if(!empty($signup_confirmation['enabled'])
&& !empty($segments_subscribed)
&& $subscriber->status !== 'subscribed'
) {
// TODO: send confirmation email
// resend confirmation email
$is_sent = true;
/*$is_sent = static::sendSignupConfirmation(
$subscriber->asArray(),
$segments->asArray()
);*/
// error message if the email could not be sent
if($is_sent === false) {
$errors[] = __('The signup confirmation email could not be sent. Please check your settings.');
}
}
// get success message to display after subscription
$form_settings = (
isset($form->settings)
? unserialize($form->settings) : null
);
if($subscriber !== null && empty($errors)) {
$result = true;
$message = $form_settings['success_message'];
} else {
$result = false;
}
if($form_settings !== null) {
// url params for non ajax requests
if($doing_ajax === false) {
// get referer
$referer = (wp_get_referer() !== false)
? wp_get_referer() : $_SERVER['HTTP_REFERER'];
// redirection parameters
$params = array(
'mailpoet_form' => $form->id()
);
// handle success/error messages
if($result === false) {
$params['mailpoet_error'] = urlencode($message);
} else {
$params['mailpoet_success'] = urlencode($message);
}
}
switch ($form_settings['on_success']) {
case 'page':
// response depending on context
if($doing_ajax === true) {
wp_send_json(array(
'result' => $result,
'page' => get_permalink($form_settings['success_page']),
'message' => $message
));
} else {
$redirect_to = ($result === false) ? $referer : get_permalink($form_settings['success_page']);
wp_redirect(add_query_arg($params, $redirect_to));
}
break;
case 'message':
default:
// response depending on context
if($doing_ajax === true) {
wp_send_json(array(
'result' => $result,
'message' => $message
));
} else {
// redirect to previous page
wp_redirect(add_query_arg($params, $referer));
}
break;
}
}
}
function restore($id) {
$result = false;
@ -93,16 +274,7 @@ class Subscribers {
wp_send_json($result);
}
function item_action($data = array()) {
$item_action = new Listing\ItemAction(
'\MailPoet\Models\Segment',
$data
);
wp_send_json($item_action->apply());
}
function bulk_action($data = array()) {
function bulkAction($data = array()) {
$bulk_action = new Listing\BulkAction(
'\MailPoet\Models\Subscriber',
$data

View File

@ -225,7 +225,7 @@
},
{
name: "<%= __('First name') %>",
field: 'firstname',
field: 'first_name',
type: 'input',
params: {
label: "<%= __('First name') %>"
@ -234,7 +234,7 @@
},
{
name: "<%= __('Last name') %>",
field: 'lastname',
field: 'last_name',
type: 'input',
params: {
label: "<%= __('Last name') %>"
@ -272,7 +272,7 @@
});
// toolbar: open default section
$('.mailpoet_toolbar_section[data-section="fields"]').removeClass('closed');
$('.mailpoet_toolbar_section[data-section="shortcodes"]').removeClass('closed');
// form: edit name (in place editor)
$('#mailpoet_form_edit_name').on('click', function() {
@ -381,7 +381,7 @@
MailPoet.Ajax.post({
endpoint: 'forms',
action: 'save_editor',
action: 'saveEditor',
data: form
}).done(function(response) {
if(response === false) {
@ -425,9 +425,17 @@
$('#mailpoet_on_success_'+value).show();
}
function mailpoet_form_export(exports) {
function mailpoet_form_export() {
var template = Handlebars.compile($('#form_template_exports').html());
$('#mailpoet_form_export').html(template({ exports: exports }));
MailPoet.Ajax.post({
endpoint: 'forms',
action: 'getExports',
data: $('#mailpoet_form_id').val()
}).done(function(response) {
if(response !== false) {
$('#mailpoet_form_export').html(template({ exports: response }));
}
});
}
$(document).on('click', '.mailpoet_form_export_toggle', function() {

View File

@ -6,7 +6,7 @@
{{#ifCond type '==' 'input'}}
{{> _settings_label }}
{{> _settings_label_within }}
{{#ifCond field 'in' 'firstname,lastname' }}
{{#ifCond field 'in' 'first_name,last_name' }}
{{> _settings_required }}
{{/ifCond}}
{{/ifCond}}

View File

@ -15,7 +15,7 @@
>
<div class="mailpoet_message"></div>
<input type="hidden" name="form" value="<%= form.id %>" />
<input type="hidden" name="form_id" value="<%= form.id %>" />
<% if not(settings.segments_selected_by == 'user') %>
<input type="hidden" name="segments" value="<%= settings.segments | join(',') %>" />

View File

@ -146,7 +146,12 @@ config.push(_.extend({}, baseConfig, {
config.push(_.extend({}, baseConfig, {
name: 'public',
entry: {
public: ['mailpoet', 'ajax', 'public.js']
public: [
'mailpoet',
'ajax',
'jquery.serialize_object',
'public.js'
]
},
externals: {
'jquery': 'jQuery'