Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
ebca4257a6 | |||
c3944095bc | |||
a1445d1b6a | |||
e62c24879b | |||
00f06ea202 | |||
32ca24ce38 | |||
44e3adb422 | |||
a1346ebecc | |||
25b51d0446 | |||
556a170903 | |||
7ac386a8e2 | |||
d91b55ec52 | |||
786fbc36a2 | |||
160e8b7a12 | |||
0b1f85da09 | |||
fbc6f54ddc | |||
a603e97b8c | |||
0875b627b6 | |||
035784ece0 | |||
aa93c7349f | |||
82cf4a28fd | |||
832e5ef342 | |||
e3de3a123a | |||
db91590159 | |||
28c61fca0b | |||
e62a8c2ec5 | |||
fdbd1245e3 | |||
0eef46db57 | |||
080ae88a04 | |||
225be9f3cd | |||
c9a42ebb76 | |||
ae9b3df92d | |||
63a08ebb55 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ wysija-newsletters.zip
|
||||
tests/javascript/testBundles
|
||||
assets/css/*.css
|
||||
assets/js/*.js
|
||||
.vagrant
|
||||
|
67
Vagrantfile
vendored
Normal file
67
Vagrantfile
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
Vagrant.configure(2) do |config|
|
||||
config.vm.provider "virtualbox" do |v|
|
||||
v.name = "phoenix"
|
||||
v.memory = "2048"
|
||||
end
|
||||
|
||||
config.vm.define :web do |web|
|
||||
web.vm.box = "ubuntu/trusty64"
|
||||
web.vm.hostname = "phoenix"
|
||||
web.vm.network "forwarded_port", guest: 80, host: 8080
|
||||
web.vm.synced_folder(
|
||||
".",
|
||||
"/var/www/html/wp-content/plugins/wysija-newsletters",
|
||||
create: true,
|
||||
owner: "vagrant",
|
||||
group: "www-data"
|
||||
)
|
||||
|
||||
web.vm.provision "shell", inline: <<-SHELL
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y apache2 curl zip sendmail git build-essential
|
||||
|
||||
sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password password root'
|
||||
sudo debconf-set-selections <<< 'mysql-server mysql-server/root_password_again password root'
|
||||
sudo apt-get install -y mysql-server-5.5
|
||||
|
||||
sudo apt-get install -y php5 libapache2-mod-php5 php5-curl php5-gd php5-mcrypt php5-readline mysql-server-5.5 php5-mysql php-apc
|
||||
sudo sed -i "s/error_reporting = .*/error_reporting = E_ALL/" /etc/php5/apache2/php.ini
|
||||
sudo sed -i "s/display_errors = .*/display_errors = On/" /etc/php5/apache2/php.ini
|
||||
|
||||
cd /var/www/html
|
||||
|
||||
sudo wget https://github.com/calvinlough/sqlbuddy/raw/gh-pages/sqlbuddy.zip -O /var/www/html/sqlbuddy.zip
|
||||
sudo rm index.html
|
||||
unzip sqlbuddy.zip
|
||||
|
||||
sudo curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
|
||||
sudo chmod +x wp-cli.phar
|
||||
sudo mv wp-cli.phar /usr/local/bin/wp
|
||||
sudo wp core download --allow-root
|
||||
mysql -uroot -proot -e "create database wordpress"
|
||||
sudo wp core config --allow-root --dbname=wordpress --dbuser=root --dbpass=root
|
||||
sudo wp core install --allow-root --url="http://localhost:8080" --title=WordPress --admin_user=admin --admin_password=password --admin_email=test@mailpoet-container.com
|
||||
|
||||
sudo sed -i "s/upload_max_filesize = .*/upload_max_filesize = 32M/" /etc/php5/apache2/php.ini
|
||||
sudo sed -i "s/post_max_size = .*/post_max_size = 32M/" /etc/php5/apache2/php.ini
|
||||
sudo chown -hR vagrant:www-data /var/www/html/
|
||||
sudo a2enmod rewrite > /dev/null 2>&1
|
||||
|
||||
cd /var/www/html/wp-content/plugins/wysija-newsletters
|
||||
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
sudo add-apt-repository -y ppa:chris-lea/node.js
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y nodejs
|
||||
|
||||
sudo sed -i "s/export APACHE_RUN_USER.*/export APACHE_RUN_USER=vagrant/" /etc/apache2/envvars
|
||||
sudo chown -R vagrant:www-data /var/lock/apache2
|
||||
|
||||
sudo service apache2 restart
|
||||
SHELL
|
||||
end
|
||||
end
|
@ -159,23 +159,6 @@ body.mailpoet_modal_opened
|
||||
margin: 0
|
||||
text-align: right
|
||||
|
||||
.mailpoet_button
|
||||
padding: 3px 15px
|
||||
border: 1px solid #444
|
||||
font-weight: normal
|
||||
cursor: pointer
|
||||
background-color: #222
|
||||
color: #cfcfcf
|
||||
font-size: 1em
|
||||
|
||||
.mailpoet_button:hover
|
||||
background-color: #00aacc
|
||||
color: #fff
|
||||
|
||||
.mailpoet_button:active
|
||||
background-color: #00ccff
|
||||
color: #fff
|
||||
|
||||
@media screen and (max-width: 782px)
|
||||
#mailpoet_modal_overlay.mailpoet_panel_overlay
|
||||
top: 46px
|
||||
|
@ -19,6 +19,10 @@ $divider-hover-border-color = $primary-active-color
|
||||
width: 100%
|
||||
border: 1px solid transparent
|
||||
|
||||
.mailpoet_active_divider_style
|
||||
border: 1px solid $active-divider-border-color
|
||||
background: $active-divider-background-color
|
||||
|
||||
.mailpoet_field_divider_style:hover
|
||||
border: 1px solid $divider-hover-border-color
|
||||
|
||||
|
@ -1,15 +1,12 @@
|
||||
.mailpoet_posts_block
|
||||
box-shadow(none)
|
||||
padding-left: 0
|
||||
padding-right: 0
|
||||
|
||||
& > .mailpoet_content
|
||||
font-size: 1em
|
||||
text-align: center
|
||||
background-color: $primary-active-color
|
||||
margin: 20px 0
|
||||
padding: 15px
|
||||
box-shadow(inset 1px 2px 1px $primary-inset-shadow-color)
|
||||
color: $white-color
|
||||
border-radius(3px)
|
||||
.mailpoet_posts_block_posts
|
||||
overflow: auto
|
||||
|
||||
& > .mailpoet_block
|
||||
width: 100%
|
||||
|
||||
.mailpoet_post_selection_filter_row
|
||||
margin-top: 5px
|
||||
|
@ -306,7 +306,7 @@ define([
|
||||
_.each(postTypes, function(type) {
|
||||
select.append(jQuery('<option>', {
|
||||
value: type.name,
|
||||
text: type.labels.singular_name,
|
||||
text: type.label,
|
||||
}));
|
||||
});
|
||||
select.val(selectedValue);
|
||||
|
@ -31,7 +31,7 @@ define([
|
||||
base = BaseBlock;
|
||||
|
||||
Module.PostsBlockModel = base.BlockModel.extend({
|
||||
stale: ['_selectedPosts', '_availablePosts'],
|
||||
stale: ['_selectedPosts', '_availablePosts', '_transformedPosts'],
|
||||
defaults: function() {
|
||||
return this._getDefaults({
|
||||
type: 'posts',
|
||||
@ -63,6 +63,7 @@ define([
|
||||
divider: {},
|
||||
_selectedPosts: [],
|
||||
_availablePosts: [],
|
||||
_transformedPosts: new (App.getBlockTypeModel('container'))(),
|
||||
}, App.getConfig().get('blockDefaults.posts'));
|
||||
},
|
||||
relations: function() {
|
||||
@ -71,15 +72,26 @@ define([
|
||||
divider: App.getBlockTypeModel('divider'),
|
||||
_selectedPosts: Backbone.Collection,
|
||||
_availablePosts: Backbone.Collection,
|
||||
_transformedPosts: App.getBlockTypeModel('container'),
|
||||
};
|
||||
},
|
||||
initialize: function() {
|
||||
var that = this;
|
||||
var that = this,
|
||||
POST_REFRESH_DELAY_MS = 500,
|
||||
refreshAvailablePosts = _.debounce(this.fetchAvailablePosts.bind(this), POST_REFRESH_DELAY_MS),
|
||||
refreshTransformedPosts = _.debounce(this._refreshTransformedPosts.bind(this), POST_REFRESH_DELAY_MS);
|
||||
|
||||
// Attach Radio.Requests API primarily for highlighting
|
||||
_.extend(this, Radio.Requests);
|
||||
|
||||
this.fetchAvailablePosts();
|
||||
this.on('change:amount change:contentType change:terms change:inclusionType change:postStatus change:search change:sortBy', this._scheduleFetchAvailablePosts, this);
|
||||
this.on('change:amount change:contentType change:terms change:inclusionType change:postStatus change:search change:sortBy', refreshAvailablePosts);
|
||||
|
||||
this.listenTo(this.get('_selectedPosts'), 'add remove reset', refreshTransformedPosts);
|
||||
this.on('change:displayType change:titleFormat change:titlePosition change:titleAlignment change:titleIsLink change:imagePadded change:showAuthor change:authorPrecededBy change:showCategories change:categoriesPrecededBy change:readMoreType change:readMoreText change:showDivider', refreshTransformedPosts);
|
||||
this.listenTo(this.get('readMoreButton'), 'change', refreshTransformedPosts);
|
||||
this.listenTo(this.get('divider'), 'change', refreshTransformedPosts);
|
||||
|
||||
this.on('insertSelectedPosts', this._insertSelectedPosts, this);
|
||||
},
|
||||
fetchAvailablePosts: function() {
|
||||
@ -93,20 +105,23 @@ define([
|
||||
console.log('Posts fetchPosts error', arguments);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Batch more changes during a specific time, instead of fetching
|
||||
* ALC posts on each model change
|
||||
*/
|
||||
_scheduleFetchAvailablePosts: function() {
|
||||
var timeout = 500,
|
||||
that = this;
|
||||
if (this._fetchPostsTimer !== undefined) {
|
||||
clearTimeout(this._fetchPostsTimer);
|
||||
_refreshTransformedPosts: function() {
|
||||
var that = this,
|
||||
data = this.toJSON();
|
||||
|
||||
data.posts = this.get('_selectedPosts').pluck('ID');
|
||||
|
||||
if (data.posts.length === 0) {
|
||||
this.get('_transformedPosts.blocks').reset();
|
||||
return;
|
||||
}
|
||||
this._fetchPostsTimer = setTimeout(function() {
|
||||
that.fetchAvailablePosts();
|
||||
that._fetchPostsTimer = undefined;
|
||||
}, timeout);
|
||||
|
||||
WordpressComponent.getTransformedPosts(data).done(function(posts) {
|
||||
console.log('Transformed posts fetched', arguments);
|
||||
that.get('_transformedPosts').get('blocks').reset(posts, {parse: true});
|
||||
}).fail(function() {
|
||||
console.log('Posts _refreshTransformedPosts error', arguments);
|
||||
});
|
||||
},
|
||||
_insertSelectedPosts: function() {
|
||||
var that = this,
|
||||
@ -131,6 +146,9 @@ define([
|
||||
className: "mailpoet_block mailpoet_posts_block mailpoet_droppable_block",
|
||||
getTemplate: function() { return templates.postsBlock; },
|
||||
modelEvents: {},
|
||||
regions: _.extend({
|
||||
postsRegion: '.mailpoet_posts_block_posts',
|
||||
}, base.BlockView.prototype.regions),
|
||||
onDragSubstituteBy: function() { return Module.PostsWidgetView; },
|
||||
initialize: function() {
|
||||
base.BlockView.prototype.initialize.apply(this, arguments);
|
||||
@ -142,6 +160,13 @@ define([
|
||||
this.toolsRegion.show(this.toolsView);
|
||||
}
|
||||
this.trigger('showSettings');
|
||||
|
||||
var ContainerView = App.getBlockTypeView('container'),
|
||||
renderOptions = {
|
||||
disableTextEditor: true,
|
||||
disableDragAndDrop: true,
|
||||
};
|
||||
this.postsRegion.show(new ContainerView({ model: this.model.get('_transformedPosts'), renderOptions: renderOptions }));
|
||||
},
|
||||
notifyAboutSelf: function() {
|
||||
return this;
|
||||
@ -216,6 +241,7 @@ define([
|
||||
insertPosts: function() {
|
||||
this.model.trigger('insertSelectedPosts');
|
||||
this.model.destroy();
|
||||
this.close();
|
||||
},
|
||||
});
|
||||
|
||||
@ -307,11 +333,6 @@ define([
|
||||
},
|
||||
}).trigger( 'change' );
|
||||
},
|
||||
onBeforeDestroy: function() {
|
||||
base.BlockSettingsView.prototype.onBeforeDestroy.apply(this, arguments);
|
||||
// Force close select2 if it hasn't closed yet
|
||||
this.$('.mailpoet_posts_categories_and_tags').select2('close');
|
||||
},
|
||||
changeField: function(field, event) {
|
||||
this.model.set(field, jQuery(event.target).val());
|
||||
},
|
||||
@ -323,7 +344,7 @@ define([
|
||||
_.each(postTypes, function(type) {
|
||||
select.append(jQuery('<option>', {
|
||||
value: type.name,
|
||||
text: type.labels.singular_name,
|
||||
text: type.label,
|
||||
}));
|
||||
});
|
||||
select.val(selectedValue);
|
||||
|
@ -56,7 +56,7 @@ define([
|
||||
};
|
||||
|
||||
Module.getTransformedPosts = function(options) {
|
||||
return Module._cachedQuery({
|
||||
return Module._query({
|
||||
action: 'getTransformedPosts',
|
||||
options: options,
|
||||
});
|
||||
|
264
assets/js/src/vendor_static/jquery.sticky-kit.js
Normal file
264
assets/js/src/vendor_static/jquery.sticky-kit.js
Normal file
@ -0,0 +1,264 @@
|
||||
// Generated by CoffeeScript 1.9.2
|
||||
|
||||
/**
|
||||
@license Sticky-kit v1.1.2 | WTFPL | Leaf Corcoran 2015 | http://leafo.net
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var $, win;
|
||||
|
||||
$ = this.jQuery || window.jQuery;
|
||||
|
||||
win = $(window);
|
||||
|
||||
$.fn.stick_in_parent = function(opts) {
|
||||
var doc, elm, enable_bottoming, fn, i, inner_scrolling, len, manual_spacer, offset_top, outer_width, parent_selector, recalc_every, sticky_class;
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
sticky_class = opts.sticky_class, inner_scrolling = opts.inner_scrolling, recalc_every = opts.recalc_every, parent_selector = opts.parent, offset_top = opts.offset_top, manual_spacer = opts.spacer, enable_bottoming = opts.bottoming;
|
||||
if (offset_top == null) {
|
||||
offset_top = 0;
|
||||
}
|
||||
if (parent_selector == null) {
|
||||
parent_selector = void 0;
|
||||
}
|
||||
if (inner_scrolling == null) {
|
||||
inner_scrolling = true;
|
||||
}
|
||||
if (sticky_class == null) {
|
||||
sticky_class = "is_stuck";
|
||||
}
|
||||
doc = $(document);
|
||||
if (enable_bottoming == null) {
|
||||
enable_bottoming = true;
|
||||
}
|
||||
outer_width = function(el) {
|
||||
var _el, computed, w;
|
||||
if (window.getComputedStyle) {
|
||||
_el = el[0];
|
||||
computed = window.getComputedStyle(el[0]);
|
||||
w = parseFloat(computed.getPropertyValue("width")) + parseFloat(computed.getPropertyValue("margin-left")) + parseFloat(computed.getPropertyValue("margin-right"));
|
||||
if (computed.getPropertyValue("box-sizing") !== "border-box") {
|
||||
w += parseFloat(computed.getPropertyValue("border-left-width")) + parseFloat(computed.getPropertyValue("border-right-width")) + parseFloat(computed.getPropertyValue("padding-left")) + parseFloat(computed.getPropertyValue("padding-right"));
|
||||
}
|
||||
return w;
|
||||
} else {
|
||||
return el.outerWidth(true);
|
||||
}
|
||||
};
|
||||
fn = function(elm, padding_bottom, parent_top, parent_height, top, height, el_float, detached) {
|
||||
var bottomed, detach, fixed, last_pos, last_scroll_height, offset, parent, recalc, recalc_and_tick, recalc_counter, spacer, tick;
|
||||
if (elm.data("sticky_kit")) {
|
||||
return;
|
||||
}
|
||||
elm.data("sticky_kit", true);
|
||||
last_scroll_height = doc.height();
|
||||
parent = elm.parent();
|
||||
if (parent_selector != null) {
|
||||
parent = parent.closest(parent_selector);
|
||||
}
|
||||
if (!parent.length) {
|
||||
throw "failed to find stick parent";
|
||||
}
|
||||
fixed = false;
|
||||
bottomed = false;
|
||||
spacer = manual_spacer != null ? manual_spacer && elm.closest(manual_spacer) : $("<div />");
|
||||
if (spacer) {
|
||||
spacer.css('position', elm.css('position'));
|
||||
}
|
||||
recalc = function() {
|
||||
var border_top, padding_top, restore;
|
||||
if (detached) {
|
||||
return;
|
||||
}
|
||||
last_scroll_height = doc.height();
|
||||
border_top = parseInt(parent.css("border-top-width"), 10);
|
||||
padding_top = parseInt(parent.css("padding-top"), 10);
|
||||
padding_bottom = parseInt(parent.css("padding-bottom"), 10);
|
||||
parent_top = parent.offset().top + border_top + padding_top;
|
||||
parent_height = parent.height();
|
||||
if (fixed) {
|
||||
fixed = false;
|
||||
bottomed = false;
|
||||
if (manual_spacer == null) {
|
||||
elm.insertAfter(spacer);
|
||||
spacer.detach();
|
||||
}
|
||||
elm.css({
|
||||
position: "",
|
||||
top: "",
|
||||
width: "",
|
||||
bottom: ""
|
||||
}).removeClass(sticky_class);
|
||||
restore = true;
|
||||
}
|
||||
top = elm.offset().top - (parseInt(elm.css("margin-top"), 10) || 0) - offset_top;
|
||||
height = elm.outerHeight(true);
|
||||
el_float = elm.css("float");
|
||||
if (spacer) {
|
||||
spacer.css({
|
||||
width: outer_width(elm),
|
||||
height: height,
|
||||
display: elm.css("display"),
|
||||
"vertical-align": elm.css("vertical-align"),
|
||||
"float": el_float
|
||||
});
|
||||
}
|
||||
if (restore) {
|
||||
return tick();
|
||||
}
|
||||
};
|
||||
recalc();
|
||||
|
||||
last_pos = void 0;
|
||||
offset = offset_top;
|
||||
recalc_counter = recalc_every;
|
||||
tick = function() {
|
||||
var css, delta, recalced, scroll, will_bottom, win_height;
|
||||
if (detached) {
|
||||
return;
|
||||
}
|
||||
recalced = false;
|
||||
if (recalc_counter != null) {
|
||||
recalc_counter -= 1;
|
||||
if (recalc_counter <= 0) {
|
||||
recalc_counter = recalc_every;
|
||||
recalc();
|
||||
recalced = true;
|
||||
}
|
||||
}
|
||||
if (!recalced && doc.height() !== last_scroll_height) {
|
||||
recalc();
|
||||
recalced = true;
|
||||
}
|
||||
scroll = win.scrollTop();
|
||||
if (last_pos != null) {
|
||||
delta = scroll - last_pos;
|
||||
}
|
||||
last_pos = scroll;
|
||||
if (fixed) {
|
||||
if (enable_bottoming) {
|
||||
will_bottom = scroll + height + offset > parent_height + parent_top;
|
||||
if (bottomed && !will_bottom) {
|
||||
bottomed = false;
|
||||
elm.css({
|
||||
position: "fixed",
|
||||
bottom: "",
|
||||
top: offset
|
||||
}).trigger("sticky_kit:unbottom");
|
||||
}
|
||||
}
|
||||
if (scroll < top) {
|
||||
fixed = false;
|
||||
offset = offset_top;
|
||||
if (manual_spacer == null) {
|
||||
if (el_float === "left" || el_float === "right") {
|
||||
elm.insertAfter(spacer);
|
||||
}
|
||||
spacer.detach();
|
||||
}
|
||||
css = {
|
||||
position: "",
|
||||
width: "",
|
||||
top: ""
|
||||
};
|
||||
elm.css(css).removeClass(sticky_class).trigger("sticky_kit:unstick");
|
||||
}
|
||||
if (inner_scrolling) {
|
||||
win_height = win.height();
|
||||
if (height + offset_top > win_height) {
|
||||
if (!bottomed) {
|
||||
offset -= delta;
|
||||
offset = Math.max(win_height - height, offset);
|
||||
offset = Math.min(offset_top, offset);
|
||||
if (fixed) {
|
||||
elm.css({
|
||||
top: offset + "px"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (scroll > top) {
|
||||
fixed = true;
|
||||
css = {
|
||||
position: "fixed",
|
||||
top: offset
|
||||
};
|
||||
css.width = elm.css("box-sizing") === "border-box" ? elm.outerWidth() + "px" : elm.width() + "px";
|
||||
elm.css(css).addClass(sticky_class);
|
||||
if (manual_spacer == null) {
|
||||
elm.after(spacer);
|
||||
if (el_float === "left" || el_float === "right") {
|
||||
spacer.append(elm);
|
||||
}
|
||||
}
|
||||
elm.trigger("sticky_kit:stick");
|
||||
}
|
||||
}
|
||||
if (fixed && enable_bottoming) {
|
||||
if (will_bottom == null) {
|
||||
will_bottom = scroll + height + offset > parent_height + parent_top;
|
||||
}
|
||||
if (!bottomed && will_bottom) {
|
||||
bottomed = true;
|
||||
if (parent.css("position") === "static") {
|
||||
parent.css({
|
||||
position: "relative"
|
||||
});
|
||||
}
|
||||
return elm.css({
|
||||
position: "absolute",
|
||||
bottom: padding_bottom,
|
||||
top: "auto"
|
||||
}).trigger("sticky_kit:bottom");
|
||||
}
|
||||
}
|
||||
};
|
||||
recalc_and_tick = function() {
|
||||
recalc();
|
||||
return tick();
|
||||
};
|
||||
detach = function() {
|
||||
detached = true;
|
||||
win.off("touchmove", tick);
|
||||
win.off("scroll", tick);
|
||||
win.off("resize", recalc_and_tick);
|
||||
$(document.body).off("sticky_kit:recalc", recalc_and_tick);
|
||||
elm.off("sticky_kit:detach", detach);
|
||||
elm.removeData("sticky_kit");
|
||||
elm.css({
|
||||
position: "",
|
||||
bottom: "",
|
||||
top: "",
|
||||
width: ""
|
||||
});
|
||||
parent.position("position", "");
|
||||
if (fixed) {
|
||||
if (manual_spacer == null) {
|
||||
if (el_float === "left" || el_float === "right") {
|
||||
elm.insertAfter(spacer);
|
||||
}
|
||||
spacer.remove();
|
||||
}
|
||||
return elm.removeClass(sticky_class);
|
||||
}
|
||||
};
|
||||
win.on("touchmove", tick);
|
||||
win.on("scroll", tick);
|
||||
win.on("resize", recalc_and_tick);
|
||||
$(document.body).on("sticky_kit:recalc", recalc_and_tick);
|
||||
elm.on("sticky_kit:detach", detach);
|
||||
return setTimeout(tick, 0);
|
||||
};
|
||||
for (i = 0, len = this.length; i < len; i++) {
|
||||
elm = this[i];
|
||||
fn($(elm));
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
6
build
6
build
@ -7,12 +7,10 @@ rm wysija-newsletters.zip;
|
||||
mkdir wysija-newsletters;
|
||||
|
||||
# Production assets.
|
||||
npm install;
|
||||
./do compile:all;
|
||||
|
||||
# Production libraries.
|
||||
rm -rf vendor;
|
||||
rm -rf node_modules;
|
||||
rm composer.lock;
|
||||
./composer.phar install --no-dev;
|
||||
|
||||
# Copy release folders.
|
||||
@ -38,6 +36,4 @@ zip -r wysija-newsletters.zip wysija-newsletters;
|
||||
rm -rf wysija-newsletters;
|
||||
|
||||
# Reinstall dev dependencies.
|
||||
rm composer.lock;
|
||||
./composer.phar install;
|
||||
./do install;
|
||||
|
61
lib/Config/Changelog.php
Normal file
61
lib/Config/Changelog.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
namespace MailPoet\Config;
|
||||
use \MailPoet\Models\Setting;
|
||||
|
||||
class Changelog {
|
||||
function init() {
|
||||
$doing_ajax = (bool)(defined('DOING_AJAX') && DOING_AJAX);
|
||||
|
||||
// don't run any check when it's an ajax request
|
||||
if($doing_ajax) {
|
||||
return;
|
||||
}
|
||||
|
||||
// don't run any check when we're not on our pages
|
||||
if(
|
||||
!(isset($_GET['page']))
|
||||
or
|
||||
(isset($_GET['page']) && strpos($_GET['page'], 'mailpoet') !== 0)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action(
|
||||
'admin_init',
|
||||
array($this, 'check')
|
||||
);
|
||||
}
|
||||
|
||||
function check() {
|
||||
$version = Setting::getValue('version', null);
|
||||
$redirect_url = null;
|
||||
|
||||
if($version === null) {
|
||||
// new install
|
||||
$redirect_url = admin_url('admin.php?page=mailpoet-welcome');
|
||||
} else if($version !== Env::$version) {
|
||||
// update
|
||||
$redirect_url = admin_url('admin.php?page=mailpoet-update');
|
||||
}
|
||||
|
||||
if($redirect_url !== null) {
|
||||
// save version number
|
||||
Setting::setValue('version', Env::$version);
|
||||
|
||||
global $wp;
|
||||
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
||||
|
||||
if($redirect_url !== $current_url) {
|
||||
wp_safe_redirect(
|
||||
add_query_arg(
|
||||
array(
|
||||
'mailpoet_redirect' => urlencode($current_url)
|
||||
),
|
||||
$redirect_url
|
||||
)
|
||||
);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ if(!defined('ABSPATH')) exit;
|
||||
class Env {
|
||||
public static $version;
|
||||
public static $plugin_name;
|
||||
public static $plugin_url;
|
||||
public static $file;
|
||||
public static $path;
|
||||
public static $views_path;
|
||||
@ -29,9 +30,10 @@ class Env {
|
||||
public static function init($file, $version) {
|
||||
global $wpdb;
|
||||
self::$version = $version;
|
||||
self::$plugin_name = 'mailpoet';
|
||||
self::$file = $file;
|
||||
self::$path = dirname(self::$file);
|
||||
self::$plugin_name = 'mailpoet';
|
||||
self::$plugin_url = plugins_url() . '/' . basename(Env::$path);
|
||||
self::$views_path = self::$path . '/views';
|
||||
self::$assets_path = self::$path . '/assets';
|
||||
self::$assets_url = plugins_url('/assets', $file);
|
||||
|
@ -24,6 +24,7 @@ class Initializer {
|
||||
$this->setupWidget();
|
||||
$this->setupAnalytics();
|
||||
$this->setupPermissions();
|
||||
$this->setupChangelog();
|
||||
}
|
||||
|
||||
function setupDB() {
|
||||
@ -104,4 +105,9 @@ class Initializer {
|
||||
$permissions = new Permissions();
|
||||
$permissions->init();
|
||||
}
|
||||
|
||||
function setupChangelog() {
|
||||
$changelog = new Changelog();
|
||||
$changelog->init();
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class Menu {
|
||||
'MailPoet',
|
||||
'manage_options',
|
||||
'mailpoet',
|
||||
array($this, 'welcome'),
|
||||
array($this, 'home'),
|
||||
$this->assets_url . '/img/menu_icon.png',
|
||||
30
|
||||
);
|
||||
@ -94,31 +94,42 @@ class Menu {
|
||||
'mailpoet-export',
|
||||
array($this, 'export')
|
||||
);
|
||||
// add_submenu_page(
|
||||
// 'mailpoet',
|
||||
// __('Newsletter editor'),
|
||||
// __('Newsletter editor'),
|
||||
// 'manage_options',
|
||||
// 'mailpoet-newsletter-editor',
|
||||
// array($this, 'newletterEditor')
|
||||
// );
|
||||
$this->registered_pages();
|
||||
}
|
||||
|
||||
function registered_pages() {
|
||||
global $_registered_pages;
|
||||
$pages = array(
|
||||
'mailpoet-welcome' => array($this, 'welcome'),
|
||||
'mailpoet-form-editor' => array($this, 'formEditor'),
|
||||
'mailpoet-newsletter-editor' => array($this, 'newletterEditor')
|
||||
add_submenu_page(
|
||||
null,
|
||||
__('Welcome'),
|
||||
__('Welcome'),
|
||||
'manage_options',
|
||||
'mailpoet-welcome',
|
||||
array($this, 'welcome')
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
null,
|
||||
__('Update'),
|
||||
__('Update'),
|
||||
'manage_options',
|
||||
'mailpoet-update',
|
||||
array($this, 'update')
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
null,
|
||||
__('Form editor'),
|
||||
__('Form editor'),
|
||||
'manage_options',
|
||||
'mailpoet-form-editor',
|
||||
array($this, 'formEditor')
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
null,
|
||||
__('Newsletter editor'),
|
||||
__('Newsletter editor'),
|
||||
'manage_options',
|
||||
'mailpoet-newsletter-editor',
|
||||
array($this, 'newletterEditor')
|
||||
);
|
||||
foreach($pages as $menu_slug => $callback) {
|
||||
$hookname = get_plugin_page_hookname($menu_slug, null);
|
||||
if(!empty($hookname)) {
|
||||
add_action($hookname, $callback);
|
||||
}
|
||||
$_registered_pages[$hookname] = true;
|
||||
}
|
||||
}
|
||||
|
||||
function home() {
|
||||
@ -127,12 +138,52 @@ class Menu {
|
||||
}
|
||||
|
||||
function welcome() {
|
||||
global $wp;
|
||||
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
||||
$redirect_url =
|
||||
(!empty($_GET['mailpoet_redirect']))
|
||||
? urldecode($_GET['mailpoet_redirect'])
|
||||
: wp_get_referer();
|
||||
|
||||
if(
|
||||
$redirect_url === $current_url
|
||||
or
|
||||
strpos($redirect_url, 'mailpoet') === false
|
||||
) {
|
||||
$redirect_url = admin_url('admin.php?page=mailpoet');
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'settings' => Setting::getAll(),
|
||||
'current_user' => wp_get_current_user()
|
||||
'current_user' => wp_get_current_user(),
|
||||
'redirect_url' => $redirect_url
|
||||
);
|
||||
echo $this->renderer->render('welcome.html', $data);
|
||||
}
|
||||
|
||||
function update() {
|
||||
global $wp;
|
||||
$current_url = home_url(add_query_arg($wp->query_string, $wp->request));
|
||||
$redirect_url =
|
||||
(!empty($_GET['mailpoet_redirect']))
|
||||
? urldecode($_GET['mailpoet_redirect'])
|
||||
: wp_get_referer();
|
||||
|
||||
if(
|
||||
$redirect_url === $current_url
|
||||
or
|
||||
strpos($redirect_url, 'mailpoet') === false
|
||||
) {
|
||||
$redirect_url = admin_url('admin.php?page=mailpoet');
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'settings' => Setting::getAll(),
|
||||
'current_user' => wp_get_current_user(),
|
||||
'redirect_url' => $redirect_url
|
||||
);
|
||||
|
||||
echo $this->renderer->render('welcome.html', $data);
|
||||
echo $this->renderer->render('update.html', $data);
|
||||
}
|
||||
|
||||
function settings() {
|
||||
|
@ -14,9 +14,17 @@ class Newsletter extends Model {
|
||||
if(is_string($this->deleted_at) && strlen(trim($this->deleted_at)) === 0) {
|
||||
$this->set_expr('deleted_at', 'NULL');
|
||||
}
|
||||
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
function delete() {
|
||||
// delete all relations to segments
|
||||
NewsletterSegment::where('newsletter_id', $this->id)->deleteMany();
|
||||
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
function segments() {
|
||||
return $this->has_many_through(
|
||||
__NAMESPACE__.'\Segment',
|
||||
@ -126,8 +134,8 @@ class Newsletter extends Model {
|
||||
static function createOrUpdate($data = array()) {
|
||||
$newsletter = false;
|
||||
|
||||
if(isset($data['id']) && (int) $data['id'] > 0) {
|
||||
$newsletter = self::findOne((int) $data['id']);
|
||||
if(isset($data['id']) && (int)$data['id'] > 0) {
|
||||
$newsletter = self::findOne((int)$data['id']);
|
||||
}
|
||||
|
||||
if($newsletter === false) {
|
||||
|
@ -17,7 +17,7 @@ class Segment extends Model {
|
||||
function delete() {
|
||||
// delete all relations to subscribers
|
||||
SubscriberSegment::where('segment_id', $this->id)->deleteMany();
|
||||
parent::delete();
|
||||
return parent::delete();
|
||||
}
|
||||
|
||||
function newsletters() {
|
||||
|
@ -28,6 +28,13 @@ class Setting extends Model {
|
||||
}
|
||||
}
|
||||
|
||||
public static function setValue($key, $value) {
|
||||
return Setting::createOrUpdate(array(
|
||||
'name' => $key,
|
||||
'value' => $value
|
||||
));
|
||||
}
|
||||
|
||||
public static function getAll() {
|
||||
$settingsCollection = self::findMany();
|
||||
$settings = array();
|
||||
|
@ -135,20 +135,41 @@ class Subscriber extends Model {
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value END), NULL) as "' . $customField['name'].'"');
|
||||
}
|
||||
$orm = $orm
|
||||
->left_outer_join(
|
||||
->leftOuterJoin(
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE,
|
||||
array(MP_SUBSCRIBERS_TABLE.'.id', '=',
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.subscriber_id'))
|
||||
->left_outer_join(
|
||||
->leftOuterJoin(
|
||||
MP_CUSTOM_FIELDS_TABLE,
|
||||
array(MP_CUSTOM_FIELDS_TABLE.'.id','=',
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.custom_field_id'))
|
||||
->group_by(MP_SUBSCRIBERS_TABLE.'.id');
|
||||
->groupBy(MP_SUBSCRIBERS_TABLE.'.id');
|
||||
return $orm;
|
||||
}
|
||||
|
||||
static function filterWithCustomFieldsForExport($orm) {
|
||||
$orm = $orm->select(MP_SUBSCRIBERS_TABLE.'.*');
|
||||
$customFields = CustomField::findArray();
|
||||
foreach ($customFields as $customField) {
|
||||
$orm = $orm->selectExpr(
|
||||
'CASE WHEN ' .
|
||||
MP_CUSTOM_FIELDS_TABLE . '.id=' . $customField['id'] . ' THEN ' .
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE . '.value END as "' . $customField['name'].'"');
|
||||
}
|
||||
$orm = $orm
|
||||
->leftOuterJoin(
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE,
|
||||
array(MP_SUBSCRIBERS_TABLE.'.id', '=',
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.subscriber_id'))
|
||||
->leftOuterJoin(
|
||||
MP_CUSTOM_FIELDS_TABLE,
|
||||
array(MP_CUSTOM_FIELDS_TABLE.'.id','=',
|
||||
MP_SUBSCRIBER_CUSTOM_FIELD_TABLE.'.custom_field_id'));
|
||||
return $orm;
|
||||
}
|
||||
|
||||
function customFields() {
|
||||
return $this->has_many_through(
|
||||
return $this->hasManyThrough(
|
||||
__NAMESPACE__.'\CustomField',
|
||||
__NAMESPACE__.'\SubscriberCustomField',
|
||||
'subscriber_id',
|
||||
|
@ -50,9 +50,11 @@ class MetaInformationManager {
|
||||
// check if the user specified a label to be displayed before the author's name
|
||||
if(strlen($preceded_by) > 0) {
|
||||
$content = stripslashes($preceded_by) . ' ';
|
||||
} else {
|
||||
$content = '';
|
||||
}
|
||||
|
||||
return join(', ', $categories);
|
||||
return $content . join(', ', $categories);
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ class PostListTransformer {
|
||||
|
||||
function transform($posts) {
|
||||
$results = array();
|
||||
$use_divider = (bool)$this->args['showDivider'];
|
||||
$use_divider = $this->args['showDivider'] === 'true';
|
||||
|
||||
foreach ($posts as $index => $post) {
|
||||
if ($use_divider && $index > 0) {
|
||||
|
@ -22,16 +22,26 @@ class PostTransformer {
|
||||
$content = $content_manager->filterContent($content);
|
||||
|
||||
$structure_transformer = new StructureTransformer();
|
||||
$structure = $structure_transformer->transform($content, (bool)$this->args['imagePadded']);
|
||||
$structure = $structure_transformer->transform($content, $this->args['imagePadded'] === 'true');
|
||||
|
||||
$structure = $this->appendFeaturedImage($post, (bool)$this->args['imagePadded'], $structure);
|
||||
$structure = $this->appendFeaturedImage(
|
||||
$post,
|
||||
$this->args['displayType'],
|
||||
$this->args['imagePadded'] === 'true',
|
||||
$structure
|
||||
);
|
||||
$structure = $this->appendPostTitle($post, $structure);
|
||||
$structure = $this->appendReadMore($post->ID, $structure);
|
||||
|
||||
return $structure;
|
||||
}
|
||||
|
||||
private function appendFeaturedImage($post, $image_padded, $structure) {
|
||||
private function appendFeaturedImage($post, $display_type, $image_padded, $structure) {
|
||||
if ($display_type === 'full') {
|
||||
// No featured images for full posts
|
||||
return $structure;
|
||||
}
|
||||
|
||||
$featured_image = $this->getFeaturedImage(
|
||||
$post->ID,
|
||||
$post->post_title,
|
||||
@ -68,7 +78,7 @@ class PostTransformer {
|
||||
|
||||
return array(
|
||||
'type' => 'image',
|
||||
'link' => '',
|
||||
'link' => get_permalink($post_id),
|
||||
'src' => $image_info[0],
|
||||
'alt' => $alt_text,
|
||||
'padded' => $image_padded,
|
||||
@ -84,6 +94,8 @@ class PostTransformer {
|
||||
}
|
||||
|
||||
private function appendPostTitle($post, $structure) {
|
||||
$title = $this->getPostTitle($post);
|
||||
|
||||
if ($this->args['titlePosition'] === 'inTextBlock') {
|
||||
// Attach title to the first text block
|
||||
$text_block_index = null;
|
||||
@ -94,7 +106,6 @@ class PostTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
$title = $this->getPostTitle($post);
|
||||
if ($text_block_index === null) {
|
||||
$structure[] = array(
|
||||
'type' => 'text',
|
||||
@ -103,6 +114,14 @@ class PostTransformer {
|
||||
} else {
|
||||
$structure[$text_block_index]['text'] = $title . $structure[$text_block_index]['text'];
|
||||
}
|
||||
} elseif ($this->args['titlePosition'] === 'aboveBlock') {
|
||||
array_unshift(
|
||||
$structure,
|
||||
array(
|
||||
'type' => 'text',
|
||||
'text' => $title,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $structure;
|
||||
@ -113,6 +132,15 @@ class PostTransformer {
|
||||
$button = $this->args['readMoreButton'];
|
||||
$button['url'] = get_permalink($post_id);
|
||||
$structure[] = $button;
|
||||
} else {
|
||||
$structure[] = array(
|
||||
'type' => 'text',
|
||||
'text' => sprintf(
|
||||
'<a href="%s">%s</a>',
|
||||
get_permalink($post_id),
|
||||
$this->args['readMoreText']
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $structure;
|
||||
@ -121,7 +149,7 @@ class PostTransformer {
|
||||
private function getPostTitle($post) {
|
||||
$title = $post->post_title;
|
||||
|
||||
if ((bool)$this->args['titleIsLink']) {
|
||||
if ($this->args['titleIsLink'] === 'true') {
|
||||
$title = '<a href="' . get_permalink($post->ID) . '">' . $title . '</a>';
|
||||
}
|
||||
|
||||
|
@ -101,31 +101,51 @@ class Newsletters {
|
||||
));
|
||||
}
|
||||
|
||||
function delete($data = array()) {
|
||||
$newsletter = newsletter::findOne($data['id']);
|
||||
$confirm_delete = filter_var($data['confirm'], FILTER_VALIDATE_BOOLEAN);
|
||||
if($newsletter !== false) {
|
||||
if($confirm_delete) {
|
||||
$newsletter->delete();
|
||||
$result = array('newsletters' => 1);
|
||||
} else {
|
||||
$newsletter->set_expr('deleted_at', 'NOW()');
|
||||
$result = array('newsletters' => (int)$newsletter->save());
|
||||
}
|
||||
} else {
|
||||
function restore($id) {
|
||||
$result = false;
|
||||
|
||||
$newsletter = Newsletter::findOne($id);
|
||||
if($newsletter !== false) {
|
||||
$result = $newsletter->restore();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function restore($id) {
|
||||
function trash($id) {
|
||||
$result = false;
|
||||
|
||||
$newsletter = Newsletter::findOne($id);
|
||||
if($newsletter !== false) {
|
||||
$newsletter->set_expr('deleted_at', 'NULL');
|
||||
$result = array('newsletters' => (int)$newsletter->save());
|
||||
} else {
|
||||
$result = false;
|
||||
$result = $newsletter->trash();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function delete($id) {
|
||||
$result = false;
|
||||
|
||||
$newsletter = Newsletter::findOne($id);
|
||||
if($newsletter !== false) {
|
||||
$newsletter->delete();
|
||||
$result = 1;
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
function duplicate($id) {
|
||||
$result = false;
|
||||
|
||||
$newsletter = Newsletter::findOne($id);
|
||||
if($newsletter !== false) {
|
||||
$data = array(
|
||||
'subject' => sprintf(__('Copy of %s'), $newsletter->subject)
|
||||
);
|
||||
$result = $newsletter->duplicate($data)->asArray();
|
||||
}
|
||||
|
||||
wp_send_json($result);
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,6 @@ class Segments {
|
||||
)
|
||||
->findOne()->asArray();
|
||||
|
||||
!d(\ORM::get_last_query());exit;
|
||||
$item = array_merge($item, $stats);
|
||||
|
||||
$item['subscribers_url'] = admin_url(
|
||||
|
@ -2,11 +2,14 @@
|
||||
namespace MailPoet\Subscribers\ImportExport\Export;
|
||||
|
||||
use MailPoet\Config\Env;
|
||||
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
||||
use MailPoet\Models\CustomField;
|
||||
use MailPoet\Models\Segment;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Models\SubscriberSegment;
|
||||
use MailPoet\Subscribers\ImportExport\BootStrapMenu;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\Util\XLSXWriter;
|
||||
use Symfony\Component\Console\Helper\Helper;
|
||||
|
||||
class Export {
|
||||
public function __construct($data) {
|
||||
@ -16,82 +19,79 @@ class Export {
|
||||
$this->segments = $data['segments'];
|
||||
$this->subscribersWithoutSegment = array_search(0, $this->segments);
|
||||
$this->subscriberFields = $data['subscriberFields'];
|
||||
$this->exportFile = $this->getExportFile($this->exportFormatOption);
|
||||
$this->exportFileURL = $this->getExportFileURL($this->exportFile);
|
||||
$this->profilerStart = microtime(true);
|
||||
$this->exportFile = sprintf(
|
||||
Env::$temp_path . '/mailpoet_export_%s.%s',
|
||||
substr(md5(time()), 0, 4),
|
||||
$this->exportFormatOption
|
||||
);
|
||||
$this->exportFileURL = sprintf(
|
||||
'%s/%s/%s/%s',
|
||||
plugins_url(),
|
||||
Env::$plugin_name,
|
||||
Env::$temp_name,
|
||||
basename($this->exportFile)
|
||||
);
|
||||
}
|
||||
|
||||
function process() {
|
||||
$subscribers = SubscriberSegment::
|
||||
left_outer_join(
|
||||
Subscriber::$_table,
|
||||
array(
|
||||
Subscriber::$_table . '.id',
|
||||
'=',
|
||||
SubscriberSegment::$_table . '.subscriber_id'
|
||||
))
|
||||
->left_outer_join(
|
||||
Segment::$_table,
|
||||
array(
|
||||
Segment::$_table . '.id',
|
||||
'=',
|
||||
SubscriberSegment::$_table . '.segment_id'
|
||||
))
|
||||
->select(Segment::$_table . '.name', 'segment_name')
|
||||
->orderByAsc('segment_name')
|
||||
->filter('filterWithCustomFields')
|
||||
->whereIn(SubscriberSegment::$_table . '.segment_id', $this->segments);
|
||||
if(!$this->groupBySegmentOption) $subscribers = $subscribers->groupBy(Subscriber::$_table . '.id');
|
||||
if($this->exportConfirmedOption) $subscribers = $subscribers->where(Subscriber::$_table . '.status', 'confirmed');
|
||||
$subscribers = $subscribers->findArray();
|
||||
$formattedSubscriberFields = $this->formatSubscriberFields($this->subscriberFields);
|
||||
$subscribers = $this->getSubscribers();
|
||||
$subscriberCustomFields = $this->getSubscriberCustomFields();
|
||||
$formattedSubscriberFields = $this->formatSubscriberFields(
|
||||
$this->subscriberFields,
|
||||
$subscriberCustomFields
|
||||
);
|
||||
try {
|
||||
if($this->exportFormatOption === 'csv') {
|
||||
$CSVFile = fopen($this->exportFile, 'w');
|
||||
$formatCSV = function ($row) {
|
||||
return '"' . str_replace('"', '\"', $row) . '"';
|
||||
};
|
||||
// add UTF-8 BOM (3 bytes, hex EF BB BF) at the start of the file for Excel to automatically recognize the encoding
|
||||
// add UTF-8 BOM (3 bytes, hex EF BB BF) at the start of the file for
|
||||
// Excel to automatically recognize the encoding
|
||||
fwrite($CSVFile, chr(0xEF) . chr(0xBB) . chr(0xBF));
|
||||
if($this->groupBySegmentOption) $formattedSubscriberFields[] = __('List');
|
||||
fwrite($CSVFile, implode(",", array_map($formatCSV, $formattedSubscriberFields)) . "\n");
|
||||
if($this->groupBySegmentOption) {
|
||||
$formattedSubscriberFields[] = __('List');
|
||||
}
|
||||
fwrite(
|
||||
$CSVFile,
|
||||
implode(
|
||||
',',
|
||||
array_map(
|
||||
$formatCSV,
|
||||
$formattedSubscriberFields
|
||||
)
|
||||
) . "\n"
|
||||
);
|
||||
foreach ($subscribers as $subscriber) {
|
||||
$row = array_map(function ($field) use ($subscriber) {
|
||||
return $subscriber[$field];
|
||||
}, $this->subscriberFields);
|
||||
if($this->groupBySegmentOption) $row[] = $subscriber['segment_name'];
|
||||
fwrite($CSVFile, implode(",", array_map($formatCSV, $row)) . "\n");
|
||||
$row = $this->formatSubscriberData(
|
||||
$subscriber,
|
||||
$formattedSubscriberFields
|
||||
);
|
||||
if($this->groupBySegmentOption) {
|
||||
$row[] = ucwords($subscriber['segment_name']);
|
||||
}
|
||||
fwrite($CSVFile, implode(',', array_map($formatCSV, $row)) . "\n");
|
||||
}
|
||||
fclose($CSVFile);
|
||||
} else {
|
||||
$writer = new XLSXWriter();
|
||||
$writer->setAuthor('MailPoet (www.mailpoet.com)');
|
||||
$headerRow = array($formattedSubscriberFields);
|
||||
$segment = null;
|
||||
$lastSegment = false;
|
||||
$rows = array();
|
||||
foreach ($subscribers as $subscriber) {
|
||||
if($segment && $segment != $subscriber['segment_name'] && $this->groupBySegmentOption) {
|
||||
$writer->writeSheet(array_merge($headerRow, $rows), ucwords($segment));
|
||||
if($lastSegment && $lastSegment !== $subscriber['segment_name'] &&
|
||||
$this->groupBySegmentOption
|
||||
) {
|
||||
$writer->writeSheet(
|
||||
array_merge($headerRow, $rows), ucwords($lastSegment)
|
||||
);
|
||||
$rows = array();
|
||||
}
|
||||
// detect RTL language and set Excel to properly display the sheet
|
||||
if(!$writer->rtl && preg_grep('/\p{Arabic}|\p{Hebrew}/u', $subscriber)) {
|
||||
$RTLRegex = '/\p{Arabic}|\p{Hebrew}/u';
|
||||
if(!$writer->rtl && (
|
||||
preg_grep($RTLRegex, $subscriber) ||
|
||||
preg_grep($RTLRegex, $formattedSubscriberFields))
|
||||
) {
|
||||
$writer->rtl = true;
|
||||
}
|
||||
$rows[] = array_map(function ($field) use ($subscriber) {
|
||||
return $subscriber[$field];
|
||||
}, $this->subscriberFields);
|
||||
$segment = $subscriber['segment_name'];
|
||||
$rows[] = $this->formatSubscriberData(
|
||||
$subscriber,
|
||||
$formattedSubscriberFields
|
||||
);
|
||||
$lastSegment = $subscriber['segment_name'];
|
||||
}
|
||||
$writer->writeSheet(array_merge($headerRow, $rows), 'MailPoet');
|
||||
$writer->writeToFile($this->exportFile);
|
||||
@ -107,20 +107,106 @@ class Export {
|
||||
'data' => array(
|
||||
'totalExported' => count($subscribers),
|
||||
'exportFileURL' => $this->exportFileURL
|
||||
)
|
||||
),
|
||||
'profiler' => $this->timeExecution()
|
||||
);
|
||||
}
|
||||
|
||||
function formatSubscriberFields($subscriberFields) {
|
||||
function getSubscribers() {
|
||||
$subscribers = Subscriber::
|
||||
left_outer_join(
|
||||
SubscriberSegment::$_table,
|
||||
array(
|
||||
Subscriber::$_table . '.id',
|
||||
'=',
|
||||
SubscriberSegment::$_table . '.subscriber_id'
|
||||
))
|
||||
->left_outer_join(
|
||||
Segment::$_table,
|
||||
array(
|
||||
Segment::$_table . '.id',
|
||||
'=',
|
||||
SubscriberSegment::$_table . '.segment_id'
|
||||
))
|
||||
->orderByAsc('segment_name')
|
||||
->filter('filterWithCustomFieldsForExport');
|
||||
if($this->subscribersWithoutSegment !== false) {
|
||||
$subscribers = $subscribers
|
||||
->selectExpr('CASE WHEN ' . Segment::$_table . '.name IS NOT NULL ' .
|
||||
'THEN ' . Segment::$_table . '.name ' .
|
||||
'ELSE "' . __('Not In List') . '" END as segment_name'
|
||||
)
|
||||
->whereRaw(
|
||||
SubscriberSegment::$_table . '.segment_id IN (' .
|
||||
rtrim(str_repeat('?,', count($this->segments)), ',') . ') ' .
|
||||
'OR ' . SubscriberSegment::$_table . '.segment_id IS NULL ',
|
||||
$this->segments
|
||||
);
|
||||
} else {
|
||||
$subscribers = $subscribers
|
||||
->select(Segment::$_table . '.name', 'segment_name')
|
||||
->whereIn(SubscriberSegment::$_table . '.segment_id', $this->segments);
|
||||
}
|
||||
if(!$this->groupBySegmentOption) {
|
||||
$subscribers =
|
||||
$subscribers->groupBy(Subscriber::$_table . '.id');
|
||||
}
|
||||
if($this->exportConfirmedOption) {
|
||||
$subscribers =
|
||||
$subscribers->where(Subscriber::$_table . '.status', 'subscribed');
|
||||
}
|
||||
return $subscribers->findArray();
|
||||
}
|
||||
|
||||
function getExportFileURL($file) {
|
||||
return sprintf(
|
||||
'%s/%s/%s',
|
||||
Env::$plugin_url,
|
||||
Env::$temp_name,
|
||||
basename($file)
|
||||
);
|
||||
}
|
||||
|
||||
function getExportFile($format) {
|
||||
return sprintf(
|
||||
Env::$temp_path . '/MailPoet_export_%s.%s',
|
||||
substr(md5(time()), 0, 4),
|
||||
$format
|
||||
);
|
||||
}
|
||||
|
||||
function getSubscriberCustomFields() {
|
||||
return Helpers::arrayColumn(
|
||||
CustomField::findArray(),
|
||||
'name',
|
||||
'id'
|
||||
);
|
||||
}
|
||||
|
||||
function formatSubscriberFields($subscriberFields, $subscriberCustomFields) {
|
||||
$bootStrapMenu = new BootStrapMenu();
|
||||
$translatedFields = $bootStrapMenu->getSubscriberFields();
|
||||
return array_map(function ($field) use ($translatedFields) {
|
||||
return (isset($translatedFields[$field])) ?
|
||||
return array_map(function ($field) use (
|
||||
$translatedFields, $subscriberCustomFields
|
||||
) {
|
||||
$field = (isset($translatedFields[$field])) ?
|
||||
ucfirst($translatedFields[$field]) :
|
||||
ucfirst($field);
|
||||
return (isset($subscriberCustomFields[$field])) ?
|
||||
$subscriberCustomFields[$field] : $field;
|
||||
}, $subscriberFields);
|
||||
}
|
||||
|
||||
function formatSubscriberData($subscriber, $subscriberCustomFields) {
|
||||
return array_map(function ($field) use (
|
||||
$subscriber, $subscriberCustomFields
|
||||
) {
|
||||
return (isset($subscriberCustomFields[$field])) ?
|
||||
$subscriberCustomFields[$field] :
|
||||
$subscriber[$field];
|
||||
}, $this->subscriberFields);
|
||||
}
|
||||
|
||||
function timeExecution() {
|
||||
$profilerEnd = microtime(true);
|
||||
return ($profilerEnd - $this->profilerStart) / 60;
|
||||
|
@ -75,7 +75,7 @@ class Import {
|
||||
'updated' => count($updatedSubscribers),
|
||||
'segments' => $segments->getSegments()
|
||||
),
|
||||
'profile' => $this->timeExecution()
|
||||
'profiler' => $this->timeExecution()
|
||||
);
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ class Import {
|
||||
}
|
||||
|
||||
function filterSubscriberStatus($subscribersData) {
|
||||
if(!in_array('status', $this->subscriberFields)) return;
|
||||
if(!in_array('status', $this->subscriberFields)) return $subscribersData;
|
||||
$statuses = array(
|
||||
'subscribed' => array(
|
||||
'subscribed',
|
||||
@ -174,6 +174,11 @@ class Import {
|
||||
'1',
|
||||
'true'
|
||||
),
|
||||
'unconfirmed' => array(
|
||||
'unconfirmed',
|
||||
0,
|
||||
"0"
|
||||
),
|
||||
'unsubscribed' => array(
|
||||
'unsubscribed',
|
||||
-1,
|
||||
@ -183,12 +188,15 @@ class Import {
|
||||
);
|
||||
$subscribersData['status'] = array_map(function ($state) use ($statuses) {
|
||||
if(in_array(strtolower($state), $statuses['subscribed'])) {
|
||||
return 'confirmed';
|
||||
return 'subscribed';
|
||||
}
|
||||
if(in_array(strtolower($state), $statuses['unsubscribed'])) {
|
||||
return 'unsubscribed';
|
||||
}
|
||||
return 'confirmed'; // make "subscribed" a default status
|
||||
if(in_array(strtolower($state), $statuses['unconfirmed'])) {
|
||||
return 'unconfirmed';
|
||||
}
|
||||
return 'subscribed'; // make "subscribed" a default status
|
||||
}, $subscribersData['status']);
|
||||
return $subscribersData;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ if (!defined('ABSPATH')) exit;
|
||||
|
||||
/*
|
||||
* Plugin Name: MailPoet
|
||||
* Version: 0.0.4
|
||||
* Version: 0.0.5
|
||||
* Plugin URI: http://www.mailpoet.com
|
||||
* Description: MailPoet Newsletters.
|
||||
* Author: MailPoet
|
||||
@ -18,12 +18,12 @@ if (!defined('ABSPATH')) exit;
|
||||
*
|
||||
* @package WordPress
|
||||
* @author MailPoet
|
||||
* @since 0.0.4
|
||||
* @since 0.0.5
|
||||
*/
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
define('MAILPOET_VERSION', '0.0.4');
|
||||
define('MAILPOET_VERSION', '0.0.5');
|
||||
|
||||
$initializer = new Initializer(array(
|
||||
'file' => __FILE__,
|
||||
|
@ -5,8 +5,7 @@
|
||||
},
|
||||
"napa": {
|
||||
"blob": "eligrey/Blob.js.git",
|
||||
"filesaver": "eligrey/FileSaver.js.git",
|
||||
"sticky-kit": "leafo/sticky-kit.git"
|
||||
"filesaver": "eligrey/FileSaver.js.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"backbone": "1.2.3",
|
||||
|
@ -1,7 +1,7 @@
|
||||
define([
|
||||
'newsletter_editor/App',
|
||||
'newsletter_editor/components/wordpress',
|
||||
'newsletter_editor/blocks/posts',
|
||||
'newsletter_editor/blocks/posts'
|
||||
], function(EditorApplication, WordpressComponent, PostsBlock) {
|
||||
|
||||
describe('Posts', function () {
|
||||
@ -373,12 +373,7 @@ define([
|
||||
});
|
||||
|
||||
describe('when "title as list" is selected', function() {
|
||||
var model, view;
|
||||
beforeEach(function() {
|
||||
model = new (PostsBlock.PostsBlockModel)();
|
||||
model.request = sinon.stub().returns({$el: {}});
|
||||
view = new (PostsBlock.PostsBlockSettingsView)({model: model});
|
||||
view.render();
|
||||
view.$('.mailpoet_posts_display_type').val('titleOnly').change();
|
||||
view.$('.mailpoet_posts_title_format').val('ul').change();
|
||||
});
|
||||
|
@ -1,23 +1,237 @@
|
||||
<?php
|
||||
|
||||
use MailPoet\Subscribers\ImportExport\Export;
|
||||
use MailPoet\Config\Env;
|
||||
use MailPoet\Models\CustomField;
|
||||
use MailPoet\Models\Segment;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Models\SubscriberCustomField;
|
||||
use MailPoet\Models\SubscriberSegment;
|
||||
use MailPoet\Subscribers\ImportExport\Export\Export;
|
||||
|
||||
class ExportCest {
|
||||
function __construct() {
|
||||
function _before() {
|
||||
$this->JSONdata = json_decode(file_get_contents(dirname(__FILE__) . '/ExportTestData.json'), true);
|
||||
$this->subscriberFields = array(
|
||||
'first_name' => 'First name',
|
||||
'last_name' => 'Last name',
|
||||
'email' => 'Email',
|
||||
1 => 'Country'
|
||||
);
|
||||
|
||||
$this->subscribersData = array(
|
||||
array(
|
||||
'first_name' => 'Adam',
|
||||
'last_name' => 'Smith',
|
||||
'email' => 'adam@smith.com'
|
||||
),
|
||||
array(
|
||||
'first_name' => 'Mary',
|
||||
'last_name' => 'Jane',
|
||||
'email' => 'mary@jane.com',
|
||||
'status' => 'subscribed',
|
||||
1 => 'Brazil'
|
||||
),
|
||||
array(
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Kookoo',
|
||||
'email' => 'john@kookoo.com'
|
||||
),
|
||||
array(
|
||||
'first_name' => 'Paul',
|
||||
'last_name' => 'Newman',
|
||||
'email' => 'paul@newman.com'
|
||||
)
|
||||
);
|
||||
$this->customFieldsData = array(
|
||||
array(
|
||||
'name' => 'Country',
|
||||
'type' => 'text'
|
||||
)
|
||||
);
|
||||
$this->segmentsData = array(
|
||||
array(
|
||||
'name' => 'Newspapers'
|
||||
),
|
||||
array(
|
||||
'name' => 'Journals'
|
||||
)
|
||||
);
|
||||
foreach ($this->subscribersData as $subscriber) {
|
||||
if(isset($subscriber[1])) {
|
||||
unset($subscriber[1]);
|
||||
}
|
||||
$entity = Subscriber::create();
|
||||
$entity->hydrate($subscriber);
|
||||
$entity->save();
|
||||
}
|
||||
foreach ($this->segmentsData as $customField) {
|
||||
$entity = Segment::create();
|
||||
$entity->hydrate($customField);
|
||||
$entity->save();
|
||||
}
|
||||
foreach ($this->customFieldsData as $customField) {
|
||||
$entity = CustomField::create();
|
||||
$entity->hydrate($customField);
|
||||
$entity->save();
|
||||
}
|
||||
$entity = SubscriberCustomField::create();
|
||||
$entity->subscriber_id = 2;
|
||||
$entity->custom_field_id = 1;
|
||||
$entity->value = $this->subscribersData[1][1];
|
||||
$entity->save();
|
||||
$entity = SubscriberSegment::create();
|
||||
$entity->subscriber_id = 1;
|
||||
$entity->segment_id = 1;
|
||||
$entity->save();
|
||||
$entity = SubscriberSegment::create();
|
||||
$entity->subscriber_id = 1;
|
||||
$entity->segment_id = 2;
|
||||
$entity->save();
|
||||
$entity = SubscriberSegment::create();
|
||||
$entity->subscriber_id = 2;
|
||||
$entity->segment_id = 1;
|
||||
$entity->save();
|
||||
$entity = SubscriberSegment::create();
|
||||
$entity->subscriber_id = 3;
|
||||
$entity->segment_id = 2;
|
||||
$entity->save();
|
||||
$this->export = new Export($this->JSONdata);
|
||||
}
|
||||
|
||||
function itCanConstruct() {
|
||||
expect($this->export->exportConfirmedOption)
|
||||
->equals(false);
|
||||
expect($this->export->exportFormatOption)
|
||||
->equals('csv');
|
||||
expect($this->export->groupBySegmentOption)
|
||||
->equals(false);
|
||||
expect($this->export->segments)
|
||||
->equals(
|
||||
array(
|
||||
1,
|
||||
2
|
||||
)
|
||||
);
|
||||
expect($this->export->subscribersWithoutSegment)
|
||||
->equals(0);
|
||||
expect($this->export->subscriberFields)
|
||||
->equals(
|
||||
array(
|
||||
'email',
|
||||
'first_name',
|
||||
'1'
|
||||
)
|
||||
);
|
||||
expect(
|
||||
preg_match(
|
||||
'|' .
|
||||
Env::$temp_path . '/MailPoet_export_[a-f0-9]{4}.' .
|
||||
$this->export->exportFormatOption .
|
||||
'|', $this->export->exportFile)
|
||||
)->equals(1);
|
||||
expect(
|
||||
preg_match(
|
||||
'|' .
|
||||
Env::$plugin_url . '/' .
|
||||
Env::$temp_name . '/' .
|
||||
basename($this->export->exportFile) .
|
||||
'|'
|
||||
, $this->export->exportFileURL)
|
||||
)->equals(1);
|
||||
}
|
||||
|
||||
function itCanGetSubscriberCustomFields() {
|
||||
$source = CustomField::where('name', $this->customFieldsData[0]['name'])
|
||||
->findOne();
|
||||
$target = $this->export->getSubscriberCustomFields();
|
||||
expect($target)->equals(array($source->id => $source->name));
|
||||
}
|
||||
|
||||
function itCanFormatSubscriberFields() {
|
||||
$formattedSubscriberFields = $this->export->formatSubscriberFields(
|
||||
array_keys($this->subscriberFields),
|
||||
$this->export->getSubscriberCustomFields()
|
||||
);
|
||||
expect($formattedSubscriberFields)
|
||||
->equals(array_values($this->subscriberFields));
|
||||
}
|
||||
|
||||
function itProperlyReturnsSubscriberCustomFields() {
|
||||
$subscribers = $this->export->getSubscribers();
|
||||
foreach ($subscribers as $subscriber) {
|
||||
if($subscriber['email'] === $this->subscribersData[1]) {
|
||||
expect($subscriber['Country'])
|
||||
->equals($this->subscribersData[1][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function itCanGetSubscribers() {
|
||||
$this->export->segments = array(1);
|
||||
$subscribers = $this->export->getSubscribers();
|
||||
expect(count($subscribers))->equals(2);
|
||||
$this->export->segments = array(2);
|
||||
$subscribers = $this->export->getSubscribers();
|
||||
expect(count($subscribers))->equals(2);
|
||||
$this->export->segments = array(
|
||||
1,
|
||||
2
|
||||
);
|
||||
$subscribers = $this->export->getSubscribers();
|
||||
expect(count($subscribers))->equals(3);
|
||||
}
|
||||
|
||||
function itCanGroupSubscribersBySegments() {
|
||||
$this->export->groupBySegmentOption = true;
|
||||
$this->export->subscribersWithoutSegment = true;
|
||||
$subscribers = $this->export->getSubscribers();
|
||||
expect(count($subscribers))->equals(5);
|
||||
}
|
||||
|
||||
function itCanGetSubscribersOnlyWithoutSegments() {
|
||||
$this->export->segments = array(0);
|
||||
$this->export->subscribersWithoutSegment = true;
|
||||
$subscribers = $this->export->getSubscribers();
|
||||
expect(count($subscribers))->equals(1);
|
||||
expect($subscribers[0]['segment_name'])->equals('Not In List');
|
||||
}
|
||||
|
||||
function itCanGetOnlyConfirmedSubscribers() {
|
||||
$this->export->exportConfirmedOption = true;
|
||||
$subscribers = $this->export->getSubscribers();
|
||||
expect(count($subscribers))->equals(1);
|
||||
expect($subscribers[0]['email'])
|
||||
->equals($this->subscribersData[1]['email']);
|
||||
}
|
||||
|
||||
function itCanGetSubscribersOnlyInSegments() {
|
||||
SubscriberSegment::where('subscriber_id', 3)
|
||||
->findOne()
|
||||
->delete();
|
||||
$subscribers = $this->export->getSubscribers();
|
||||
expect(count($subscribers))->equals(2);
|
||||
}
|
||||
|
||||
function itCanProcess() {
|
||||
$this->export->exportFile = $this->export->getExportFile('csv');
|
||||
$this->export->exportFormatOption = 'csv';
|
||||
$this->export->process();
|
||||
$CSVFileSize = filesize($this->export->exportFile);
|
||||
$this->export->exportFile = $this->export->getExportFile('xls');
|
||||
$this->export->exportFormatOption = 'xls';
|
||||
$this->export->process();
|
||||
$XLSFileSize = filesize($this->export->exportFile);
|
||||
expect($CSVFileSize)->greaterThan(0);
|
||||
expect($XLSFileSize)->greaterThan(0);
|
||||
expect($XLSFileSize)->greaterThan($CSVFileSize);
|
||||
|
||||
}
|
||||
|
||||
function _after() {
|
||||
ORM::forTable(Subscriber::$_table)
|
||||
->deleteMany();
|
||||
ORM::forTable(SubscriberCustomField::$_table)
|
||||
->deleteMany();
|
||||
ORM::forTable(SubscriberSegment::$_table)
|
||||
->deleteMany();
|
||||
ORM::raw_execute('TRUNCATE ' . Subscriber::$_table);
|
||||
ORM::raw_execute('TRUNCATE ' . Segment::$_table);
|
||||
ORM::raw_execute('TRUNCATE ' . SubscriberSegment::$_table);
|
||||
ORM::raw_execute('TRUNCATE ' . CustomField::$_table);
|
||||
ORM::raw_execute('TRUNCATE ' . SubscriberCustomField::$_table);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"exportConfirmedOption": false,
|
||||
"exportFormatOption": "csv",
|
||||
"groupBySegmentOption": false,
|
||||
"segments": [
|
||||
"1",
|
||||
"2"
|
||||
],
|
||||
"subscriberFields": [
|
||||
"email",
|
||||
"first_name",
|
||||
"1"
|
||||
]
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
use MailPoet\Subscribers\ImportExport\Import\Import;
|
||||
use MailPoet\Models\Subscriber;
|
||||
use MailPoet\Models\SubscriberCustomField;
|
||||
use MailPoet\Models\SubscriberSegment;
|
||||
use MailPoet\Subscribers\ImportExport\Import\Import;
|
||||
use MailPoet\Util\Helpers;
|
||||
|
||||
class ImportCest {
|
||||
@ -108,38 +108,39 @@ class ImportCest {
|
||||
function itCanFilterSubscriberState() {
|
||||
$data = array(
|
||||
'status' => array(
|
||||
'confirmed',
|
||||
'subscribed',
|
||||
//subscribed
|
||||
'subscribed',
|
||||
'confirmed',
|
||||
1,
|
||||
'1',
|
||||
'true',
|
||||
//unconfirmed
|
||||
'unconfirmed',
|
||||
0,
|
||||
"0",
|
||||
//unsubscribed
|
||||
'unsubscribed',
|
||||
-1,
|
||||
'-1',
|
||||
'false',
|
||||
'something',
|
||||
'else'
|
||||
'false'
|
||||
),
|
||||
);
|
||||
$statuses = $this->import->filterSubscriberStatus($data);
|
||||
expect($statuses)->equals(
|
||||
array(
|
||||
'status' => array(
|
||||
'confirmed',
|
||||
'confirmed',
|
||||
'confirmed',
|
||||
'confirmed',
|
||||
'confirmed',
|
||||
'confirmed',
|
||||
'confirmed',
|
||||
'subscribed',
|
||||
'subscribed',
|
||||
'subscribed',
|
||||
'subscribed',
|
||||
'subscribed',
|
||||
'unconfirmed',
|
||||
'unconfirmed',
|
||||
'unconfirmed',
|
||||
'unsubscribed',
|
||||
'unsubscribed',
|
||||
'unsubscribed',
|
||||
'unsubscribed',
|
||||
'confirmed',
|
||||
'confirmed'
|
||||
'unsubscribed'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"subscribers":{
|
||||
"39":[
|
||||
"subscribers": {
|
||||
"39": [
|
||||
"United States",
|
||||
"China",
|
||||
"Colombia",
|
||||
@ -999,7 +999,7 @@
|
||||
"China",
|
||||
"China"
|
||||
],
|
||||
"first_name":[
|
||||
"first_name": [
|
||||
"Rose",
|
||||
"Samuel",
|
||||
"Louis",
|
||||
@ -1998,7 +1998,7 @@
|
||||
"Lillian",
|
||||
"Ryan"
|
||||
],
|
||||
"last_name":[
|
||||
"last_name": [
|
||||
"Hansen",
|
||||
"Hall",
|
||||
"Freeman",
|
||||
@ -2997,7 +2997,7 @@
|
||||
"Clark",
|
||||
"Russell"
|
||||
],
|
||||
"email":[
|
||||
"email": [
|
||||
"rhansen0@stanford.edu",
|
||||
"shall1@zdnet.com",
|
||||
"lfreeman2@gmpg.org",
|
||||
@ -3996,7 +3996,7 @@
|
||||
"lclarkrq@xinhuanet.com",
|
||||
"rrussellrr@bloomberg.com"
|
||||
],
|
||||
"status":[
|
||||
"status": [
|
||||
"unsubscribed",
|
||||
"confirmed",
|
||||
"subscribed",
|
||||
@ -4996,8 +4996,8 @@
|
||||
"confirmed"
|
||||
]
|
||||
},
|
||||
"segments":[
|
||||
"segments": [
|
||||
"195"
|
||||
],
|
||||
"updateSubscribers":true
|
||||
"updateSubscribers": true
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<div class="mailpoet_tools"></div>
|
||||
<div class="mailpoet_content">
|
||||
<div class="mailpoet_automated_latest_content_block_overlay"></div>
|
||||
<div class="mailpoet_automated_latest_content_block_overlay"></div>
|
||||
<div class="mailpoet_automated_latest_content_block_posts"></div>
|
||||
</div>
|
||||
<div class="mailpoet_block_highlight"></div>
|
||||
|
@ -37,7 +37,16 @@
|
||||
|
||||
<hr class="mailpoet_separator" />
|
||||
|
||||
|
||||
<div class="mailpoet_form_field">
|
||||
<a href="javascript:;" class="mailpoet_automated_latest_content_show_display_options"><%= __('Display options') %></a>
|
||||
</div>
|
||||
<div class="mailpoet_automated_latest_content_display_options mailpoet_hidden">
|
||||
<div class="mailpoet_form_field">
|
||||
<a href="javascript:;" class="mailpoet_automated_latest_content_hide_display_options"><%= __('Hide display options') %></a>
|
||||
</div>
|
||||
|
||||
<div class="mailpoet_form_field">
|
||||
<div class="mailpoet_form_field_radio_option">
|
||||
<label>
|
||||
<input type="radio" name="mailpoet_automated_latest_content_display_type" class="mailpoet_automated_latest_content_display_type" value="excerpt" {{#ifCond model.displayType '==' 'excerpt'}}CHECKED{{/ifCond}}/>
|
||||
@ -56,14 +65,6 @@
|
||||
<%= __('Title only') %>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mailpoet_form_field">
|
||||
<a href="javascript:;" class="mailpoet_automated_latest_content_show_display_options"><%= __('Display options') %></a>
|
||||
</div>
|
||||
<div class="mailpoet_automated_latest_content_display_options mailpoet_hidden">
|
||||
<div class="mailpoet_form_field">
|
||||
<a href="javascript:;" class="mailpoet_automated_latest_content_hide_display_options"><%= __('Hide display options') %></a>
|
||||
</div>
|
||||
|
||||
<div class="mailpoet_form_field">
|
||||
@ -215,7 +216,7 @@
|
||||
<%= __('Below text') %>
|
||||
</label>
|
||||
</div>
|
||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_small mailpoet_form_field_title_inline"><%= __('Categories:') %></div>
|
||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_small mailpoet_form_field_title_inline"><%= __('Preceded by:') %></div>
|
||||
<div class="mailpoet_form_field_input_option">
|
||||
<input type="text" class="mailpoet_input mailpoet_input_medium mailpoet_automated_latest_content_categories" value="{{ model.categoriesPrecededBy }}" />
|
||||
</div>
|
||||
@ -251,7 +252,7 @@
|
||||
</div>
|
||||
|
||||
<div class="mailpoet_form_field">
|
||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_small mailpoet_form_field_title_inline"><%= __('Sort by') %></div>
|
||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_small"><%= __('Sort by') %></div>
|
||||
<div class="mailpoet_form_field_radio_option">
|
||||
<label>
|
||||
<input type="radio" name="mailpoet_automated_latest_content_sort_by" class="mailpoet_automated_latest_content_sort_by" value="newest" {{#ifCond model.sortBy '==' 'newest'}}CHECKED{{/ifCond}}/>
|
||||
@ -268,7 +269,7 @@
|
||||
|
||||
<div class="mailpoet_automated_latest_content_non_title_list_options {{#ifCond model.displayType '==' 'titleOnly'}}{{#ifCond model.titleFormat '==' 'ul'}}mailpoet_hidden{{/ifCond}}{{/ifCond}}">
|
||||
<div class="mailpoet_form_field">
|
||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_small mailpoet_form_field_title_inline"><%= __('Show divider between posts') %></div>
|
||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_small"><%= __('Show divider between posts') %></div>
|
||||
<div class="mailpoet_form_field_radio_option">
|
||||
<label>
|
||||
<input type="radio" name="mailpoet_automated_latest_content_show_divider"class="mailpoet_automated_latest_content_show_divider" value="true" {{#if model.showDivider}}CHECKED{{/if}}/>
|
||||
@ -281,7 +282,7 @@
|
||||
<%= __('No') %>
|
||||
</label>
|
||||
</div>
|
||||
<div class="mailpoet_form_field_input_option">
|
||||
<div>
|
||||
<a href="javascript:;" class="mailpoet_automated_latest_content_select_divider"><%= __('Select divider') %></a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -20,6 +20,7 @@
|
||||
{{/ifCond}}
|
||||
|
||||
<div class="mailpoet_form_field">
|
||||
<div class="mailpoet_form_field_title"><%= __('Alignment') %></div>
|
||||
<div class="mailpoet_form_field_radio_option">
|
||||
<label>
|
||||
<input type="radio" name="alignment" class="mailpoet_field_button_alignment" value="left" {{#ifCond model.styles.block.textAlign '===' 'left'}}CHECKED{{/ifCond}}/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div class="mailpoet_tools"></div>
|
||||
<div class="mailpoet_content">
|
||||
<%= __('Your posts will be inserted here') %>
|
||||
<div class="mailpoet_posts_block_posts"></div>
|
||||
</div>
|
||||
<div class="mailpoet_block_highlight"></div>
|
||||
|
@ -2,7 +2,9 @@
|
||||
<div class="mailpoet_settings_posts_selection"></div>
|
||||
<div class="mailpoet_settings_posts_display_options mailpoet_hidden"></div>
|
||||
<div class="mailpoet_settings_posts_controls">
|
||||
<input type="button" class="mailpoet_button mailpoet_button_primary mailpoet_settings_posts_insert_selected" value="<%= __('Insert selected') %>" />
|
||||
<div class="mailpoet_form_field">
|
||||
<a href="javascript:;" class="mailpoet_settings_posts_show_post_selection mailpoet_hidden"><%= __('Back to selection') %></a>
|
||||
<a href="javascript:;" class="mailpoet_settings_posts_show_display_options"><%= __('Display options') %></a>
|
||||
</div>
|
||||
<input type="button" class="mailpoet_button mailpoet_button_primary mailpoet_settings_posts_insert_selected" value="<%= __('Insert selected') %>" />
|
||||
</div>
|
||||
|
@ -170,7 +170,7 @@
|
||||
<%= __('Below text') %>
|
||||
</label>
|
||||
</div>
|
||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_small mailpoet_form_field_title_inline"><%= __('Categories:') %></div>
|
||||
<div class="mailpoet_form_field_title mailpoet_form_field_title_small mailpoet_form_field_title_inline"><%= __('Preceded by:') %></div>
|
||||
<div class="mailpoet_form_field_input_option">
|
||||
<input type="text" class="mailpoet_input mailpoet_input_medium mailpoet_posts_categories" value="{{ model.categoriesPrecededBy }}" />
|
||||
</div>
|
||||
|
@ -13,6 +13,9 @@
|
||||
<option value="pending"><%= __('Pending Review') %></option>
|
||||
<option value="private"><%= __('Private') %></option>
|
||||
</select></div>
|
||||
<div class="mailpoet_post_selection_filter_row">
|
||||
<div class="mailpoet_form_field_title"><%= __('Categories & tags:') %></div>
|
||||
</div>
|
||||
<div class="mailpoet_post_selection_filter_row">
|
||||
<select class="mailpoet_select mailpoet_posts_categories_and_tags" multiple="multiple">
|
||||
{{#each terms}}
|
||||
|
@ -7,7 +7,11 @@
|
||||
'pageTitle': __('Newsletters'),
|
||||
'searchLabel': __('Search'),
|
||||
'loadingItems': __('Loading newsletters...'),
|
||||
'noItemsFound': __('No newsletters found.')
|
||||
'noItemsFound': __('No newsletters found.'),
|
||||
'selectAllLabel': __('All newsletters on this page are selected.'),
|
||||
'selectedAllLabel': __('All %d newsletters are selected.'),
|
||||
'selectAllLink': __('Select all pages.'),
|
||||
'clearSelection': __('Clear selection.')
|
||||
}) %>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
24
views/update.html
Normal file
24
views/update.html
Normal file
@ -0,0 +1,24 @@
|
||||
<% extends 'layout.html' %>
|
||||
|
||||
<% block content %>
|
||||
<div id="mailpoet_update">
|
||||
<h2><%= __("What's new?") %></h2>
|
||||
|
||||
<p>Plugin version: <strong><%= settings.version %></strong></p>
|
||||
|
||||
<p>
|
||||
Current user:
|
||||
<strong><%= current_user.user_nicename %></strong>
|
||||
<<a href="mailto:<%= current_user.user_email %>">
|
||||
<%=- current_user.user_email -%>
|
||||
</a>>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a
|
||||
class="button button-primary"
|
||||
href="<%= redirect_url %>"
|
||||
>Take me to MailPoet</a>
|
||||
</p>
|
||||
</div>
|
||||
<% endblock %>
|
@ -2,12 +2,23 @@
|
||||
|
||||
<% block content %>
|
||||
<div id="mailpoet_welcome">
|
||||
<h2><%= __('Welcome welcome welcome!') %></h2>
|
||||
<h2><%= __('Welcome!') %></h2>
|
||||
|
||||
<h3>Settings:</h3>
|
||||
<%= dump(settings) %>
|
||||
<p>Plugin version: <strong><%= settings.version %></strong></p>
|
||||
|
||||
<h3>Current user:</h3>
|
||||
<%= dump(current_user) %>
|
||||
<p>
|
||||
Current user:
|
||||
<strong><%= current_user.user_nicename %></strong>
|
||||
<<a href="mailto:<%= current_user.user_email %>">
|
||||
<%=- current_user.user_email -%>
|
||||
</a>>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a
|
||||
class="button button-primary"
|
||||
href="<%= redirect_url %>"
|
||||
>Take me to MailPoet</a>
|
||||
</p>
|
||||
</div>
|
||||
<% endblock %>
|
||||
|
@ -23,7 +23,7 @@ baseConfig = {
|
||||
'handlebars': 'handlebars/dist/handlebars.js',
|
||||
'backbone.marionette': 'backbone.marionette/lib/backbone.marionette',
|
||||
'backbone.supermodel$': 'backbone.supermodel/build/backbone.supermodel.js',
|
||||
'sticky-kit': 'sticky-kit/jquery.sticky-kit',
|
||||
'sticky-kit': 'vendor_static/jquery.sticky-kit.js',
|
||||
'interact$': 'interact.js/interact.js',
|
||||
'spectrum$': 'spectrum-colorpicker/spectrum.js',
|
||||
'blob$': 'blob/Blob.js',
|
||||
@ -166,9 +166,6 @@ config.push(_.extend({}, baseConfig, {
|
||||
'public.js'
|
||||
]
|
||||
},
|
||||
/*plugins: [
|
||||
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'),
|
||||
],*/
|
||||
externals: {
|
||||
'jquery': 'jQuery'
|
||||
}
|
||||
|
Reference in New Issue
Block a user