Compare commits

...

17 Commits
3.9.1 ... 3.10

Author SHA1 Message Date
8ff02878e2 Release MP3 3.10 2018-09-11 15:29:02 +03:00
82a4681cd6 Merge pull request #1492 from mailpoet/translations-load
Rename global translations file [MAILPOET-1520]
2018-09-10 13:27:34 -04:00
7035d92815 Merge pull request #1491 from mailpoet/welcome-emails
Move welcome emails to free plugin [MAILPOET-1518]
2018-09-07 12:17:37 -04:00
cc5a4d0aac Merge pull request #1453 from mailpoet/schedule-standard
Schedule standard  [MQ-55] [MQ-45]
2018-09-07 10:06:38 -04:00
fd4af798f1 Update ScheduleNewsletterCest.php 2018-09-07 09:26:05 -04:00
bf03dd105f Merge pull request #1494 from mailpoet/nested-container-render
Fix rendering of nested vertical containers [MAILPOET-1524]
2018-09-06 14:07:56 -04:00
013ab522c6 Merge pull request #1493 from mailpoet/unsubscribe-link
Use newsletter body content to check for unsubscribe link [MAILPOET-1515]
2018-09-06 13:32:56 -04:00
3e9be631e4 Fix rendering of nested vertical containers
[MAILPOET-1524]
2018-09-06 14:14:21 +02:00
30538f9f9b Merge pull request #1490 from mailpoet/changelog-fix
Fix Changelog formatting in readme.txt [MAILPOET-1521]
2018-09-06 07:49:03 -04:00
428b7a1363 Schedule standard [MQ-55] [MQ-45] 2018-09-05 11:59:18 -04:00
ddcc6c03a0 Schedule standard [MQ-55] [MQ-45] 2018-09-05 11:33:59 -04:00
f8306635a7 Use newsletter body content to check for unsubscribe link
We used the whole newsletter but there is a defaultContent which always contains
unsubscribe link so the check always passed
2018-09-05 16:10:32 +02:00
8c10896bc8 Rename global translations file
[MAILPOET-1520]
2018-09-05 14:51:45 +02:00
8ee8498bd5 Move welcome emails to free plugin
[MAILPOET-1518]
2018-09-05 13:00:29 +02:00
a2ce279e23 Fix Changelog formatting in readme.txt
[MAILPOET-1521]
2018-09-04 17:55:33 +02:00
43c4a24ab3 Schedule Standard Newsletter Test [MQ-45] 2018-08-02 12:17:29 -04:00
f2382d25bd Search for Standard Newsletter [MQ-55] 2018-08-02 10:28:13 -04:00
14 changed files with 275 additions and 34 deletions

View File

