Compare commits
25 Commits
c1ced0cc73
...
e674cfe30e
Author | SHA1 | Date | |
---|---|---|---|
e674cfe30e | |||
ef31486d2e | |||
03e10b96e9 | |||
54359dc610 | |||
5c7a746470 | |||
83033c7991 | |||
b480fb510f | |||
043d8d187b | |||
1faf5822a2 | |||
0898ed7b56 | |||
d5908a6fb9 | |||
b6ed846b8b | |||
75cf32c211 | |||
80e0a92243 | |||
2ccaff11ae | |||
d98722a94a | |||
3b75c10670 | |||
7dea7bbf00 | |||
f6c81b2583 | |||
8bc5c1b976 | |||
2f77fc3912 | |||
3d970898d7 | |||
ff3614821a | |||
6acf7a5137 | |||
e9127734b2 |
@ -197,10 +197,10 @@ jobs:
|
||||
- run:
|
||||
name: Download additional WP Plugins for tests
|
||||
command: |
|
||||
./do download:woo-commerce-zip 9.8.2
|
||||
./do download:woo-commerce-zip 9.8.3
|
||||
./do download:woo-commerce-subscriptions-zip 7.4.0
|
||||
./do download:woo-commerce-memberships-zip
|
||||
./do download:automate-woo-zip 6.1.10
|
||||
./do download:automate-woo-zip 6.1.11
|
||||
- run:
|
||||
name: Dump tests ENV variables for acceptance tests
|
||||
command: |
|
||||
|
@ -195,8 +195,8 @@ div.mailpoet-listing-bulk-actions-container {
|
||||
border-bottom: 1px solid $color-tertiary-light;
|
||||
box-shadow: none;
|
||||
max-width: 30vw;
|
||||
padding: $grid-gap-medium $grid-gap-half;
|
||||
vertical-align: middle;
|
||||
padding: 12px $grid-gap-half;
|
||||
vertical-align: top;
|
||||
|
||||
@include respond-to(small-screen) {
|
||||
max-width: none;
|
||||
@ -310,13 +310,10 @@ a.mailpoet-listing-title {
|
||||
|
||||
.mailpoet-listing-actions {
|
||||
align-items: center;
|
||||
display: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
left: 0;
|
||||
line-height: 15px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
visibility: hidden;
|
||||
|
||||
a {
|
||||
color: $color-text-light;
|
||||
@ -340,7 +337,7 @@ a.mailpoet-listing-title {
|
||||
}
|
||||
|
||||
tr:hover & {
|
||||
display: flex;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@include respond-to(small-screen) {
|
||||
|
@ -1,8 +1,15 @@
|
||||
import slugify from 'slugify';
|
||||
|
||||
export function formatCustomFieldBlockName(blockName, customField) {
|
||||
const name = slugify(customField.name, { lower: true })
|
||||
let name = slugify(customField.name, { lower: true })
|
||||
.replace(/[^a-z0-9]+/g, '')
|
||||
.replace(/-$/, '');
|
||||
|
||||
// Ensure unique block names by appending ID if the slug is empty or too short
|
||||
// (which can happen with certain character sets)
|
||||
if (!name || name.length < 2) {
|
||||
name = `field${customField.id}`;
|
||||
}
|
||||
|
||||
return `${blockName}-${name}`;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"apiVersion": 2,
|
||||
"apiVersion": 3,
|
||||
"name": "mailpoet/marketing-optin-block",
|
||||
"version": "0.1.0",
|
||||
"title": "MailPoet Marketing Opt-in",
|
||||
|
@ -18,6 +18,7 @@ const adminUrl = getSetting('adminUrl');
|
||||
const { optinEnabled, defaultText } = getSetting('mailpoet_data');
|
||||
|
||||
function EmptyState(): JSX.Element {
|
||||
const adminUrlToEnableOptIn = `${adminUrl}admin.php?page=mailpoet-settings#/woocommerce`;
|
||||
return (
|
||||
<Placeholder
|
||||
icon={<Icon icon={megaphone} />}
|
||||
@ -32,10 +33,10 @@ function EmptyState(): JSX.Element {
|
||||
</span>
|
||||
<Button
|
||||
variant="primary"
|
||||
href={`${adminUrl}admin.php?page=mailpoet-settings#/woocommerce`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="wp-block-mailpoet-newsletter-block-placeholder__button"
|
||||
onClick={() => {
|
||||
window.open(adminUrlToEnableOptIn, '_blank', 'noopener noreferrer');
|
||||
}}
|
||||
>
|
||||
{__('Enable opt-in for Checkout', 'mailpoet')}
|
||||
</Button>
|
||||
|
@ -4,12 +4,13 @@ import { Icon } from './icon.jsx';
|
||||
|
||||
const wp = window.wp;
|
||||
const { Placeholder, PanelBody } = wp.components;
|
||||
const { BlockIcon, InspectorControls } = wp.blockEditor;
|
||||
const { BlockIcon, InspectorControls, useBlockProps } = wp.blockEditor;
|
||||
const ServerSideRender = wp.serverSideRender;
|
||||
|
||||
const allForms = window.mailpoet_forms;
|
||||
|
||||
function Edit({ attributes, setAttributes }) {
|
||||
const blockProps = useBlockProps();
|
||||
function displayFormsSelect() {
|
||||
if (!Array.isArray(allForms)) return null;
|
||||
if (allForms.length === 0) return null;
|
||||
@ -27,7 +28,7 @@ function Edit({ attributes, setAttributes }) {
|
||||
{window.locale.selectForm}
|
||||
</option>
|
||||
{allForms.map((form) => (
|
||||
<option value={form.id}>
|
||||
<option value={form.id} key={`form-${form.id}`}>
|
||||
{form.name +
|
||||
(form.status === 'disabled'
|
||||
? ` (${window.locale.inactive})`
|
||||
@ -63,7 +64,7 @@ function Edit({ attributes, setAttributes }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div {...blockProps}>
|
||||
<InspectorControls>
|
||||
<PanelBody title="MailPoet Subscription Form" initialOpen>
|
||||
{selectFormSettings()}
|
||||
@ -81,7 +82,7 @@ function Edit({ attributes, setAttributes }) {
|
||||
)}
|
||||
{attributes.formId !== null && renderForm()}
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ const { registerBlockType } = wp.blocks;
|
||||
|
||||
registerBlockType('mailpoet/subscription-form-block-render', {
|
||||
title: window.locale.subscriptionForm,
|
||||
apiVersion: 3,
|
||||
attributes: {
|
||||
formId: {
|
||||
type: 'number',
|
||||
@ -19,6 +20,7 @@ registerBlockType('mailpoet/subscription-form-block-render', {
|
||||
|
||||
registerBlockType('mailpoet/subscription-form-block', {
|
||||
title: window.locale.subscriptionForm,
|
||||
apiVersion: 3,
|
||||
icon: Icon,
|
||||
category: 'widgets',
|
||||
example: {},
|
||||
|
@ -1,5 +1,9 @@
|
||||
== Changelog ==
|
||||
|
||||
= 5.12.1 - 2025-05-06 =
|
||||
* Fixed: listing action items overlaying with row border when on two lines on smaller screens;
|
||||
* Fixed: Handling of Japanese characters in custom field blocks in the form editor.
|
||||
|
||||
= 5.12.0 - 2025-04-29 =
|
||||
* Improved: more consistent look and feel of MailPoet pages with WordPress;
|
||||
* Improved: optimized email template images to decrease their file size;
|
||||
|
@ -0,0 +1,90 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Migrations\App;
|
||||
|
||||
use MailPoet\Entities\StatisticsClickEntity;
|
||||
use MailPoet\Entities\StatisticsUnsubscribeEntity;
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoet\Entities\SubscriberSegmentEntity;
|
||||
use MailPoet\Migrator\AppMigration;
|
||||
use MailPoetVendor\Doctrine\DBAL\Connection;
|
||||
|
||||
class Migration_20250501_114655_App extends AppMigration {
|
||||
private const DB_QUERY_CHUNK_SIZE = 1000;
|
||||
|
||||
public function run(): void {
|
||||
$clicksStatsTable = $this->entityManager->getClassMetadata(StatisticsClickEntity::class)->getTableName();
|
||||
$unsubscribeStatsTable = $this->entityManager->getClassMetadata(StatisticsUnsubscribeEntity::class)->getTableName();
|
||||
$subscribersTable = $this->entityManager->getClassMetadata(SubscriberEntity::class)->getTableName();
|
||||
$subscribersSegmentsTable = $this->entityManager->getClassMetadata(SubscriberSegmentEntity::class)->getTableName();
|
||||
|
||||
// First get all subscriber IDs that were unsubscribed by a bot
|
||||
$subscriberIds = $this->entityManager->getConnection()->executeQuery(
|
||||
"SELECT DISTINCT mp_unsub.subscriber_id
|
||||
FROM {$unsubscribeStatsTable} AS mp_unsub
|
||||
LEFT JOIN {$clicksStatsTable} AS mp_click
|
||||
ON mp_unsub.newsletter_id = mp_click.newsletter_id
|
||||
AND mp_unsub.subscriber_id = mp_click.subscriber_id
|
||||
AND ABS(TIMESTAMPDIFF(SECOND, mp_click.created_at, mp_unsub.created_at)) <= 4
|
||||
WHERE mp_unsub.created_at > '2025-03-01'
|
||||
GROUP BY mp_unsub.subscriber_id
|
||||
HAVING COUNT(mp_click.id) >= 3"
|
||||
)->fetchFirstColumn();
|
||||
|
||||
if (empty($subscriberIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Process subscriber IDs in chunks
|
||||
foreach (array_chunk($subscriberIds, self::DB_QUERY_CHUNK_SIZE) as $chunk) {
|
||||
$this->processSubscriberChunk(
|
||||
$chunk,
|
||||
$subscribersTable,
|
||||
$subscribersSegmentsTable,
|
||||
$unsubscribeStatsTable
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function processSubscriberChunk(
|
||||
array $subscriberIds,
|
||||
string $subscribersTable,
|
||||
string $subscribersSegmentsTable,
|
||||
string $unsubscribeStatsTable
|
||||
): void {
|
||||
// Switch the global subscriber status to subscribed
|
||||
$this->entityManager->getConnection()->executeQuery(
|
||||
"UPDATE {$subscribersTable}
|
||||
SET status = :subscribedStatus
|
||||
WHERE id IN (:subscriberIds)
|
||||
AND status = :unsubscribedStatus",
|
||||
[
|
||||
'subscribedStatus' => SubscriberEntity::STATUS_SUBSCRIBED,
|
||||
'unsubscribedStatus' => SubscriberEntity::STATUS_UNSUBSCRIBED,
|
||||
'subscriberIds' => $subscriberIds,
|
||||
],
|
||||
[
|
||||
'subscriberIds' => Connection::PARAM_INT_ARRAY,
|
||||
]
|
||||
);
|
||||
|
||||
// Update the subscriber_segment table, find rows that were unsubscribed at the same time
|
||||
$this->entityManager->getConnection()->executeQuery(
|
||||
"UPDATE {$subscribersSegmentsTable} AS mp_subseg
|
||||
JOIN {$unsubscribeStatsTable} AS mp_unsub
|
||||
ON mp_subseg.subscriber_id = mp_unsub.subscriber_id
|
||||
AND ABS(TIMESTAMPDIFF(SECOND, mp_subseg.updated_at, mp_unsub.created_at)) <= 2
|
||||
SET mp_subseg.status = :subscribedStatus
|
||||
WHERE mp_subseg.status = :unsubscribedStatus
|
||||
AND mp_subseg.subscriber_id IN (:subscriberIds)",
|
||||
[
|
||||
'subscribedStatus' => SubscriberEntity::STATUS_SUBSCRIBED,
|
||||
'unsubscribedStatus' => SubscriberEntity::STATUS_UNSUBSCRIBED,
|
||||
'subscriberIds' => $subscriberIds,
|
||||
],
|
||||
[
|
||||
'subscriberIds' => Connection::PARAM_INT_ARRAY,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
@ -115,7 +115,7 @@ class Migration_20230831_143755_Db extends DbMigration {
|
||||
$stepId = strval($item['step_id']);
|
||||
$stepKey = strval($steps[$stepId]['key'] ?? 'unknown');
|
||||
$triggerId = $steps['root']['next_steps'][0]['id'];
|
||||
$triggerKey = $steps['root']['next_steps'][0]['key'];
|
||||
$triggerKey = $steps['root']['next_steps'][0]['key'] ?? 'unknown';
|
||||
|
||||
$queries[] = "UPDATE {$logsTable} SET step_key = '{$stepKey}' WHERE id = {$id}";
|
||||
|
||||
@ -132,7 +132,16 @@ class Migration_20230831_143755_Db extends DbMigration {
|
||||
}
|
||||
}
|
||||
|
||||
$this->connection->executeStatement(implode(';', $queries));
|
||||
$nativeConnection = $this->connection->getNativeConnection();
|
||||
// If the connection is a mysqli object, we can use the multi_query method
|
||||
if (is_object($nativeConnection) && get_class($nativeConnection) === 'mysqli') {
|
||||
$query = implode(';', $queries);
|
||||
$nativeConnection->multi_query($query);
|
||||
} else { // Otherwise, we need to execute each query individually (e.g. PDO or SQLite)
|
||||
foreach ($queries as $query) {
|
||||
$this->connection->executeStatement($query);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
* Plugin Name: MailPoet
|
||||
* Version: 5.12.0
|
||||
* Version: 5.12.1
|
||||
* Plugin URI: https://www.mailpoet.com
|
||||
* Description: Create and send newsletters, post notifications and welcome emails from your WordPress.
|
||||
* Author: MailPoet
|
||||
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
$mailpoetPlugin = [
|
||||
'version' => '5.12.0',
|
||||
'version' => '5.12.1',
|
||||
'filename' => __FILE__,
|
||||
'path' => dirname(__FILE__),
|
||||
'autoloader' => dirname(__FILE__) . '/vendor/autoload.php',
|
||||
|
@ -3,7 +3,7 @@ Contributors: mailpoet, woocommerce, automattic
|
||||
Tags: email marketing, post notification, woocommerce emails, email automation, newsletter
|
||||
Requires at least: 6.7
|
||||
Tested up to: 6.8
|
||||
Stable tag: 5.12.0
|
||||
Stable tag: 5.12.1
|
||||
Requires PHP: 7.4
|
||||
License: GPLv3
|
||||
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
||||
@ -222,11 +222,8 @@ Check our [Knowledge Base](https://kb.mailpoet.com) or contact us through our [s
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 5.12.0 - 2025-04-29 =
|
||||
* Improved: more consistent look and feel of MailPoet pages with WordPress;
|
||||
* Improved: optimized email template images to decrease their file size;
|
||||
* Improved: better handling of unsubscribes via the link provided in the List-Unsubscribe header;
|
||||
* Fixed: unreadable customer name in automation analytics when Gravatar fails to load;
|
||||
* Fixed: "Custom HTML" block in form editor doesn't preserve "Automatically add paragraphs" setting.
|
||||
= 5.12.1 - 2025-05-06 =
|
||||
* Fixed: listing action items overlaying with row border when on two lines on smaller screens;
|
||||
* Fixed: Handling of Japanese characters in custom field blocks in the form editor.
|
||||
|
||||
[See the changelog for all versions.](https://github.com/mailpoet/mailpoet/blob/trunk/mailpoet/changelog.txt)
|
||||
|
51
mailpoet/tests/DataFactories/StatisticsUnsubscribes.php
Normal file
51
mailpoet/tests/DataFactories/StatisticsUnsubscribes.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Test\DataFactories;
|
||||
|
||||
use MailPoet\DI\ContainerWrapper;
|
||||
use MailPoet\Entities\NewsletterEntity;
|
||||
use MailPoet\Entities\SendingQueueEntity;
|
||||
use MailPoet\Entities\StatisticsUnsubscribeEntity;
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoetVendor\Doctrine\ORM\EntityManager;
|
||||
use PHPUnit\Framework\Assert;
|
||||
|
||||
class StatisticsUnsubscribes {
|
||||
protected $data;
|
||||
|
||||
/** @var NewsletterEntity */
|
||||
private $newsletter;
|
||||
|
||||
/** @var SubscriberEntity */
|
||||
private $subscriber;
|
||||
|
||||
public function __construct(
|
||||
NewsletterEntity $newsletter,
|
||||
SubscriberEntity $subscriber
|
||||
) {
|
||||
$this->newsletter = $newsletter;
|
||||
$this->subscriber = $subscriber;
|
||||
}
|
||||
|
||||
public function withCreatedAt(\DateTimeInterface $createdAt): self {
|
||||
$this->data['createdAt'] = $createdAt;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function create(): StatisticsUnsubscribeEntity {
|
||||
$entityManager = ContainerWrapper::getInstance()->get(EntityManager::class);
|
||||
$queue = $this->newsletter->getLatestQueue();
|
||||
Assert::assertInstanceOf(SendingQueueEntity::class, $queue);
|
||||
$entity = new StatisticsUnsubscribeEntity(
|
||||
$this->newsletter,
|
||||
$queue,
|
||||
$this->subscriber
|
||||
);
|
||||
if (($this->data['createdAt'] ?? null) instanceof \DateTimeInterface) {
|
||||
$entity->setCreatedAt($this->data['createdAt']);
|
||||
}
|
||||
$entityManager->persist($entity);
|
||||
$entityManager->flush();
|
||||
return $entity;
|
||||
}
|
||||
}
|
61
mailpoet/tests/DataFactories/SubscriberSegment.php
Normal file
61
mailpoet/tests/DataFactories/SubscriberSegment.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace MailPoet\Test\DataFactories;
|
||||
|
||||
use MailPoet\DI\ContainerWrapper;
|
||||
use MailPoet\Entities\SegmentEntity;
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoet\Entities\SubscriberSegmentEntity;
|
||||
use MailPoetVendor\Doctrine\ORM\EntityManager;
|
||||
|
||||
class SubscriberSegment {
|
||||
protected $data;
|
||||
|
||||
/** @var SubscriberEntity */
|
||||
private $subscriber;
|
||||
|
||||
/** @var SegmentEntity */
|
||||
private $segment;
|
||||
|
||||
public function __construct(
|
||||
SubscriberEntity $subscriber,
|
||||
SegmentEntity $segment,
|
||||
string $status = SubscriberEntity::STATUS_SUBSCRIBED
|
||||
) {
|
||||
$this->subscriber = $subscriber;
|
||||
$this->segment = $segment;
|
||||
$this->data['status'] = $status;
|
||||
}
|
||||
|
||||
public function withStatus(string $status): self {
|
||||
$this->data['status'] = $status;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withUpdatedAt(\DateTimeInterface $updatedAt): self {
|
||||
$this->data['updatedAt'] = $updatedAt;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function create(): SubscriberSegmentEntity {
|
||||
$entityManager = ContainerWrapper::getInstance()->get(EntityManager::class);
|
||||
$entity = new SubscriberSegmentEntity($this->segment, $this->subscriber, $this->data['status']);
|
||||
|
||||
if (isset($this->data['status'])) {
|
||||
$entity->setStatus($this->data['status']);
|
||||
}
|
||||
|
||||
$entityManager->persist($entity);
|
||||
$entityManager->flush();
|
||||
$entityManager->refresh($entity);
|
||||
if (($this->data['updatedAt'] ?? null) instanceof \DateTimeInterface) {
|
||||
$subscribersSegmentsTable = $entityManager->getClassMetadata(SubscriberSegmentEntity::class)->getTableName();
|
||||
$entityManager->getConnection()->executeQuery("UPDATE {$subscribersSegmentsTable} SET updated_at = :updatedAt WHERE id = :id", [
|
||||
'updatedAt' => $this->data['updatedAt']->format('Y-m-d H:i:s'),
|
||||
'id' => $entity->getId(),
|
||||
]);
|
||||
};
|
||||
$entityManager->refresh($entity);
|
||||
return $entity;
|
||||
}
|
||||
}
|
@ -122,22 +122,22 @@ class GutenbergFormBlockCest {
|
||||
$i->amEditingPostWithId($postId);
|
||||
$this->closeDialog($i);
|
||||
$i->waitForText('My Gutenberg form');
|
||||
$i->switchToIframe('iframe[name="editor-canvas"]');
|
||||
$i->click('[aria-label="Add title"]');
|
||||
$i->click('[aria-label="Add block"]');
|
||||
$i->switchToIFrame();
|
||||
$i->fillField('[placeholder="Search"]', 'MailPoet Subscription Form');
|
||||
$i->waitForElement(Locator::contains('button', 'MailPoet Subscription Form'));
|
||||
$i->click(Locator::contains('button', 'MailPoet Subscription Form'));
|
||||
$i->switchToIframe('iframe[name="editor-canvas"]');
|
||||
$i->waitForElement('[aria-label="Block: MailPoet Subscription Form"]');
|
||||
$i->selectOption('.mailpoet-block-create-forms-list', 'Acceptance Test Block Form');
|
||||
$i->waitForElementVisible('[data-automation-id="form_email"]');
|
||||
$i->waitForElementVisible('[data-automation-id="form_first_name"]');
|
||||
$i->waitForElementVisible('[data-automation-id="form_last_name"]');
|
||||
// From WP 6.6 the button label is Save
|
||||
if (version_compare($i->getWordPressVersion(), '6.6', '<')) {
|
||||
$i->click('Update');
|
||||
} else {
|
||||
$i->click('Save');
|
||||
}
|
||||
$i->switchToIFrame();
|
||||
$i->click('Save');
|
||||
|
||||
$i->waitForText('Post updated.');
|
||||
|
||||
$i->wantTo('Verify the added form on the front-end');
|
||||
|
@ -63,7 +63,9 @@ class WooCheckoutBlocksCest {
|
||||
$i->wantTo('Check a message when opt-in is disabled');
|
||||
$i->login();
|
||||
$i->amOnAdminPage("post.php?post={$this->checkoutPostId}&action=edit");
|
||||
$i->switchToIframe('iframe[name="editor-canvas"]');
|
||||
$i->canSee('MailPoet marketing opt-in would be shown here if enabled. You can enable from the settings page.');
|
||||
$i->switchToIframe();
|
||||
$i->logOut();
|
||||
$this->orderProduct($i, $customerEmail, true, false);
|
||||
$i->login();
|
||||
@ -223,25 +225,27 @@ class WooCheckoutBlocksCest {
|
||||
$i->wantTo('Choose a pattern was not present, skipping action.');
|
||||
}
|
||||
$this->closeDialog($i);
|
||||
$i->switchToIframe('iframe[name="editor-canvas"]');
|
||||
$i->click('[aria-label="Add title"]'); // For block inserter to show up
|
||||
$i->click('[aria-label="Add block"]');
|
||||
$i->switchToIframe();
|
||||
$i->fillField('[placeholder="Search"]', 'Checkout');
|
||||
$i->waitForElement(Locator::contains('button > span > span', 'Checkout'));
|
||||
$i->click(Locator::contains('button > span > span', 'Checkout')); // Select Checkout block
|
||||
$i->switchToIframe('iframe[name="editor-canvas"]');
|
||||
$i->waitForElement('[aria-label="Block: Checkout"]');
|
||||
|
||||
// Close dialog with Compatibility notice
|
||||
$i->switchToIframe();
|
||||
$this->closeDialog($i);
|
||||
|
||||
// Enable registration during the checkout
|
||||
$i->switchToIframe('iframe[name="editor-canvas"]');
|
||||
$i->click('[aria-label="Block: Contact Information"]');
|
||||
|
||||
// From WP 6.6 the button label is Save
|
||||
$version = (string)preg_replace('/-(RC|beta)\d*/', '', $i->getWordPressVersion());
|
||||
if (version_compare($version, '6.6', '<')) {
|
||||
$i->click('Update');
|
||||
} else {
|
||||
$i->click('Save');
|
||||
}
|
||||
$i->switchToIframe();
|
||||
$i->click('Save');
|
||||
|
||||
$i->waitForText('Page updated.');
|
||||
$i->logOut();
|
||||
return $postId;
|
||||
|
@ -20,7 +20,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
$defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create();
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subMonths(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$processed = $this->reporter->getData();
|
||||
|
||||
$this->assertEquals(1, $processed['Number of standard newsletters sent in last 7 days']);
|
||||
@ -32,7 +32,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
$dynamicSegment = (new Segment())->withType(SegmentEntity::TYPE_DYNAMIC)->create();
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(8), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(89), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subMonths(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$processed = $this->reporter->getData();
|
||||
|
||||
$this->assertEquals(1, $processed['Number of standard newsletters sent in last 7 days']);
|
||||
@ -47,7 +47,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
$defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create();
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subMonths(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
$processed = $this->reporter->getData();
|
||||
|
||||
$this->assertEquals(1, $processed['Number of standard newsletters sent in last 7 days']);
|
||||
@ -65,7 +65,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
$defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create();
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subMonths(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$processed = $this->reporter->getData();
|
||||
|
||||
$this->assertEquals(1, $processed['Number of post notification campaigns sent in the last 7 days']);
|
||||
@ -77,7 +77,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
$dynamicSegment = (new Segment())->withType(SegmentEntity::TYPE_DYNAMIC)->create();
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(8), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(89), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subMonths(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$processed = $this->reporter->getData();
|
||||
|
||||
$this->assertEquals(1, $processed['Number of post notification campaigns sent in the last 7 days']);
|
||||
@ -92,7 +92,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
$defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create();
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'filterSegment' => ['not' => 'relevant']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'filterSegment' => ['not' => 'relevant']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'filterSegment' => ['not' => 'relevant']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subMonths(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'filterSegment' => ['not' => 'relevant']]]]);
|
||||
$processed = $this->reporter->getData();
|
||||
|
||||
$this->assertEquals(1, $processed['Number of post notification campaigns sent in the last 7 days']);
|
||||
@ -110,7 +110,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
$defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create();
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subMonths(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$processed = $this->reporter->getData();
|
||||
|
||||
$this->assertEquals(1, $processed['Number of re-engagement campaigns sent in the last 7 days']);
|
||||
@ -122,7 +122,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
$dynamicSegment = (new Segment())->withType(SegmentEntity::TYPE_DYNAMIC)->create();
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(8), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(89), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subMonths(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$processed = $this->reporter->getData();
|
||||
|
||||
$this->assertEquals(1, $processed['Number of re-engagement campaigns sent in the last 7 days']);
|
||||
@ -137,7 +137,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
$dynamicSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create();
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(8), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(89), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subMonths(2), [$dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
$processed = $this->reporter->getData();
|
||||
|
||||
$this->assertEquals(1, $processed['Number of re-engagement campaigns sent in the last 7 days']);
|
||||
@ -154,7 +154,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
public function testItWorksWithLegacyWelcomeEmails(): void {
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_WELCOME, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_WELCOME, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_WELCOME, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_WELCOME, Carbon::now()->subMonths(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$processed = $this->reporter->getData();
|
||||
$this->assertSame(1, $processed['Number of legacy welcome email campaigns sent in the last 7 days']);
|
||||
$this->assertSame(2, $processed['Number of legacy welcome email campaigns sent in the last 30 days']);
|
||||
@ -164,7 +164,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
public function testItWorksWithLegacyAbandonedCartEmails(): void {
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'cart_product_ids' => ['123']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'cart_product_ids' => ['1234']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'cart_product_ids' => ['1235']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subMonths(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'cart_product_ids' => ['1235']]]]);
|
||||
$processed = $this->reporter->getData();
|
||||
$this->assertSame(1, $processed['Number of legacy abandoned cart campaigns sent in the last 7 days']);
|
||||
$this->assertSame(2, $processed['Number of legacy abandoned cart campaigns sent in the last 30 days']);
|
||||
@ -174,7 +174,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
public function testItWorksWithLegacyPurchasedProductEmails(): void {
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'orderedProducts' => ['123']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'orderedProducts' => ['1234']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'orderedProducts' => ['1235']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subMonths(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'orderedProducts' => ['1235']]]]);
|
||||
$processed = $this->reporter->getData();
|
||||
$this->assertSame(1, $processed['Number of legacy purchased product campaigns sent in the last 7 days']);
|
||||
$this->assertSame(2, $processed['Number of legacy purchased product campaigns sent in the last 30 days']);
|
||||
@ -184,7 +184,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
public function testItWorksWithLegacyPurchasedInCategoryEmails(): void {
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'orderedProductCategories' => ['123']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'orderedProductCategories' => ['1234']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'orderedProductCategories' => ['1235']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subMonths(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'orderedProductCategories' => ['1235']]]]);
|
||||
$processed = $this->reporter->getData();
|
||||
$this->assertSame(1, $processed['Number of legacy purchased in category campaigns sent in the last 7 days']);
|
||||
$this->assertSame(2, $processed['Number of legacy purchased in category campaigns sent in the last 30 days']);
|
||||
@ -194,7 +194,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
public function testItWorksWithLegacyFirstPurchaseEmails(): void {
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'order_amount' => 123, 'order_date' => '2024-03-01', 'order_id' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'order_amount' => 123, 'order_date' => '2024-03-01', 'order_id' => '2']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'order_amount' => 123, 'order_date' => '2024-03-01', 'order_id' => '3']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATIC, Carbon::now()->subMonths(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'order_amount' => 123, 'order_date' => '2024-03-01', 'order_id' => '3']]]);
|
||||
$processed = $this->reporter->getData();
|
||||
$this->assertSame(1, $processed['Number of legacy first purchase campaigns sent in the last 7 days']);
|
||||
$this->assertSame(2, $processed['Number of legacy first purchase campaigns sent in the last 30 days']);
|
||||
@ -204,7 +204,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
public function testItWorksForAutomationEmails(): void {
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATION, Carbon::now()->subDays(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1', 'orderedProductCategories' => ['123']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATION, Carbon::now()->subDays(8), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2', 'orderedProductCategories' => ['1234']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATION, Carbon::now()->subDays(89), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'orderedProductCategories' => ['1235']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_AUTOMATION, Carbon::now()->subMonths(2), [], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3', 'orderedProductCategories' => ['1235']]]]);
|
||||
|
||||
$processed = $this->reporter->getData();
|
||||
|
||||
@ -218,15 +218,15 @@ class ReporterTest extends \MailPoetTest {
|
||||
$dynamicSegment = (new Segment())->withType(SegmentEntity::TYPE_DYNAMIC)->create();
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '2']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subMonths(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '3']]]);
|
||||
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(2), [$defaultSegment, $dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '4']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(8), [$defaultSegment, $dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '5']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subDays(89), [$defaultSegment, $dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '6']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_RE_ENGAGEMENT, Carbon::now()->subMonths(2), [$defaultSegment, $dynamicSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '6']]]);
|
||||
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '7', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '8', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '9', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_STANDARD, Carbon::now()->subMonths(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '9', 'filterSegment' => ['theDataDoesNot' => 'matter']]]]);
|
||||
|
||||
$processed = $this->reporter->getData();
|
||||
$this->assertEquals(3, $processed['Number of campaigns sent in the last 7 days']);
|
||||
@ -244,7 +244,7 @@ class ReporterTest extends \MailPoetTest {
|
||||
|
||||
public function testItDoesNotDoubleCountDuplicateCampaignIds(): void {
|
||||
$defaultSegment = (new Segment())->withType(SegmentEntity::TYPE_DEFAULT)->create();
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(89), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subMonths(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(8), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$this->createSentNewsletter(NewsletterEntity::TYPE_NOTIFICATION_HISTORY, Carbon::now()->subDays(2), [$defaultSegment], ['sendingQueueOptions' => ['meta' => ['campaignId' => '1']]]);
|
||||
$processed = $this->reporter->getData();
|
||||
|
@ -0,0 +1,150 @@
|
||||
<?php declare(strict_types = 1);
|
||||
|
||||
namespace integration\Migrations\App;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use MailPoet\Entities\NewsletterEntity;
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoet\Migrations\App\Migration_20250501_114655_App;
|
||||
use MailPoet\Test\DataFactories\Newsletter as NewsletterFactory;
|
||||
use MailPoet\Test\DataFactories\NewsletterLink as NewsletterLinkFactory;
|
||||
use MailPoet\Test\DataFactories\Segment as SegmentFactory;
|
||||
use MailPoet\Test\DataFactories\StatisticsClicks;
|
||||
use MailPoet\Test\DataFactories\StatisticsUnsubscribes;
|
||||
use MailPoet\Test\DataFactories\Subscriber;
|
||||
use MailPoet\Test\DataFactories\SubscriberSegment as SubscriberSegmentFactory;
|
||||
|
||||
// phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
|
||||
class Migration_20250501_114655_App_Test extends \MailPoetTest {
|
||||
/** @var Migration_20250501_114655_App */
|
||||
private $migration;
|
||||
|
||||
public function _before() {
|
||||
parent::_before();
|
||||
$this->migration = new Migration_20250501_114655_App($this->diContainer);
|
||||
}
|
||||
|
||||
public function testItPausesInvalidTasksWithUnprocessedSubscribers(): void {
|
||||
$subscriberFactory = new Subscriber();
|
||||
$subscriberUnsubscribedBefore = $subscriberFactory->withEmail('subscriber1@example.com')
|
||||
->withCreatedAt(new DateTimeImmutable('2024-12-01 10:00:00'))
|
||||
->withStatus(SubscriberEntity::STATUS_UNSUBSCRIBED)
|
||||
->create();
|
||||
$subscriberUnsubscribedByBot = $subscriberFactory->withEmail('subscriber2@example.com')
|
||||
->withCreatedAt(new DateTimeImmutable('2024-12-01 10:00:00'))
|
||||
->withStatus(SubscriberEntity::STATUS_UNSUBSCRIBED)
|
||||
->create();
|
||||
$subscriberUnsubscribedByUserManyClicks = $subscriberFactory->withEmail('subscriber3@example.com')
|
||||
->withCreatedAt(new DateTimeImmutable('2024-12-01 10:00:00'))
|
||||
->withStatus(SubscriberEntity::STATUS_UNSUBSCRIBED)
|
||||
->create();
|
||||
$subscriberUnsubscribedByUserSingleClick = $subscriberFactory->withEmail('subscriber4@example.com')
|
||||
->withCreatedAt(new DateTimeImmutable('2024-12-01 10:00:00'))
|
||||
->withStatus(SubscriberEntity::STATUS_UNSUBSCRIBED)
|
||||
->create();
|
||||
|
||||
$newsletterFactory = new NewsletterFactory();
|
||||
$newsletter = $newsletterFactory->withType(NewsletterEntity::TYPE_STANDARD)
|
||||
->withSubject('Test Newsletter')
|
||||
->withSendingQueue()
|
||||
->withStatus(NewsletterEntity::STATUS_SENT)
|
||||
->create();
|
||||
|
||||
$newsletterLinkFactory = new NewsletterLinkFactory($newsletter);
|
||||
$newsletterLink = $newsletterLinkFactory
|
||||
->withUrl('https://example.com/test')
|
||||
->create();
|
||||
|
||||
$newsletterLink2 = $newsletterLinkFactory
|
||||
->withUrl('https://example.com/test2')
|
||||
->create();
|
||||
|
||||
$newsletterLink3 = $newsletterLinkFactory
|
||||
->withUrl('https://example.com/test3')
|
||||
->create();
|
||||
|
||||
// Create a test segment
|
||||
$segment = (new SegmentFactory())->create();
|
||||
|
||||
// Create subscriber segments for each subscriber
|
||||
$subscriberSegmentFactory = new SubscriberSegmentFactory($subscriberUnsubscribedBefore, $segment);
|
||||
$subscriberSegmentBefore = $subscriberSegmentFactory
|
||||
->withStatus(SubscriberEntity::STATUS_UNSUBSCRIBED)
|
||||
->withUpdatedAt(new DateTimeImmutable('2024-12-01 10:00:00'))
|
||||
->create();
|
||||
|
||||
$subscriberSegmentFactory = new SubscriberSegmentFactory($subscriberUnsubscribedByBot, $segment);
|
||||
$subscriberSegmentByBot = $subscriberSegmentFactory
|
||||
->withStatus(SubscriberEntity::STATUS_UNSUBSCRIBED)
|
||||
->withUpdatedAt(new DateTimeImmutable('2025-04-01 10:00:03'))
|
||||
->create();
|
||||
|
||||
$subscriberSegmentFactory = new SubscriberSegmentFactory($subscriberUnsubscribedByUserManyClicks, $segment);
|
||||
$subscriberSegmentByUserManyClicks = $subscriberSegmentFactory
|
||||
->withStatus(SubscriberEntity::STATUS_UNSUBSCRIBED)
|
||||
->withUpdatedAt(new DateTimeImmutable('2025-04-01 10:00:55'))
|
||||
->create();
|
||||
|
||||
$subscriberSegmentFactory = new SubscriberSegmentFactory($subscriberUnsubscribedByUserSingleClick, $segment);
|
||||
$subscriberSegmentByUserSingleClick = $subscriberSegmentFactory
|
||||
->withStatus(SubscriberEntity::STATUS_UNSUBSCRIBED)
|
||||
->withUpdatedAt(new DateTimeImmutable('2025-04-01 10:00:00'))
|
||||
->create();
|
||||
|
||||
// $subscriberUnsubscribedBefore Has many suspicious clicks but unsubscribed before the issue
|
||||
$subscriber1ClickFactory = new StatisticsClicks($newsletterLink, $subscriberUnsubscribedBefore);
|
||||
$subscriber1ClickFactory->withCreatedAt(new DateTimeImmutable('2024-12-01 10:00:00'))->create();
|
||||
$subscriber1ClickFactory = new StatisticsClicks($newsletterLink2, $subscriberUnsubscribedBefore);
|
||||
$subscriber1ClickFactory->withCreatedAt(new DateTimeImmutable('2024-12-01 10:00:00'))->create();
|
||||
$subscriber1ClickFactory = new StatisticsClicks($newsletterLink3, $subscriberUnsubscribedBefore);
|
||||
$subscriber1ClickFactory->withCreatedAt(new DateTimeImmutable('2024-12-01 10:00:00'))->create();
|
||||
$subscriber1UnsubscribeFactory = new StatisticsUnsubscribes($newsletter, $subscriberUnsubscribedBefore);
|
||||
$subscriber1UnsubscribeFactory->withCreatedAt(new DateTimeImmutable('2024-12-01 10:00:00'))->create();
|
||||
|
||||
// $subscriberUnsubscribedByBot Has many suspicious clicks but and unsubscribed after the issue
|
||||
$subscriber2ClickFactory = new StatisticsClicks($newsletterLink, $subscriberUnsubscribedByBot);
|
||||
$subscriber2ClickFactory->withCreatedAt(new DateTimeImmutable('2025-04-01 10:00:00'))->create();
|
||||
$subscriber2ClickFactory = new StatisticsClicks($newsletterLink2, $subscriberUnsubscribedByBot);
|
||||
$subscriber2ClickFactory->withCreatedAt(new DateTimeImmutable('2025-04-01 10:00:02'))->create();
|
||||
$subscriber2ClickFactory = new StatisticsClicks($newsletterLink3, $subscriberUnsubscribedByBot);
|
||||
$subscriber2ClickFactory->withCreatedAt(new DateTimeImmutable('2025-04-01 10:00:05'))->create();
|
||||
$subscriber2UnsubscribeFactory = new StatisticsUnsubscribes($newsletter, $subscriberUnsubscribedByBot);
|
||||
$subscriber2UnsubscribeFactory->withCreatedAt(new DateTimeImmutable('2025-04-01 10:00:03'))->create();
|
||||
|
||||
// $subscriberUnsubscribedByUserManyClicks Has many clicks but they are spread in time so it's not suspicious
|
||||
$subscriber3ClickFactory = new StatisticsClicks($newsletterLink, $subscriberUnsubscribedByUserManyClicks);
|
||||
$subscriber3ClickFactory->withCreatedAt(new DateTimeImmutable('2025-04-01 10:00:00'))->create();
|
||||
$subscriber3ClickFactory = new StatisticsClicks($newsletterLink2, $subscriberUnsubscribedByUserManyClicks);
|
||||
$subscriber3ClickFactory->withCreatedAt(new DateTimeImmutable('2025-04-01 10:00:30'))->create();
|
||||
$subscriber3ClickFactory = new StatisticsClicks($newsletterLink3, $subscriberUnsubscribedByUserManyClicks);
|
||||
$subscriber3ClickFactory->withCreatedAt(new DateTimeImmutable('2025-04-01 10:00:50'))->create();
|
||||
$subscriber3UnsubscribeFactory = new StatisticsUnsubscribes($newsletter, $subscriberUnsubscribedByUserManyClicks);
|
||||
$subscriber3UnsubscribeFactory->withCreatedAt(new DateTimeImmutable('2025-04-01 10:00:55'))->create();
|
||||
|
||||
// $subscriberUnsubscribedByUserSingleClick Has one click and unsubscribed after the issue
|
||||
$subscriber4ClickFactory = new StatisticsClicks($newsletterLink, $subscriberUnsubscribedByUserSingleClick);
|
||||
$subscriber4ClickFactory->withCreatedAt(new DateTimeImmutable('2025-04-01 10:00:00'))->create();
|
||||
$subscriber4UnsubscribeFactory = new StatisticsUnsubscribes($newsletter, $subscriberUnsubscribedByUserSingleClick);
|
||||
$subscriber4UnsubscribeFactory->withCreatedAt(new DateTimeImmutable('2025-04-01 10:00:00'))->create();
|
||||
$this->migration->run();
|
||||
|
||||
$this->entityManager->refresh($subscriberUnsubscribedBefore);
|
||||
$this->entityManager->refresh($subscriberUnsubscribedByBot);
|
||||
$this->entityManager->refresh($subscriberUnsubscribedByUserManyClicks);
|
||||
$this->entityManager->refresh($subscriberUnsubscribedByUserSingleClick);
|
||||
$this->entityManager->refresh($subscriberSegmentBefore);
|
||||
$this->entityManager->refresh($subscriberSegmentByBot);
|
||||
$this->entityManager->refresh($subscriberSegmentByUserManyClicks);
|
||||
$this->entityManager->refresh($subscriberSegmentByUserSingleClick);
|
||||
|
||||
$this->assertEquals(SubscriberEntity::STATUS_UNSUBSCRIBED, $subscriberUnsubscribedBefore->getStatus());
|
||||
$this->assertEquals(SubscriberEntity::STATUS_SUBSCRIBED, $subscriberUnsubscribedByBot->getStatus());
|
||||
$this->assertEquals(SubscriberEntity::STATUS_UNSUBSCRIBED, $subscriberUnsubscribedByUserManyClicks->getStatus());
|
||||
$this->assertEquals(SubscriberEntity::STATUS_UNSUBSCRIBED, $subscriberUnsubscribedByUserSingleClick->getStatus());
|
||||
|
||||
$this->assertEquals(SubscriberEntity::STATUS_UNSUBSCRIBED, $subscriberSegmentBefore->getStatus());
|
||||
$this->assertEquals(SubscriberEntity::STATUS_SUBSCRIBED, $subscriberSegmentByBot->getStatus());
|
||||
$this->assertEquals(SubscriberEntity::STATUS_UNSUBSCRIBED, $subscriberSegmentByUserManyClicks->getStatus());
|
||||
$this->assertEquals(SubscriberEntity::STATUS_UNSUBSCRIBED, $subscriberSegmentByUserSingleClick->getStatus());
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@
|
||||
"d3-color@<3.1.0": ">=3.1.0",
|
||||
"debug@>=4.0.0 <4.3.1": ">=4.3.1",
|
||||
"decode-uri-component@<0.2.1": ">=0.2.1",
|
||||
"http-proxy-middleware": ">=2.0.9",
|
||||
"json5@<1.0.2": ">=1.0.2",
|
||||
"path-to-regexp@<0.1.12": "0.1.12",
|
||||
"react": "18.3.1",
|
||||
|
43
pnpm-lock.yaml
generated
43
pnpm-lock.yaml
generated
@ -13,6 +13,7 @@ overrides:
|
||||
d3-color@<3.1.0: '>=3.1.0'
|
||||
debug@>=4.0.0 <4.3.1: '>=4.3.1'
|
||||
decode-uri-component@<0.2.1: '>=0.2.1'
|
||||
http-proxy-middleware: '>=2.0.9'
|
||||
json5@<1.0.2: '>=1.0.2'
|
||||
path-to-regexp@<0.1.12: 0.1.12
|
||||
react: 18.3.1
|
||||
@ -8287,7 +8288,7 @@ packages:
|
||||
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||
engines: {node: '>= 6.0.0'}
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@ -8684,7 +8685,7 @@ packages:
|
||||
/axios@1.7.4:
|
||||
resolution: {integrity: sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==}
|
||||
dependencies:
|
||||
follow-redirects: 1.15.6
|
||||
follow-redirects: 1.15.6(debug@4.4.0)
|
||||
form-data: 4.0.0
|
||||
proxy-from-env: 1.1.0
|
||||
transitivePeerDependencies:
|
||||
@ -12095,7 +12096,7 @@ packages:
|
||||
resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
|
||||
dev: true
|
||||
|
||||
/follow-redirects@1.15.6:
|
||||
/follow-redirects@1.15.6(debug@4.4.0):
|
||||
resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==}
|
||||
engines: {node: '>=4.0'}
|
||||
peerDependencies:
|
||||
@ -12103,6 +12104,8 @@ packages:
|
||||
peerDependenciesMeta:
|
||||
debug:
|
||||
optional: true
|
||||
dependencies:
|
||||
debug: 4.4.0(supports-color@8.1.1)
|
||||
dev: true
|
||||
|
||||
/for-each@0.3.3:
|
||||
@ -12380,7 +12383,7 @@ packages:
|
||||
dependencies:
|
||||
basic-ftp: 5.0.5
|
||||
data-uri-to-buffer: 6.0.2
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0(supports-color@8.1.1)
|
||||
fs-extra: 11.2.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@ -12910,31 +12913,26 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/http-proxy-middleware@2.0.6(@types/express@4.17.21):
|
||||
resolution: {integrity: sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
peerDependencies:
|
||||
'@types/express': ^4.17.13
|
||||
peerDependenciesMeta:
|
||||
'@types/express':
|
||||
optional: true
|
||||
/http-proxy-middleware@3.0.5:
|
||||
resolution: {integrity: sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@types/express': 4.17.21
|
||||
'@types/http-proxy': 1.17.15
|
||||
http-proxy: 1.18.1
|
||||
debug: 4.4.0(supports-color@8.1.1)
|
||||
http-proxy: 1.18.1(debug@4.4.0)
|
||||
is-glob: 4.0.3
|
||||
is-plain-obj: 3.0.0
|
||||
is-plain-object: 5.0.0
|
||||
micromatch: 4.0.8
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/http-proxy@1.18.1:
|
||||
/http-proxy@1.18.1(debug@4.4.0):
|
||||
resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
dependencies:
|
||||
eventemitter3: 4.0.7
|
||||
follow-redirects: 1.15.6
|
||||
follow-redirects: 1.15.6(debug@4.4.0)
|
||||
requires-port: 1.0.0
|
||||
transitivePeerDependencies:
|
||||
- debug
|
||||
@ -15567,7 +15565,7 @@ packages:
|
||||
dependencies:
|
||||
'@tootallnate/quickjs-emscripten': 0.23.0
|
||||
agent-base: 7.1.1
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0(supports-color@8.1.1)
|
||||
get-uri: 6.0.3
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.5
|
||||
@ -16443,7 +16441,7 @@ packages:
|
||||
engines: {node: '>= 14'}
|
||||
dependencies:
|
||||
agent-base: 7.1.1
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0(supports-color@8.1.1)
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.5
|
||||
lru-cache: 7.18.3
|
||||
@ -17920,7 +17918,7 @@ packages:
|
||||
engines: {node: '>= 14'}
|
||||
dependencies:
|
||||
agent-base: 7.1.1
|
||||
debug: 4.3.4
|
||||
debug: 4.4.0(supports-color@8.1.1)
|
||||
socks: 2.8.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@ -19503,7 +19501,7 @@ packages:
|
||||
express: 4.21.0
|
||||
graceful-fs: 4.2.11
|
||||
html-entities: 2.5.2
|
||||
http-proxy-middleware: 2.0.6(@types/express@4.17.21)
|
||||
http-proxy-middleware: 3.0.5
|
||||
ipaddr.js: 2.2.0
|
||||
launch-editor: 2.8.1
|
||||
open: 8.4.2
|
||||
@ -19520,7 +19518,6 @@ packages:
|
||||
ws: 8.18.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- debug
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
@ -75,7 +75,7 @@ services:
|
||||
- mailhog-data:/mailhog-data
|
||||
|
||||
wordpress:
|
||||
image: wordpress:${WORDPRESS_IMAGE_VERSION:-6.8.0-php8.3}
|
||||
image: wordpress:${WORDPRESS_IMAGE_VERSION:-6.8.1-php8.3}
|
||||
container_name: wordpress_${CIRCLE_NODE_INDEX:-default}
|
||||
depends_on:
|
||||
smtp:
|
||||
|
Reference in New Issue
Block a user