forms listing complete
This commit is contained in:
@ -1,10 +1,12 @@
|
||||
define([
|
||||
'react',
|
||||
'react-dom',
|
||||
'jquery',
|
||||
'select2'
|
||||
],
|
||||
function(
|
||||
React,
|
||||
ReactDOM,
|
||||
jQuery
|
||||
) {
|
||||
var Selection = React.createClass({
|
||||
@ -21,12 +23,12 @@ function(
|
||||
this.setupSelect2();
|
||||
},
|
||||
setupSelect2: function() {
|
||||
if(this.state.initialized === true) {
|
||||
if(!this.props.field.multiple || this.state.initialized === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.props.field.select2 && Object.keys(this.props.item).length > 0) {
|
||||
var select2 = jQuery('#'+this.props.field.id).select2({
|
||||
if(Object.keys(this.props.item).length > 0) {
|
||||
var select2 = jQuery('#'+this.refs.select.id).select2({
|
||||
width: (this.props.width || ''),
|
||||
templateResult: function(item) {
|
||||
if (item.element && item.element.selected) {
|
||||
@ -37,8 +39,7 @@ function(
|
||||
}
|
||||
});
|
||||
|
||||
select2.on('change', this.handleChange)
|
||||
|
||||
select2.on('change', this.handleChange);
|
||||
select2.select2(
|
||||
'val',
|
||||
this.props.item[this.props.field.name]
|
||||
@ -55,11 +56,16 @@ function(
|
||||
});
|
||||
}
|
||||
},
|
||||
handleChange: function() {
|
||||
handleChange: function(e) {
|
||||
if(this.props.onValueChange !== undefined) {
|
||||
if(this.props.field.multiple) {
|
||||
value = jQuery('#'+this.refs.select.id).select2('val');
|
||||
} else {
|
||||
value = e.target.value;
|
||||
}
|
||||
this.props.onValueChange({
|
||||
target: {
|
||||
value: jQuery('#'+this.props.field.id).select2('val'),
|
||||
value: value,
|
||||
name: this.props.field.name
|
||||
}
|
||||
});
|
||||
@ -89,7 +95,8 @@ function(
|
||||
|
||||
return (
|
||||
<select
|
||||
id={ this.props.field.id }
|
||||
id={ this.props.field.id || this.props.field.name }
|
||||
ref="select"
|
||||
placeholder={ this.props.field.placeholder }
|
||||
multiple={ this.props.field.multiple }
|
||||
onChange={ this.handleChange }
|
||||
|
@ -14,7 +14,8 @@ const fields = [
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
type: 'selection',
|
||||
endpoint: 'segments'
|
||||
endpoint: 'segments',
|
||||
multiple: true
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Router, Link, History } from 'react-router'
|
||||
import { Router, Link } from 'react-router'
|
||||
import Listing from 'listing/listing.jsx'
|
||||
import classNames from 'classnames'
|
||||
import MailPoet from 'mailpoet'
|
||||
@ -11,6 +11,11 @@ const columns = [
|
||||
label: 'Name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
name: 'segments',
|
||||
label: 'Lists',
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
name: 'created_at',
|
||||
label: 'Created on',
|
||||
@ -20,64 +25,65 @@ const columns = [
|
||||
|
||||
const messages = {
|
||||
onTrash: function(response) {
|
||||
let count = ~~response.forms;
|
||||
if(response) {
|
||||
let message = null;
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 form was moved to the trash.'
|
||||
);
|
||||
} else if(count > 1) {
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d forms were moved to the trash.'
|
||||
).replace('%$1d', count);
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
onDelete: function(response) {
|
||||
let count = ~~response.forms;
|
||||
if(response) {
|
||||
let message = null;
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 form was permanently deleted.'
|
||||
);
|
||||
} else if(count > 1) {
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d forms were permanently deleted.'
|
||||
).replace('%$1d', count);
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
onRestore: function(response) {
|
||||
let count = ~~response.forms;
|
||||
if(response) {
|
||||
let message = null;
|
||||
|
||||
if(count === 1 || response === true) {
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 form has been restored from the trash.'
|
||||
);
|
||||
} else if(count > 1) {
|
||||
} else if(~~response > 1) {
|
||||
message = (
|
||||
'%$1d forms have been restored from the trash.'
|
||||
).replace('%$1d', count);
|
||||
).replace('%$1d', ~~response);
|
||||
}
|
||||
|
||||
if(message !== null) {
|
||||
MailPoet.Notice.success(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
link: function(item) {
|
||||
return (
|
||||
<Link to={ `/edit/${item.id}` }>Edit</Link>
|
||||
@ -86,24 +92,17 @@ const item_actions = [
|
||||
},
|
||||
{
|
||||
name: 'duplicate_form',
|
||||
refresh: true,
|
||||
link: function(item) {
|
||||
return (
|
||||
<a
|
||||
href="javascript:;"
|
||||
onClick={ this.onDuplicate.bind(null, item) }
|
||||
>Duplicate</a>
|
||||
);
|
||||
},
|
||||
onDuplicate: function(item) {
|
||||
MailPoet.Ajax.post({
|
||||
label: 'Duplicate',
|
||||
onClick: function(item, refresh) {
|
||||
return MailPoet.Ajax.post({
|
||||
endpoint: 'forms',
|
||||
action: 'duplicate',
|
||||
data: item.id
|
||||
}).done(function() {
|
||||
}).done(function(response) {
|
||||
MailPoet.Notice.success(
|
||||
('List "%$1s" has been duplicated.').replace('%$1s', item.name)
|
||||
('Form "%$1s" has been duplicated.').replace('%$1s', response.name)
|
||||
);
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -113,12 +112,7 @@ const bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
getData: function() {
|
||||
return {
|
||||
confirm: false
|
||||
}
|
||||
},
|
||||
onSuccess: messages.onDelete
|
||||
onSuccess: messages.onTrash
|
||||
}
|
||||
];
|
||||
|
||||
@ -161,6 +155,8 @@ const FormList = React.createClass({
|
||||
</h2>
|
||||
|
||||
<Listing
|
||||
location={ this.props.location }
|
||||
params={ this.props.params }
|
||||
messages={ messages }
|
||||
search={ false }
|
||||
limit={ 1000 }
|
||||
|
@ -34,11 +34,9 @@ define(
|
||||
};
|
||||
},
|
||||
handleSelectItem: function(e) {
|
||||
var is_checked = jQuery(e.target).is(':checked');
|
||||
|
||||
this.props.onSelectItem(
|
||||
parseInt(e.target.value, 10),
|
||||
is_checked
|
||||
e.target.checked
|
||||
);
|
||||
|
||||
return !e.target.checked;
|
||||
@ -61,11 +59,12 @@ define(
|
||||
if(this.props.is_selectable === true) {
|
||||
checkbox = (
|
||||
<th className="check-column" scope="row">
|
||||
<label className="screen-reader-text">
|
||||
{ 'Select ' + this.props.item.email }</label>
|
||||
<label className="screen-reader-text">{
|
||||
'Select ' + this.props.item[this.props.columns[0].name]
|
||||
}</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
defaultValue={ this.props.item.id }
|
||||
value={ this.props.item.id }
|
||||
checked={
|
||||
this.props.item.selected || this.props.selection === 'all'
|
||||
}
|
||||
@ -267,7 +266,7 @@ define(
|
||||
is_selectable={ this.props.is_selectable }
|
||||
item_actions={ this.props.item_actions }
|
||||
group={ this.props.group }
|
||||
key={ 'item-' + index }
|
||||
key={ `item-${item.id}-${index}` }
|
||||
item={ item } />
|
||||
);
|
||||
}.bind(this))}
|
||||
|
@ -34,8 +34,7 @@ define(
|
||||
placeholder: "Select a list",
|
||||
id: "mailpoet_segments",
|
||||
endpoint: "segments",
|
||||
multiple: true,
|
||||
select2: true
|
||||
multiple: true
|
||||
},
|
||||
{
|
||||
name: 'sender',
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Router, Route, Link } from 'react-router'
|
||||
import { Router, Link } from 'react-router'
|
||||
|
||||
import jQuery from 'jquery'
|
||||
import MailPoet from 'mailpoet'
|
||||
@ -40,10 +40,10 @@ var columns = [
|
||||
}
|
||||
];
|
||||
|
||||
var messages = {
|
||||
const messages = {
|
||||
onTrash: function(response) {
|
||||
if(response) {
|
||||
var message = null;
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment was moved to the trash.'
|
||||
@ -61,7 +61,7 @@ var messages = {
|
||||
},
|
||||
onDelete: function(response) {
|
||||
if(response) {
|
||||
var message = null;
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment was permanently deleted.'
|
||||
@ -79,7 +79,7 @@ var messages = {
|
||||
},
|
||||
onRestore: function(response) {
|
||||
if(response) {
|
||||
var message = null;
|
||||
let message = null;
|
||||
if(~~response === 1) {
|
||||
message = (
|
||||
'1 segment has been restored from the trash.'
|
||||
@ -97,7 +97,7 @@ var messages = {
|
||||
}
|
||||
};
|
||||
|
||||
var item_actions = [
|
||||
const item_actions = [
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
@ -133,7 +133,7 @@ var item_actions = [
|
||||
}
|
||||
];
|
||||
|
||||
var bulk_actions = [
|
||||
const bulk_actions = [
|
||||
{
|
||||
name: 'trash',
|
||||
label: 'Trash',
|
||||
@ -141,7 +141,7 @@ var bulk_actions = [
|
||||
}
|
||||
];
|
||||
|
||||
var SegmentList = React.createClass({
|
||||
const SegmentList = React.createClass({
|
||||
renderItem: function(segment, actions) {
|
||||
var rowClasses = classNames(
|
||||
'manage-column',
|
||||
|
@ -42,6 +42,7 @@ class Initializer {
|
||||
$forms = Env::$db_prefix . 'forms';
|
||||
$subscriber_segment = Env::$db_prefix . 'subscriber_segment';
|
||||
$newsletter_segment = Env::$db_prefix . 'newsletter_segment';
|
||||
$form_segment = Env::$db_prefix . 'form_segment';
|
||||
$custom_fields = Env::$db_prefix . 'custom_fields';
|
||||
$subscriber_custom_field = Env::$db_prefix . 'subscriber_custom_field';
|
||||
$newsletter_option_fields = Env::$db_prefix . 'newsletter_option_fields';
|
||||
@ -55,6 +56,7 @@ class Initializer {
|
||||
define('MP_SUBSCRIBER_SEGMENT_TABLE', $subscriber_segment);
|
||||
define('MP_NEWSLETTER_TEMPLATES_TABLE', $newsletter_templates);
|
||||
define('MP_NEWSLETTER_SEGMENT_TABLE', $newsletter_segment);
|
||||
define('MP_FORM_SEGMENT_TABLE', $form_segment);
|
||||
define('MP_CUSTOM_FIELDS_TABLE', $custom_fields);
|
||||
define('MP_SUBSCRIBER_CUSTOM_FIELD_TABLE', $subscriber_custom_field);
|
||||
define('MP_NEWSLETTER_OPTION_FIELDS_TABLE', $newsletter_option_fields);
|
||||
|
@ -17,6 +17,7 @@ class Migrator {
|
||||
'segments',
|
||||
'subscriber_segment',
|
||||
'newsletter_segment',
|
||||
'form_segment',
|
||||
'custom_fields',
|
||||
'subscriber_custom_field',
|
||||
'newsletter_option_fields',
|
||||
@ -142,6 +143,18 @@ class Migrator {
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
|
||||
function form_segment() {
|
||||
$attributes = array(
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
'form_id mediumint(9) NOT NULL,',
|
||||
'segment_id mediumint(9) NOT NULL,',
|
||||
'created_at TIMESTAMP NOT NULL DEFAULT 0,',
|
||||
'updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,',
|
||||
'PRIMARY KEY (id)'
|
||||
);
|
||||
return $this->sqlify(__FUNCTION__, $attributes);
|
||||
}
|
||||
|
||||
function custom_fields() {
|
||||
$attributes = array(
|
||||
'id mediumint(9) NOT NULL AUTO_INCREMENT,',
|
||||
|
@ -14,6 +14,15 @@ class Form extends Model {
|
||||
));
|
||||
}
|
||||
|
||||
function segments() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Segment',
|
||||
__NAMESPACE__.'\FormSegment',
|
||||
'form_id',
|
||||
'segment_id'
|
||||
);
|
||||
}
|
||||
|
||||
static function search($orm, $search = '') {
|
||||
return $orm->where_like('name', '%'.$search.'%');
|
||||
}
|
||||
@ -56,57 +65,28 @@ class Form extends Model {
|
||||
$form->set($data);
|
||||
}
|
||||
|
||||
$saved = $form->save();
|
||||
|
||||
if($saved === true) {
|
||||
return true;
|
||||
} else {
|
||||
$errors = $form->getValidationErrors();
|
||||
if(!empty($errors)) {
|
||||
return $errors;
|
||||
}
|
||||
try {
|
||||
$form->save();
|
||||
return $form;
|
||||
} catch(Exception $e) {
|
||||
return $form->getValidationErrors();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static function trash($listing, $data = array()) {
|
||||
$confirm_delete = filter_var($data['confirm'], FILTER_VALIDATE_BOOLEAN);
|
||||
if($confirm_delete) {
|
||||
// delete relations with all segments
|
||||
$forms = $listing->getSelection()->findResultSet();
|
||||
if(!empty($forms)) {
|
||||
$forms_count = 0;
|
||||
foreach($forms as $form) {
|
||||
if($form->delete()) {
|
||||
$forms_count++;
|
||||
function duplicate($data = array()) {
|
||||
$duplicate = parent::duplicate($data);
|
||||
|
||||
if($duplicate !== false) {
|
||||
foreach($this->segments()->findResultSet() as $relation) {
|
||||
$new_relation = FormSegment::create();
|
||||
$new_relation->set('segment_id', $relation->id);
|
||||
$new_relation->set('form_id', $duplicate->id);
|
||||
$new_relation->save();
|
||||
}
|
||||
}
|
||||
return array(
|
||||
'segments' => $forms_count
|
||||
);
|
||||
|
||||
return $duplicate;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
// soft delete
|
||||
$forms = $listing->getSelection()
|
||||
->findResultSet()
|
||||
->set_expr('deleted_at', 'NOW()')
|
||||
->save();
|
||||
|
||||
return array(
|
||||
'segments' => $forms->count()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static function restore($listing, $data = array()) {
|
||||
$forms = $listing->getSelection()
|
||||
->findResultSet()
|
||||
->set_expr('deleted_at', 'NULL')
|
||||
->save();
|
||||
|
||||
return array(
|
||||
'segments' => $forms->count()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
12
lib/Models/FormSegment.php
Normal file
12
lib/Models/FormSegment.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace MailPoet\Models;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
|
||||
class FormSegment extends Model {
|
||||
public static $_table = MP_FORM_SEGMENT_TABLE;
|
||||
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
@ -29,6 +29,15 @@ class Segment extends Model {
|
||||
);
|
||||
}
|
||||
|
||||
function forms() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Form',
|
||||
__NAMESPACE__.'\FormSegment',
|
||||
'segment_id',
|
||||
'form_id'
|
||||
);
|
||||
}
|
||||
|
||||
static function search($orm, $search = '') {
|
||||
return $orm->where_like('name', '%'.$search.'%');
|
||||
}
|
||||
|
@ -15,6 +15,15 @@ class Subscriber extends Model {
|
||||
));
|
||||
}
|
||||
|
||||
function segments() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Segment',
|
||||
__NAMESPACE__.'\SubscriberSegment',
|
||||
'subscriber_id',
|
||||
'segment_id'
|
||||
);
|
||||
}
|
||||
|
||||
function delete() {
|
||||
// delete all relations to segments
|
||||
SubscriberSegment::where('subscriber_id', $this->id)->deleteMany();
|
||||
@ -42,7 +51,9 @@ class Subscriber extends Model {
|
||||
);
|
||||
|
||||
foreach($segments as $segment) {
|
||||
$subscribers_count = $segment->subscribers()->count();
|
||||
$subscribers_count = $segment->subscribers()
|
||||
->whereNull('deleted_at')
|
||||
->count();
|
||||
if($subscribers_count > 0) {
|
||||
$segment_list[] = array(
|
||||
'label' => sprintf('%s (%d)', $segment->name, $subscribers_count),
|
||||
@ -143,15 +154,6 @@ class Subscriber extends Model {
|
||||
return $orm;
|
||||
}
|
||||
|
||||
function segments() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Segment',
|
||||
__NAMESPACE__.'\SubscriberSegment',
|
||||
'subscriber_id',
|
||||
'segment_id'
|
||||
);
|
||||
}
|
||||
|
||||
function customFields() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\CustomField',
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace MailPoet\Router;
|
||||
use \MailPoet\Models\Form;
|
||||
use \MailPoet\Models\FormSegment;
|
||||
use \MailPoet\Listing;
|
||||
|
||||
if(!defined('ABSPATH')) exit;
|
||||
@ -16,7 +17,13 @@ class Forms {
|
||||
if($form === false) {
|
||||
wp_send_json(false);
|
||||
} else {
|
||||
wp_send_json($form->asArray());
|
||||
$segments = $form->segments();
|
||||
$form = $form->asArray();
|
||||
$form['segments'] = array_map(function($segment) {
|
||||
return $segment['id'];
|
||||
}, $segments->findArray());
|
||||
|
||||
wp_send_json($form);
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,6 +35,17 @@ class Forms {
|
||||
|
||||
$listing_data = $listing->get();
|
||||
|
||||
// fetch segments relations for each returned item
|
||||
foreach($listing_data['items'] as &$item) {
|
||||
// form's segments
|
||||
$relations = FormSegment::select('segment_id')
|
||||
->where('form_id', $item['id'])
|
||||
->findMany();
|
||||
$item['segments'] = array_map(function($relation) {
|
||||
return $relation->segment_id;
|
||||
}, $relations);
|
||||
}
|
||||
|
||||
wp_send_json($listing_data);
|
||||
}
|
||||
|
||||
@ -37,53 +55,90 @@ class Forms {
|
||||
}
|
||||
|
||||
function save($data = array()) {
|
||||
$result = Form::createOrUpdate($data);
|
||||
if(isset($data['segments'])) {
|
||||
$segment_ids = $data['segments'];
|
||||
unset($data['segments']);
|
||||
}
|
||||
|
||||
if($result !== true) {
|
||||
wp_send_json($result);
|
||||
$form = Form::createOrUpdate($data);
|
||||
|
||||
if($form->id() && !empty($segment_ids)) {
|
||||
// remove previous relationships with segments
|
||||
FormSegment::where('form_id', $form->id())->deleteMany();
|
||||
|
||||
// create relationship with segments
|
||||
foreach($segment_ids as $segment_id) {
|
||||
$relation = FormSegment::create();
|
||||
$relation->segment_id = $segment_id;
|
||||
$relation->form_id = $form->id();
|
||||
$relation->save();
|
||||
}
|
||||
}
|
||||
|
||||
if($form === false) {
|
||||
wp_send_json($form->getValidationErrors());
|
||||
} else {
|
||||
wp_send_json(true);
|
||||
}
|
||||
}
|
||||
|
||||
function restore($id) {
|
||||
$result = false;
|
||||
|
||||
$form = Form::findOne($id);
|
||||
if($form !== false) {
|
||||
$form->set_expr('deleted_at', 'NULL');
|
||||
$result = $form->save();
|
||||
} else {
|
||||
$result = false;
|
||||
$result = $form->restore();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function delete($data = array()) {
|
||||
$form = Form::findOne($data['id']);
|
||||
$confirm_delete = filter_var($data['confirm'], FILTER_VALIDATE_BOOLEAN);
|
||||
if($form !== false) {
|
||||
if($confirm_delete) {
|
||||
$form->delete();
|
||||
$result = true;
|
||||
} else {
|
||||
$form->set_expr('deleted_at', 'NOW()');
|
||||
$result = $form->save();
|
||||
}
|
||||
} else {
|
||||
function trash($id) {
|
||||
$result = false;
|
||||
|
||||
$form = Form::findOne($id);
|
||||
if($form !== false) {
|
||||
$result = $form->trash();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function delete($id) {
|
||||
$result = false;
|
||||
|
||||
$form = Form::findOne($id);
|
||||
if($form !== false) {
|
||||
$form->delete();
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function duplicate($id) {
|
||||
$result = false;
|
||||
|
||||
$form = Form::duplicate($id);
|
||||
$form = Form::findOne($id);
|
||||
if($form !== false) {
|
||||
$result = $form;
|
||||
$data = array(
|
||||
'name' => sprintf(__('Copy of %s'), $form->name)
|
||||
);
|
||||
$result = $form->duplicate($data)->asArray();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function item_action($data = array()) {
|
||||
$item_action = new Listing\ItemAction(
|
||||
'\MailPoet\Models\Form',
|
||||
$data
|
||||
);
|
||||
|
||||
wp_send_json($item_action->apply());
|
||||
}
|
||||
|
||||
function bulk_action($data = array()) {
|
||||
$bulk_action = new Listing\BulkAction(
|
||||
'\MailPoet\Models\Form',
|
||||
|
Reference in New Issue
Block a user