@ -265,20 +265,24 @@ define([
}
},
validateNewsletter: function (jsonObject) {
var body = '';
var contents;
if (!App._contentContainer.isValid()) {
this.showValidationError(App._contentContainer.validationError);
return;
}
contents = JSON.stringify(jsonObject);
if (jsonObject && jsonObject.body && jsonObject.body.content) {
body = JSON.stringify(jsonObject.body.content);
}
if (App.getConfig().get('validation.validateUnsubscribeLinkPresent') &&
contents.indexOf('[link:subscription_unsubscribe_url]') < 0 &&
contents.indexOf('[link:subscription_unsubscribe]') < 0) {
body.indexOf('[link:subscription_unsubscribe_url]') < 0 &&
body.indexOf('[link:subscription_unsubscribe]') < 0) {
this.showValidationError(MailPoet.I18n.t('unsubscribeLinkMissing'));
return;
}
contents = JSON.stringify(jsonObject);
if ((App.getNewsletter().get('type') === 'notification') &&
contents.indexOf('"type":"automatedLatestContent"') < 0 &&
contents.indexOf('"type":"automatedLatestContentLayout"') < 0

View File

@ -113,6 +113,28 @@ let newsletterActions = [
);
},
},
{
name: 'duplicate',
label: MailPoet.I18n.t('duplicate'),
onClick: (newsletter, refresh) => MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'duplicate',
data: {
id: newsletter.id,
},
}).done((response) => {
MailPoet.Notice.success((MailPoet.I18n.t('newsletterDuplicated')).replace('%$1s', response.data.subject));
refresh();
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(error => error.message),
{ scroll: true }
);
}
}),
},
{
name: 'edit',
link: function link(newsletter) {

View File

@ -10,6 +10,7 @@ import NewsletterTemplates from 'newsletters/templates.jsx';
import NewsletterSend from 'newsletters/send.jsx';
import NewsletterTypeStandard from 'newsletters/types/standard.jsx';
import NewsletterTypeNotification from 'newsletters/types/notification/notification.jsx';
import NewsletterTypeWelcome from 'newsletters/types/welcome/welcome.jsx';
import AutomaticEmailEventsList from 'newsletters/types/automatic_emails/events_list.jsx';
import NewsletterListStandard from 'newsletters/listings/standard.jsx';
import NewsletterListWelcome from 'newsletters/listings/welcome.jsx';
@ -73,6 +74,10 @@ if (container) {
path: 'new/notification',
component: NewsletterTypeNotification,
},
{
path: 'new/welcome',
component: NewsletterTypeWelcome,
},
/* Template selection */
{
name: 'template',

View File

@ -67,6 +67,7 @@ const NewsletterTypes = React.createClass({
render: function render() {
const createStandardNewsletter = _.partial(this.createNewsletter, 'standard');
const createNotificationNewsletter = _.partial(this.setupNewsletter, 'notification');
const createWelcomeNewsletter = _.partial(this.setupNewsletter, 'welcome');
const defaultTypes = [
{
slug: 'standard',
@ -93,11 +94,22 @@ const NewsletterTypes = React.createClass({
videoGuide: 'https://beta.docs.mailpoet.com/article/254-video-guide-to-welcome-emails',
action: (function action() {
return (
<div>
<a href="?page=mailpoet-premium" target="_blank">
{MailPoet.I18n.t('premiumFeatureLink')}
</a>
</div>
<a
className="button button-primary"
onClick={createWelcomeNewsletter}
data-automation-id="create_welcome"
onKeyDown={(event) => {
if ((['keydown', 'keypress'].includes(event.type) && ['Enter', ' '].includes(event.key))
) {
event.preventDefault();
createWelcomeNewsletter();
}
}}
role="button"
tabIndex={0}
>
{MailPoet.I18n.t('setUp')}
</a>
);
}()),
},

View File

@ -0,0 +1,104 @@
import React from 'react';
import _ from 'underscore';
import MailPoet from 'mailpoet';
import PropTypes from 'prop-types';
import Breadcrumb from '../../breadcrumb.jsx';
import WelcomeScheduling from './scheduling.jsx';
const field = {
name: 'options',
label: 'Event',
type: 'reactComponent',
component: WelcomeScheduling,
};
class NewsletterWelcome extends React.Component {
constructor(props) {
super(props);
let availableSegments = window.mailpoet_segments || [];
let defaultSegment = 1;
availableSegments = availableSegments.filter(segment => segment.type === 'default');
if (_.size(availableSegments) > 0) {
defaultSegment = _.first(availableSegments).id;
}
this.state = {
options: {
event: 'segment',
segment: defaultSegment,
role: 'subscriber',
afterTimeNumber: 1,
afterTimeType: 'immediate',
},
};
this.handleValueChange = this.handleValueChange.bind(this);
this.handleNext = this.handleNext.bind(this);
}
handleValueChange(event) {
const { state } = this;
state[event.target.name] = event.target.value;
this.setState(state);
}
handleNext() {
MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'create',
data: _.extend({}, this.state, {
type: 'welcome',
subject: MailPoet.I18n.t('draftNewsletterTitle'),
}),
}).done((response) => {
this.showTemplateSelection(response.data.id);
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(error => error.message),
{ scroll: true }
);
}
});
}
showTemplateSelection(newsletterId) {
this.props.router.push(`/template/${newsletterId}`);
}
render() {
return (
<div>
<h1>{MailPoet.I18n.t('welcomeNewsletterTypeTitle')}</h1>
<Breadcrumb step="type" />
<h3>{MailPoet.I18n.t('selectEventToSendWelcomeEmail')}</h3>
<WelcomeScheduling
item={this.state}
field={field}
onValueChange={this.handleValueChange}
/>
<p className="submit">
<input
className="button button-primary"
type="button"
onClick={this.handleNext}
value={MailPoet.I18n.t('next')}
/>
</p>
</div>
);
}
}
NewsletterWelcome.propTypes = {
router: PropTypes.shape({
push: PropTypes.func.isRequired,
}).isRequired,
};
export default NewsletterWelcome;

View File

@ -12,8 +12,9 @@ class Localizer {
function loadGlobalText() {
$language_path = sprintf(
'%s/%s.mo',
'%s/%s-%s.mo',
Env::$languages_path,
Env::$plugin_name,
$this->locale()
);
load_textdomain(Env::$plugin_name, $language_path);

View File

@ -40,7 +40,12 @@ class Renderer {
$rendered_block_element = $_this->createElementFromBlockType($block, $column_count);
if(isset($block['blocks'])) {
$rendered_block_element = $_this->render($block, $column_count);
// nested vertical column container is rendered as an array
if(is_array($rendered_block_element)) {
$rendered_block_element = implode('', $rendered_block_element);
}
}
// vertical orientation denotes column container
if($block['type'] === 'container' && $block['orientation'] === 'vertical') {
$column_content[] = $rendered_block_element;

View File

@ -4,7 +4,7 @@ if(!defined('ABSPATH')) exit;
/*
* Plugin Name: MailPoet 3 (New)
* Version: 3.9.1
* Version: 3.10
* Plugin URI: http://www.mailpoet.com
* Description: Create and send newsletters, post notifications and welcome emails from your WordPress.
* Author: MailPoet
@ -18,7 +18,7 @@ if(!defined('ABSPATH')) exit;
*/
$mailpoet_plugin = array(
'version' => '3.9.1',
'version' => '3.10',
'filename' => __FILE__,
'path' => dirname(__FILE__),
'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',

View File

@ -3,7 +3,7 @@ Contributors: mailpoet, wysija, kgjerstad
Tags: newsletter, newsletter subscribers, email, welcome email, post notification, WooCommerce emails, newsletter builder, mailing list
Requires at least: 4.7
Tested up to: 4.9
Stable tag: 3.9.1
Stable tag: 3.10
License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.html
@ -162,24 +162,28 @@ Stop by our [support site](https://www.mailpoet.com/support).
== Changelog ==
= 3.10 - 2018-09-11 =
* Changed: welcome emails to new subscribers are now free for everyone!
* Fixed: newsletter footer warning to be displayed if unsubscribe link is missing.
= 3.9.1 - 2018-09-04 =
Improved: instructions for migrating from MP2 to MP3 clarified;
Improved: minor style adjustments for migration tool;
Improved: minor fixes to onboarding intro guide;
Improved: template page loading times decreased;
Fixed: resolved javascript warnings on help page status;
Fixed: subscriber status remains persistent after migration from MP2 to MP3 without sign-up confirmation enabled;
* Improved: instructions for migrating from MP2 to MP3 clarified;
* Improved: minor style adjustments for migration tool;
* Improved: minor fixes to onboarding intro guide;
* Improved: template page loading times decreased;
* Fixed: resolved javascript warnings on help page status;
* Fixed: subscriber status remains persistent after migration from MP2 to MP3 without sign-up confirmation enabled;
= 3.9.0 - 2018-08-28 =
Improved: email processing in sending queues is now more resilient to invalid data. Thanks Tara!
Fixed: replaced WooCommerce image in welcome wizard;
Fixed: swapped video in welcome wizard with an updated one;
Fixed: welcome wizard button displays properly for all users;
Fixed: permission error when bypassing data import after new install or reset;
Fixed: added indexes to some foreign keys which were missing;
Fixed: error displaying number of exported users;
Fixed: export search function restored;
Fixed: prevent third party APIs from adding data incorrectly via MailPoets API.
* Improved: email processing in sending queues is now more resilient to invalid data. Thanks Tara!
* Fixed: replaced WooCommerce image in welcome wizard;
* Fixed: swapped video in welcome wizard with an updated one;
* Fixed: welcome wizard button displays properly for all users;
* Fixed: permission error when bypassing data import after new install or reset;
* Fixed: added indexes to some foreign keys which were missing;
* Fixed: error displaying number of exported users;
* Fixed: export search function restored;
* Fixed: prevent third party APIs from adding data incorrectly via MailPoets API.
= 3.8.6 - 2018-08-21 =
* Improved: compatibility with caching plugins

View File

@ -0,0 +1,38 @@
<?php
namespace MailPoet\Test\Acceptance;
use MailPoet\Test\DataFactories\Newsletter;
require_once __DIR__ . '/../DataFactories/Newsletter.php';
class ScheduleNewsletterCest {
function scheduleStandardNewsletter(\AcceptanceTester $I) {
$I->wantTo('Schedule a newsletter');
$newsletter_title = 'Schedule Test Newsletter';
// step 1 - Prepare post notification data
$newsletterFactory = new Newsletter();
$newsletter = $newsletterFactory->withSubject($newsletter_title)
->withType('standard')
->create();
// step 2 - Go to editor
$I->login();
$I->amEditingNewsletter($newsletter->id);
$I->click('Next');
// step 4 - Choose list and schedule
$I->waitForElement('[data-automation-id="newsletter_send_form"]');
$I->seeInCurrentUrl('mailpoet-newsletters#/send/');
$search_field_element = 'input.select2-search__field';
$I->fillField($search_field_element, 'WordPress Users');
$I->pressKey($search_field_element, \WebDriverKeys::ENTER);
$I->checkOption('isScheduled');
$I->click('select[name=time]');
$I->selectOption('form select[name=time]', '6:00');
$I->click('Schedule');
$I->wait(30);
$I->seeInCurrentUrl('mailpoet-newsletters');
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace MailPoet\Test\Acceptance;
use MailPoet\Test\DataFactories\Newsletter;
require_once __DIR__ . '/../DataFactories/Newsletter.php';
class SearchForStandardNewsletterCest {
function searchForStandardNewsletter(\AcceptanceTester $I) {
$I->wantTo('Successfully search for an existing newsletter');
$newsletter_title = 'Search Test Newsletter';
$failure_condition_newsletter = 'Not Actually Real';
// step 1 - Prepare newsletter data
$newsletterFactory = new Newsletter();
$newsletter = $newsletterFactory->withSubject($newsletter_title)
->withType('standard')
->create();
// step 2 - Search
$I->login();
$I->amOnMailpoetPage('Emails');
$I->fillField('#search_input', $failure_condition_newsletter);
$I->click('Search');
$I->wait(5);
$I->dontSee($newsletter_title);
$I->fillField('#search_input', $newsletter_title);
$I->click('Search');
$I->waitForText($newsletter_title, 20);
}
}

View File

@ -45,6 +45,9 @@ class RendererTest extends \MailPoetTest {
expect(count($DOM('.mailpoet_cols-one')))->equals(2);
expect(count($DOM('.mailpoet_cols-two')))->equals(2);
expect(count($DOM('.mailpoet_cols-three')))->equals(3);
// nested vertical container should be rendered
expect(count($DOM('.nested-vertical-container')))->equals(1);
}
function testItRendersOneColumn() {

View File

@ -211,6 +211,21 @@
{
"type": "text",
"text": "<p>Test trailing line breaks removal</p>\n<h3>Test line breaks <br/> in headings <a href=\"http://www.example.org\">haha</a></h3><br /><br><br/>"
},
{
"type": "container",
"orientation": "vertical",
"styles": {
"block": {
"backgroundColor": "transparent"
}
},
"blocks": [
{
"type": "text",
"text": "<p class='nested-vertical-container'>Nested vertical container content</p>"
}
]
}
]
}

View File

@ -165,13 +165,6 @@ var baseConfig = {
'babel-loader',
]
},
{
include: path.resolve(__dirname, 'assets/js/src/newsletters/types/welcome/scheduling.jsx'),
use: [
'expose-loader?' + globalPrefix + '.NewsletterWelcomeNotificationScheduling',
'babel-loader',
]
},
{
include: path.resolve(__dirname, 'assets/js/src/newsletters/breadcrumb.jsx'),
use: [