Compare commits

..

2 Commits

Author SHA1 Message Date
github-actions[bot]
c3382d314e Update used WooCommerce plugin in Circle CI
- latest version: 9.6.1
 - previous version: 9.5.2
2025-02-13 01:52:47 +00:00
github-actions[bot]
81180caccb Update used WordPress images in Circle CI
- latest version: 6.7.2-php8.3
 - previous version: 6.6.2
2025-02-13 01:52:42 +00:00
26 changed files with 790 additions and 334 deletions

View File

@@ -197,7 +197,7 @@ jobs:
- run:
name: Download additional WP Plugins for tests
command: |
./do download:woo-commerce-zip 9.6.0
./do download:woo-commerce-zip 9.6.1
./do download:woo-commerce-subscriptions-zip 7.1.0
./do download:woo-commerce-memberships-zip 1.26.5
./do download:automate-woo-zip 6.1.5

71
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,71 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: 'CodeQL'
on:
push:
branches: [trunk]
pull_request:
# The branches below must be a subset of the branches above
branches: [trunk]
schedule:
- cron: '0 17 * * 4'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['javascript']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -0,0 +1,212 @@
name: Email Editor Package Tests
on:
push:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['7.4', '8.2']
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Cache Composer vendor dependencies for MailPoet
id: composer-mailpoet-cache
uses: actions/cache@v4
with:
path: mailpoet/vendor
key: ${{ runner.os }}-composer-mailpoet-${{ matrix.php-version }}-${{ hashFiles('mailpoet/composer.lock') }}-${{ hashFiles('mailpoet/composer.json') }}
- name: Cache Composer vendor-prefixed dependencies for MailPoet
id: vendor-prefixed-cache
uses: actions/cache@v4
with:
path: mailpoet/vendor-prefixed
key: ${{ runner.os }}-vendor-prefixed-${{ matrix.php-version }}-${{ hashFiles('mailpoet/prefixer/composer.lock') }}-${{ hashFiles('mailpoet/prefixer/composer.json') }}
- name: Cache Composer vendor for test environment
id: composer-tests-env-cache
uses: actions/cache@v4
with:
path: tests_env/vendor
key: ${{ runner.os }}-composer-mailpoet-${{ matrix.php-version }}-${{ hashFiles('tests_env/composer.lock') }}-${{ hashFiles('tests_env/composer.json') }}
- name: Cache Composer dependencies for Email Editor
id: composer-email-editor-cache
uses: actions/cache@v4
with:
path: packages/php/email-editor/vendor
key: ${{ runner.os }}-composer-email-editor-${{ matrix.php-version }}-${{ hashFiles('packages/php/email-editor/composer.lock') }}-${{ hashFiles('packages/php/email-editor/composer.json') }}
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: gd
- name: Install tools
run: |
COMPOSER_DEV_MODE=1 php tools/install.php
touch .env
working-directory: mailpoet
# Install Test Environment dependencies only if the cache was not hit
- name: Install test environment dependencies
if: steps.composer-tests-env-cache.outputs.cache-hit != 'true'
run: ../mailpoet/tools/vendor/composer.phar install
working-directory: tests_env
# Install MailPoet dependencies only if the cache was not hit
- name: Install mailpoet dependencies
if: |
steps.composer-mailpoet-cache.outputs.cache-hit != 'true' || steps.vendor-prefixed-cache.outputs.cache-hit != 'true'
run: ./tools/vendor/composer.phar install
working-directory: mailpoet
# Install Email Editor dependencies only if the cache was not hit
- name: Install email-editor dependencies
if: steps.composer-email-editor-cache.outputs.cache-hit != 'true'
run: ../../../mailpoet/tools/vendor/composer.phar install
working-directory: packages/php/email-editor
# Dump Email Editor autoload
# This is needed to refresh classmap autoload when the composer cache is hit
- name: Dump email-editor autoload
run: ../../../mailpoet/tools/vendor/composer.phar dump-autoload
working-directory: packages/php/email-editor
# Dump MailPoet autoload
# This is needed to refresh classmap autoload when the composer cache is hit
- name: Dump MailPoet autoload
run: ./tools/vendor/composer.phar dump-autoload
working-directory: mailpoet
# Run Email Editor unit tests
- name: Run email-editor package unit tests
run: ../../../tests_env/vendor/bin/codecept build && ../../../mailpoet/tools/vendor/composer.phar unit-test
working-directory: packages/php/email-editor
- name: Run email-editor package integration tests
run: ../../../mailpoet/tools/vendor/composer.phar integration-test
working-directory: packages/php/email-editor
code-style:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Install tools
run: |
COMPOSER_DEV_MODE=1 php tools/install.php
touch .env
working-directory: mailpoet
- name: Install composer dependencies
run: ../../tools/vendor/composer.phar install
working-directory: mailpoet/tasks/code_sniffer
- name: Run code style check
run: ../../../mailpoet/tools/vendor/composer.phar code-style
working-directory: packages/php/email-editor
phpstan-static-analysis:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['7.4', '8.2']
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Cache Composer vendor dependencies for MailPoet
id: composer-mailpoet-cache
uses: actions/cache@v4
with:
path: mailpoet/vendor
key: ${{ runner.os }}-composer-mailpoet-${{ matrix.php-version }}-${{ hashFiles('mailpoet/composer.lock') }}-${{ hashFiles('mailpoet/composer.json') }}
- name: Cache Composer vendor-prefixed dependencies for MailPoet
id: vendor-prefixed-cache
uses: actions/cache@v4
with:
path: mailpoet/vendor-prefixed
key: ${{ runner.os }}-vendor-prefixed-${{ matrix.php-version }}-${{ hashFiles('mailpoet/prefixer/composer.lock') }}-${{ hashFiles('mailpoet/prefixer/composer.json') }}
- name: Cache Composer vendor for test environment
id: composer-tests-env-cache
uses: actions/cache@v4
with:
path: tests_env/vendor
key: ${{ runner.os }}-composer-mailpoet-${{ matrix.php-version }}-${{ hashFiles('tests_env/composer.lock') }}-${{ hashFiles('tests_env/composer.json') }}
- name: Cache Composer dependencies for Email Editor
id: composer-email-editor-cache
uses: actions/cache@v4
with:
path: packages/php/email-editor/vendor
key: ${{ runner.os }}-composer-email-editor-${{ matrix.php-version }}-${{ hashFiles('packages/php/email-editor/composer.lock') }}-${{ hashFiles('packages/php/email-editor/composer.json') }}
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: gd
- name: Install tools
run: |
COMPOSER_DEV_MODE=1 php tools/install.php
touch .env
working-directory: mailpoet
# Install Test Environment dependencies only if the cache was not hit
- name: Install test environment dependencies
if: steps.composer-tests-env-cache.outputs.cache-hit != 'true'
run: ../mailpoet/tools/vendor/composer.phar install
working-directory: tests_env
# Install MailPoet dependencies only if the cache was not hit
- name: Install mailpoet dependencies
if: |
steps.composer-mailpoet-cache.outputs.cache-hit != 'true' || steps.vendor-prefixed-cache.outputs.cache-hit != 'true'
run: ./tools/vendor/composer.phar install
working-directory: mailpoet
# Install Email Editor dependencies only if the cache was not hit
- name: Install email-editor dependencies
if: steps.composer-email-editor-cache.outputs.cache-hit != 'true'
run: ../../../mailpoet/tools/vendor/composer.phar install
working-directory: packages/php/email-editor
- name: Install composer dependencies
run: ../../tools/vendor/composer.phar install
working-directory: mailpoet/tasks/phpstan
# Dump Email Editor autoload
# This is needed to refresh classmap autoload when the composer cache is hit
- name: Dump email-editor autoload
run: ../../../mailpoet/tools/vendor/composer.phar dump-autoload
working-directory: packages/php/email-editor
# Dump MailPoet autoload
# This is needed to refresh classmap autoload when the composer cache is hit
- name: Dump MailPoet autoload
run: ./tools/vendor/composer.phar dump-autoload
working-directory: mailpoet
- name: Run code phpstan
run: ../../../mailpoet/tools/vendor/composer.phar phpstan -- --php-version=${{ matrix.php-version == '7.4' && '70400' || '80200' }}
working-directory: packages/php/email-editor

View File

@@ -1,48 +0,0 @@
name: Make release
on:
push:
tags:
- '*' # Trigger on any tag push
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Pre-reqs
run: |
sudo apt update
sudo apt install -y php php-symfony composer php-cli php-gd php-mysql golang
- name: Prepare for build
run: |
cd mailpoet || { echo "Directory 'mailpoet' not found"; exit 1; }
cp .env.sample .env
- name: Update Composer dependencies
run: |
composer update
- name: Install pnpm globally
run: |
npm install -g pnpm
- name: Run the build script
run: |
sh build.sh
- name: Move built zip file
run: |
mkdir -p ../output
mv mailpoet.zip ../output
- name: Upload Release
uses: https://gitea.com/actions/release-action@main
with:
files: |-
output/mailpoet.zip
api_key: '${{secrets.RELEASE_SMITH_TOKEN}}'

View File

@@ -0,0 +1,182 @@
name: Check new versions of plugins and WordPress
on:
schedule:
- cron: '0 6 * * 1' # At 06:00 on Monday
workflow_dispatch: # Allows manual triggering
jobs:
check-versions:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3' # Specify the PHP version you want to use
# Updating used WordPress
- name: Check WordPress Docker Versions
run: php .github/workflows/scripts/check_wordpress_versions.php
- name: Check for WordPress changes
id: check_wp_changes
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
if [ "$(git status --porcelain)" != "" ]; then
echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
echo "WORDPRESS_CHANGES=true" >> $GITHUB_ENV
fi
- name: Get WordPress versions from files
id: get_wp_versions
run: |
echo "WORDPRESS_LATEST_VERSION=$(cat /tmp/latest_wordpress_version.txt)" >> $GITHUB_ENV
echo "WORDPRESS_PREVIOUS_VERSION=$(cat /tmp/previous_wordpress_version.txt)" >> $GITHUB_ENV
- name: Commit WordPress changes
if: env.WORDPRESS_CHANGES == 'true'
run: |
git add .
git commit -m $'Update used WordPress images in Circle CI\n\n - latest version: ${{ env.WORDPRESS_LATEST_VERSION }}\n - previous version: ${{ env.WORDPRESS_PREVIOUS_VERSION }}'
# Updating used WooCommerce plugin
- name: Check WooCommerce Versions
run: php .github/workflows/scripts/check_woocommerce_versions.php
- name: Check for WooCommerce changes
id: check_wc_changes
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
if [ "$(git status --porcelain)" != "" ]; then
echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
echo "WOOCOMMERCE_CHANGES=true" >> $GITHUB_ENV
fi
- name: Get WooCommerce versions from files
id: get_wc_versions
run: |
echo "WOOCOMMERCE_LATEST_VERSION=$(cat /tmp/latest_woocommerce_version.txt)" >> $GITHUB_ENV
echo "WOOCOMMERCE_PREVIOUS_VERSION=$(cat /tmp/previous_woocommerce_version.txt)" >> $GITHUB_ENV
- name: Commit WooCommerce changes
if: env.WOOCOMMERCE_CHANGES == 'true'
run: |
git add .
git commit -m $'Update used WooCommerce plugin in Circle CI\n\n - latest version: ${{ env.WOOCOMMERCE_LATEST_VERSION }}\n - previous version: ${{ env.WOOCOMMERCE_PREVIOUS_VERSION }}'
# Updating used Automate Woo plugin
- name: Check Automate Woo Versions
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: php .github/workflows/scripts/check_automate_woo_versions.php
- name: Check for Automate Woo changes
id: check_aw_changes
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
if [ "$(git status --porcelain)" != "" ]; then
echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
echo "AUTOMATE_WOO_CHANGES=true" >> $GITHUB_ENV
fi
- name: Get Automate Woo versions from files
id: get_aw_versions
run: |
echo "AUTOMATE_WOO_LATEST_VERSION=$(cat /tmp/latest_automate_woo_version.txt)" >> $GITHUB_ENV
echo "AUTOMATE_WOO_PREVIOUS_VERSION=$(cat /tmp/previous_automate_woo_version.txt)" >> $GITHUB_ENV
- name: Commit Automate Woo changes
if: env.AUTOMATE_WOO_CHANGES == 'true'
run: |
git add .
git commit -m $'Update used Automate Woo plugin in Circle CI\n\n - latest version: ${{ env.AUTOMATE_WOO_LATEST_VERSION }}\n - previous version: ${{ env.AUTOMATE_WOO_PREVIOUS_VERSION }}'
# Updating used WooCommerce Subscriptions plugin
- name: Check WooCommerce Subscriptions Versions
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: php .github/workflows/scripts/check_woocommerce_subscriptions_versions.php
- name: Check for WooCommerce Subscriptions changes
id: check_ws_changes
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
if [ "$(git status --porcelain)" != "" ]; then
echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
echo "SUBSCRIPTIONS_CHANGES=true" >> $GITHUB_ENV
fi
- name: Get WooCommerce Subscriptions versions from files
id: get_ws_versions
run: |
echo "WOOCOMMERCE_SUBSCRIPTIONS_LATEST_VERSION=$(cat /tmp/latest_woocommerce_subscriptions_version.txt)" >> $GITHUB_ENV
echo "WOOCOMMERCE_SUBSCRIPTIONS_PREVIOUS_VERSION=$(cat /tmp/previous_woocommerce_subscriptions_version.txt)" >> $GITHUB_ENV
- name: Commit WooCommerce Subscriptions changes
if: env.SUBSCRIPTIONS_CHANGES == 'true'
run: |
git add .
git commit -m $'Update used WooCommerce Subscriptions plugin in Circle CI\n\n - latest version: ${{ env.WOOCOMMERCE_SUBSCRIPTIONS_LATEST_VERSION }}\n - previous version: ${{ env.WOOCOMMERCE_SUBSCRIPTIONS_PREVIOUS_VERSION }}'
# Updating used WooCommerce Memberships plugin
- name: Check WooCommerce Memberships Versions
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: php .github/workflows/scripts/check_woocommerce_memberships_versions.php
- name: Check for WooCommerce Memberships changes
id: check_wm_changes
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
if [ "$(git status --porcelain)" != "" ]; then
echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
echo "MEMBERSHIPS_CHANGES=true" >> $GITHUB_ENV
fi
- name: Get WooCommerce Memberships versions from files
id: get_wm_versions
run: |
echo "WOOCOMMERCE_MEMBERSHIPS_LATEST_VERSION=$(cat /tmp/latest_woocommerce_memberships_version.txt)" >> $GITHUB_ENV
echo "WOOCOMMERCE_MEMBERSHIPS_PREVIOUS_VERSION=$(cat /tmp/previous_woocommerce_memberships_version.txt)" >> $GITHUB_ENV
- name: Commit WooCommerce Memberships changes
if: env.MEMBERSHIPS_CHANGES == 'true'
run: |
git add .
git commit -m $'Update used WooCommerce Memberships plugin in Circle CI\n\n - latest version: ${{ env.WOOCOMMERCE_MEMBERSHIPS_LATEST_VERSION }}\n - previous version: ${{ env.WOOCOMMERCE_MEMBERSHIPS_PREVIOUS_VERSION }}'
# Push all changes at the end if any changes were detected
#
# For local testing with act tool add following:
# env:
# GH_PAT: ${{ secrets.GH_TOKEN }}
# run: |
# git remote set-url origin https://${GH_PAT}@github.com/mailpoet/mailpoet
# git push -f origin HEAD:refs/heads/update-plugins-and-wordpress-test
- name: Push changes
if: env.CHANGES_DETECTED == 'true'
run: |
git push -f origin HEAD:refs/heads/update-plugins-and-wordpress
# Create a pull request if there are changes
- name: Create Pull Request
if: env.CHANGES_DETECTED == 'true'
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.GH_TOKEN }}
branch: update-plugins-and-wordpress
title: Update WordPress and plugins in CI jobs
base: trunk
labels: automated, check-versions
body: |
1. If all checks passed, you can merge this PR.
2. If the build failed, please investigate the failure and either address the issues or delegate the job. Then, make sure these changes are merged.

View File

@@ -0,0 +1,27 @@
name: Add link to WordPress Playground preview
on:
pull_request:
types: [opened, reopened, synchronize]
jobs:
add-wp-playground-link:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Check and append description
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_NUMBER="${{ github.event.pull_request.number }}"
BRANCH_NAME="${{ github.head_ref }}"
DESCRIPTION="$(gh pr view $PR_NUMBER --json body -q .body)"
HEADING="## Preview"
CONTENT="$(printf "${HEADING}\n\n[Preview in WordPress Playground](https://account.mailpoet.com/playground/new/branch:${BRANCH_NAME})\n\n_The latest successful build from \`${BRANCH_NAME}\` will be used. If none is available, the link won't work._")"
if [[ "$DESCRIPTION" != *"$HEADING"* ]]; then
gh pr edit $PR_NUMBER --body "$(printf "${DESCRIPTION}\n\n${CONTENT}")"
fi

30
.woodpecker.yml Normal file
View File

@@ -0,0 +1,30 @@
clone:
git:
image: woodpeckerci/plugin-git
settings:
depth: 1
steps:
build:
image: node:current-bookworm-slim
commands:
- apt update
- apt install php php-symfony bash -y
- npm install pnpm
- cd mailpoet
- bash build.sh
- mkdir ../output
- mv mailpoet.zip ../output
- cd ..
release:
image: woodpeckerci/plugin-gitea-release:latest
settings:
base_url: https://git.cavemanon.xyz
api_key:
from_secret: releasesmithapikey
files: "output/"
prerelease: false
title: "${CI_COMMIT_TAG}"
when:
- event: tag

View File

@@ -1,142 +0,0 @@
import { ExternalLink } from '@wordpress/components';
import { select, dispatch } from '@wordpress/data';
import { store as coreDataStore, useEntityProp } from '@wordpress/core-data';
import { store as editorStore } from '@wordpress/editor';
import { __ } from '@wordpress/i18n';
import { createInterpolateElement } from '@wordpress/element';
import classnames from 'classnames';
const previewTextMaxLength = 150;
const previewTextRecommendedLength = 80;
export function EmailSidebarExtensionBody({ RichTextWithButton }) {
const [mailpoetEmailData] = useEntityProp(
'postType',
'mailpoet_email',
'mailpoet_data',
);
const updateEmailMailPoetProperty = (name: string, value: string) => {
const postId = select(editorStore).getCurrentPostId();
const currentPostType = 'mailpoet_email'; // only for mailpoet_email post-type
const editedPost = select(coreDataStore).getEditedEntityRecord(
'postType',
currentPostType,
postId,
);
// @ts-expect-error Property 'mailpoet_data' does not exist on type 'Updatable<Attachment<any>>'.
const mailpoetData = editedPost?.mailpoet_data || {};
void dispatch(coreDataStore).editEntityRecord(
'postType',
currentPostType,
postId,
{
mailpoet_data: {
...mailpoetData,
[name]: value,
},
},
);
};
const subjectHelp = createInterpolateElement(
__(
'Use personalization tags to personalize your email, or learn more about <bestPracticeLink>best practices</bestPracticeLink> and using <emojiLink>emoji in subject lines</emojiLink>.',
'mailpoet',
),
{
bestPracticeLink: (
// eslint-disable-next-line jsx-a11y/anchor-has-content, jsx-a11y/control-has-associated-label
<a
href="https://www.mailpoet.com/blog/17-email-subject-line-best-practices-to-boost-engagement/"
target="_blank"
rel="noopener noreferrer"
/>
),
emojiLink: (
// eslint-disable-next-line jsx-a11y/anchor-has-content, jsx-a11y/control-has-associated-label
<a
href="https://www.mailpoet.com/blog/tips-using-emojis-in-subject-lines/"
target="_blank"
rel="noopener noreferrer"
/>
),
},
);
const previewTextLength = mailpoetEmailData?.preheader?.length ?? 0;
const preheaderHelp = createInterpolateElement(
__(
'<link>This text</link> will appear in the inbox, underneath the subject line.',
'mailpoet',
),
{
link: (
// eslint-disable-next-line jsx-a11y/anchor-has-content, jsx-a11y/control-has-associated-label
<a
href={new URL(
'article/418-preview-text',
'https://kb.mailpoet.com/',
).toString()}
key="preview-text-kb"
target="_blank"
rel="noopener noreferrer"
/>
),
},
);
return (
<>
<RichTextWithButton
attributeName="subject"
attributeValue={mailpoetEmailData?.subject}
updateProperty={updateEmailMailPoetProperty}
label={__('Subject', 'mailpoet')}
labelSuffix={
<ExternalLink href="https://kb.mailpoet.com/article/435-a-guide-to-personalisation-tags-for-tailored-newsletters#list">
{__('Guide', 'mailpoet')}
</ExternalLink>
}
help={subjectHelp}
placeholder={__('Eg. The summer sale is here!', 'mailpoet')}
/>
<br />
<RichTextWithButton
attributeName="preheader"
attributeValue={mailpoetEmailData?.preheader}
updateProperty={updateEmailMailPoetProperty}
label={__('Preview text', 'mailpoet')}
labelSuffix={
<span
className={classnames(
'mailpoet-settings-panel__preview-text-length',
{
'mailpoet-settings-panel__preview-text-length-warning':
previewTextLength > previewTextRecommendedLength,
'mailpoet-settings-panel__preview-text-length-error':
previewTextLength > previewTextMaxLength,
},
)}
>
{previewTextLength}/{previewTextMaxLength}
</span>
}
help={preheaderHelp}
placeholder={__(
"Add a preview text to capture subscribers' attention and increase open rates.",
'mailpoet',
)}
/>
</>
);
}
export function EmailSidebarExtension(RichTextWithButton: JSX.Element) {
return <EmailSidebarExtensionBody RichTextWithButton={RichTextWithButton} />;
}

View File

@@ -5,7 +5,6 @@
import { addFilter, addAction } from '@wordpress/hooks';
import { MailPoet } from 'mailpoet';
import { withSatismeterSurvey } from './satismeter-survey';
import { EmailSidebarExtension } from './email-sidebar-extension';
import './index.scss';
import { useValidationRules } from './validate-email-content';
@@ -13,12 +12,10 @@ addFilter('mailpoet_email_editor_wrap_editor_component', 'mailpoet', (editor) =>
withSatismeterSurvey(editor),
);
// validate email editor content using the defined validation rules
// content is first validated when the "Send" button is clicked and revalidated on "Save Draft"
addFilter(
'mailpoet_email_editor_content_validation_rules',
'mailpoet',
() => useValidationRules(), // returns a memorized set of rules (array of rules)
(validationRules: []) => [...validationRules, ...useValidationRules()],
);
const EVENTS_TO_TRACK = [
@@ -56,22 +53,3 @@ addFilter(
'mailpoet',
() => !!window.mailpoet_analytics_enabled,
);
// integration point for settings sidebar
addFilter(
'mailpoet_email_editor_setting_sidebar_extension_component',
'mailpoet',
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
(RichTextWithButton) => EmailSidebarExtension.bind(null, RichTextWithButton),
);
// use mailpoet data subject if available
addFilter(
'mailpoet_email_editor_preferred_template_title',
'mailpoet',
(...args) => {
const [, post] = args;
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return post?.mailpoet_data?.subject || ''; // use MailPoet subject as title
},
);

View File

@@ -64,14 +64,12 @@ export function useValidationRules() {
label: __('Insert link', 'mailpoet'),
onClick: () => {
if (!hasFooter) {
// update the email content
void dispatch(blockEditorStore).insertBlock(
linksParagraphBlock,
undefined,
contentBlockId,
);
} else {
// update the template
void dispatch(coreDataStore).editEntityRecord(
'postType',
'wp_template',

View File

@@ -57,17 +57,17 @@ echo '[BUILD] Fetching prefixed production libraries'
# Remove Doctrinne Annotations (no need since generated metadata are packed)
# Should be removed before `dump-autoload` to not include the annotations classes on the autoloader.
#rm -rf vendor-prefixed/doctrine/annotations
rm -rf vendor-prefixed/doctrine/annotations
# Remove DI Container files used for container dump (no need since generated metadata are packed)
# Should be removed before `dump-autoload` to not include these classes in the autoloader.
echo '[BUILD] Removing DI Container development dependencies'
#rm -rf vendor-prefixed/symfony/dependency-injection/Compiler
#rm -rf vendor-prefixed/symfony/dependency-injection/Config
#rm -rf vendor-prefixed/symfony/dependency-injection/Dumper
#rm -rf vendor-prefixed/symfony/dependency-injection/Loader
#rm -rf vendor-prefixed/symfony/dependency-injection/LazyProxy
#rm -rf vendor-prefixed/symfony/dependency-injection/Extension
rm -rf vendor-prefixed/symfony/dependency-injection/Compiler
rm -rf vendor-prefixed/symfony/dependency-injection/Config
rm -rf vendor-prefixed/symfony/dependency-injection/Dumper
rm -rf vendor-prefixed/symfony/dependency-injection/Loader
rm -rf vendor-prefixed/symfony/dependency-injection/LazyProxy
rm -rf vendor-prefixed/symfony/dependency-injection/Extension
./tools/vendor/composer.phar dump-autoload

View File

@@ -35,7 +35,7 @@ class EmailEditorPreviewEmail {
}
private function validateData($data) {
if (empty($data['email']) || empty($data['postId'])) {
if (empty($data['email']) || empty($data['postId']) || empty($data['newsletterId'])) {
throw new \InvalidArgumentException(esc_html__('Missing required data', 'mailpoet'));
}
@@ -50,9 +50,9 @@ class EmailEditorPreviewEmail {
* @throws \Exception
*/
private function fetchNewsletter($postData): NewsletterEntity {
$newsletter = $this->newslettersRepository->findOneBy(['wpPost' => (int)$postData['postId']]);
$newsletter = $this->newslettersRepository->findOneById((int)$postData['newsletterId']);
if (!$newsletter instanceof NewsletterEntity) {
if (!$newsletter) {
throw new \Exception(esc_html__('This email does not exist.', 'mailpoet'));
}

View File

@@ -55,8 +55,7 @@ class CreateAndSendEmailUsingGutenbergCest {
$i->click('Save Draft');
$i->waitForText('Saved');
$i->waitForText('Email saved!');
$i->click('[aria-label="Close sidebar"]'); // close the sidebar. It sometimes interferes with the send button click
$i->click('[data-automation-id="email_editor_send_button"]');
$i->click('Send');
$i->waitForElement('[name="subject"]');
$subject = $i->grabValueFrom('[name="subject"]');
verify($subject)->equals('My New Subject');

View File

@@ -35,7 +35,8 @@ export function MoreMenu(): JSX.Element {
editorCurrentPostType,
'status'
);
const { saveEditedEmail } = useDispatch( storeName );
const { saveEditedEmail, updateEmailMailPoetProperty } =
useDispatch( storeName );
const goToListings = () => {
window.location.href = urls.listings;
};
@@ -131,6 +132,10 @@ export function MoreMenu(): JSX.Element {
<MenuItem
onClick={ async () => {
await setStatus( 'draft' );
await updateEmailMailPoetProperty(
'deleted_at',
''
);
await saveEditedEmail();
recordEvent(
'header_more_menu_restore_from_trash_button_clicked'

View File

@@ -63,7 +63,6 @@ export function SendButton( { validateContent, isContentInvalid } ) {
}
} }
disabled={ isDisabled }
data-automation-id="email_editor_send_button"
>
{ label }
</Button>

View File

@@ -18,7 +18,7 @@ type Replacement = {
function getChildElement( rootElement: HTMLElement ): HTMLElement | null {
let currentElement: HTMLElement | null = rootElement;
while ( currentElement && currentElement?.children?.length > 0 ) {
while ( currentElement && currentElement.children.length > 0 ) {
// Traverse into the first child element
currentElement = currentElement.children[ 0 ] as HTMLElement;
}

View File

@@ -1,10 +1,10 @@
/**
* External dependencies
*/
import type { ReactNode } from 'react';
import { BaseControl, Button } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useDispatch, useSelect } from '@wordpress/data';
import { useCallback, useRef, useState } from '@wordpress/element';
import { useEntityProp } from '@wordpress/core-data';
import { create, insert, toHTMLString } from '@wordpress/rich-text';
import { RichText } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';
@@ -17,32 +17,25 @@ import {
getCursorPosition,
replacePersonalizationTagsWithHTMLComments,
} from './rich-text-utils';
import { storeName } from '../../store';
import { storeName, editorCurrentPostType } from '../../store';
import { PersonalizationTagsPopover } from './personalization-tags-popover';
import { recordEvent, recordEventOnce } from '../../events';
type Props = {
label: string;
labelSuffix?: ReactNode;
help?: ReactNode;
placeholder: string;
attributeName: string;
attributeValue?: string;
updateProperty: (
theAttributeName: string,
theUpdatedValue: string
) => void;
};
export function RichTextWithButton( {
label,
labelSuffix,
help,
placeholder,
attributeName,
attributeValue,
updateProperty = () => {},
}: Props ) {
} ) {
const [ mailpoetEmailData ] = useEntityProp(
'postType',
editorCurrentPostType,
'mailpoet_data'
);
const { updateEmailMailPoetProperty } = useDispatch( storeName );
const [ selectionRange, setSelectionRange ] = useState( null );
const [ isModalOpened, setIsModalOpened ] = useState( false );
const list = useSelect(
@@ -68,11 +61,11 @@ export function RichTextWithButton( {
const updatedValue = toHTMLString( { value: richTextValue } );
// Update the corresponding property
updateProperty( attributeName, updatedValue );
updateEmailMailPoetProperty( attributeName, updatedValue );
setSelectionRange( null );
},
[ attributeName, updateProperty ]
[ attributeName, updateEmailMailPoetProperty ]
);
const finalLabel = (
@@ -97,13 +90,13 @@ export function RichTextWithButton( {
</>
);
if ( ! attributeName ) {
if ( ! mailpoetEmailData ) {
return null;
}
return (
<BaseControl
id="" // See https://github.com/mailpoet/mailpoet/pull/6089#discussion_r1952126850 to understand why the ID is empty
id={ `mailpoet-settings-panel__${ attributeName }` }
label={ finalLabel }
className={ `mailpoet-settings-panel__${ attributeName }-text` }
help={ help }
@@ -114,7 +107,7 @@ export function RichTextWithButton( {
onInsert={ ( value ) => {
handleInsertPersonalizationTag(
value,
attributeValue ?? '',
mailpoetEmailData[ attributeName ] ?? '',
selectionRange
);
setIsModalOpened( false );
@@ -132,13 +125,17 @@ export function RichTextWithButton( {
<PersonalizationTagsPopover
contentRef={ richTextRef }
onUpdate={ ( originalTag, updatedTag ) => {
const currentValue = attributeValue ?? '';
const currentValue =
mailpoetEmailData[ attributeName ] ?? '';
// When we update the tag, we need to add brackets to the tag, because the popover removes them
const updatedContent = currentValue.replace(
`<!--[${ originalTag }]-->`,
`<!--[${ updatedTag }]-->`
);
updateProperty( attributeName, updatedContent );
updateEmailMailPoetProperty(
attributeName,
updatedContent
);
} }
/>
<RichText
@@ -147,17 +144,26 @@ export function RichTextWithButton( {
placeholder={ placeholder }
onFocus={ () => {
setSelectionRange(
getCursorPosition( richTextRef, attributeValue ?? '' )
getCursorPosition(
richTextRef,
mailpoetEmailData[ attributeName ] ?? ''
)
);
} }
onKeyUp={ () => {
setSelectionRange(
getCursorPosition( richTextRef, attributeValue ?? '' )
getCursorPosition(
richTextRef,
mailpoetEmailData[ attributeName ] ?? ''
)
);
} }
onClick={ () => {
setSelectionRange(
getCursorPosition( richTextRef, attributeValue ?? '' )
getCursorPosition(
richTextRef,
mailpoetEmailData[ attributeName ] ?? ''
)
);
} }
onChange={ ( value ) => {
@@ -165,7 +171,7 @@ export function RichTextWithButton( {
value ?? '',
list
);
updateProperty( attributeName, value );
updateEmailMailPoetProperty( attributeName, value );
recordEventOnce(
'rich_text_with_button_input_field_updated',
{
@@ -173,7 +179,7 @@ export function RichTextWithButton( {
}
);
} }
value={ attributeValue ?? '' }
value={ mailpoetEmailData[ attributeName ] ?? '' }
data-automation-id={ `email_${ attributeName }` }
/>
</BaseControl>

View File

@@ -4,7 +4,7 @@
import { Button, Modal, TextControl } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { check, Icon } from '@wordpress/icons';
import { __, sprintf } from '@wordpress/i18n';
import { __ } from '@wordpress/i18n';
import {
useEffect,
useRef,
@@ -13,23 +13,19 @@ import {
} from '@wordpress/element';
import { ENTER } from '@wordpress/keycodes';
import { isEmail } from '@wordpress/url';
import { applyFilters } from '@wordpress/hooks';
import { useEntityProp } from '@wordpress/core-data';
/**
* Internal dependencies
*/
import {
MailPoetEmailData,
SendingPreviewStatus,
storeName,
editorCurrentPostType,
} from '../../store';
import { recordEvent, recordEventOnce } from '../../events';
const sendingMethodConfigurationLink = applyFilters(
'mailpoet_email_editor_check_sending_method_configuration_link',
'admin.php?page=mailpoet-settings#mta'
) as string;
function RawSendPreviewEmail() {
const sendToRef = useRef( null );
@@ -44,11 +40,19 @@ function RawSendPreviewEmail() {
isSendingPreviewEmail,
sendingPreviewStatus,
isModalOpened,
errorMessage,
} = useSelect( ( select ) => select( storeName ).getPreviewState(), [] );
const [ mailpoetEmailData ] = useEntityProp(
'postType',
editorCurrentPostType,
'mailpoet_data'
) as [ MailPoetEmailData, unknown, unknown ];
const handleSendPreviewEmail = () => {
void requestSendingNewsletterPreview( previewToEmail );
void requestSendingNewsletterPreview(
mailpoetEmailData.id,
previewToEmail
);
};
const closeCallback = () => {
@@ -77,48 +81,33 @@ function RawSendPreviewEmail() {
>
{ sendingPreviewStatus === SendingPreviewStatus.ERROR ? (
<div className="mailpoet-send-preview-modal-notice-error">
<p>
{ __(
'Sorry, we were unable to send this email.',
'mailpoet'
) }
</p>
<strong>
{ errorMessage &&
sprintf(
// translators: %s is an error message.
__( 'Error: %s', 'mailpoet' ),
errorMessage
) }
</strong>
{ __(
'Sorry, we were unable to send this email.',
'mailpoet'
) }
<ul>
<li>
{ sendingMethodConfigurationLink &&
createInterpolateElement(
__(
'Please check your <link>sending method configuration</link> with your hosting provider.',
'mailpoet'
{ createInterpolateElement(
__(
'Please check your <link>sending method configuration</link> with your hosting provider.',
'mailpoet'
),
{
link: (
// eslint-disable-next-line jsx-a11y/anchor-has-content, jsx-a11y/control-has-associated-label
<a
href="admin.php?page=mailpoet-settings#mta"
target="_blank"
rel="noopener noreferrer"
onClick={ () =>
recordEvent(
'send_preview_email_modal_check_sending_method_configuration_link_clicked'
)
}
/>
),
{
link: (
// eslint-disable-next-line jsx-a11y/anchor-has-content, jsx-a11y/control-has-associated-label
<a
href={
sendingMethodConfigurationLink
}
target="_blank"
rel="noopener noreferrer"
onClick={ () =>
recordEvent(
'send_preview_email_modal_check_sending_method_configuration_link_clicked'
)
}
/>
),
}
) }
}
) }
</li>
<li>
{ createInterpolateElement(
@@ -130,7 +119,10 @@ function RawSendPreviewEmail() {
link: (
// eslint-disable-next-line jsx-a11y/anchor-has-content, jsx-a11y/control-has-associated-label
<a
href={ `https://account.mailpoet.com/?s=1&g=1&utm_source=mailpoet_email_editor&utm_medium=plugin&utm_source_platform=${ editorCurrentPostType }` }
href={ new URL(
'free-plan',
'https://www.mailpoet.com/'
).toString() }
key="sign-up-for-free"
target="_blank"
rel="noopener noreferrer"

View File

@@ -1,22 +1,92 @@
/**
* External dependencies
*/
import { PanelBody } from '@wordpress/components';
import { ExternalLink, PanelBody } from '@wordpress/components';
import { useEntityProp } from '@wordpress/core-data';
import { __ } from '@wordpress/i18n';
import { applyFilters } from '@wordpress/hooks';
import { createInterpolateElement } from '@wordpress/element';
import classnames from 'classnames';
/**
* Internal dependencies
*/
import { editorCurrentPostType } from '../../store';
import { recordEvent } from '../../events';
import { RichTextWithButton } from '../personalization-tags/rich-text-with-button';
const SidebarExtensionComponent = applyFilters(
'mailpoet_email_editor_setting_sidebar_extension_component',
RichTextWithButton
) as () => JSX.Element;
const previewTextMaxLength = 150;
const previewTextRecommendedLength = 80;
export function DetailsPanel() {
const [ mailpoetEmailData ] = useEntityProp(
'postType',
editorCurrentPostType,
'mailpoet_data'
);
const subjectHelp = createInterpolateElement(
__(
'Use personalization tags to personalize your email, or learn more about <bestPracticeLink>best practices</bestPracticeLink> and using <emojiLink>emoji in subject lines</emojiLink>.',
'mailpoet'
),
{
bestPracticeLink: (
// eslint-disable-next-line jsx-a11y/anchor-has-content, jsx-a11y/control-has-associated-label
<a
href="https://www.mailpoet.com/blog/17-email-subject-line-best-practices-to-boost-engagement/"
target="_blank"
rel="noopener noreferrer"
onClick={ () =>
recordEvent(
'details_panel_subject_help_best_practice_link_clicked'
)
}
/>
),
emojiLink: (
// eslint-disable-next-line jsx-a11y/anchor-has-content, jsx-a11y/control-has-associated-label
<a
href="https://www.mailpoet.com/blog/tips-using-emojis-in-subject-lines/"
target="_blank"
rel="noopener noreferrer"
onClick={ () =>
recordEvent(
'details_panel_subject_help_emoji_in_subject_lines_link_clicked'
)
}
/>
),
}
);
const previewTextLength = mailpoetEmailData?.preheader?.length ?? 0;
const preheaderHelp = createInterpolateElement(
__(
'<link>This text</link> will appear in the inbox, underneath the subject line.',
'mailpoet'
),
{
link: (
// eslint-disable-next-line jsx-a11y/anchor-has-content, jsx-a11y/control-has-associated-label
<a
href={ new URL(
'article/418-preview-text',
'https://kb.mailpoet.com/'
).toString() }
key="preview-text-kb"
target="_blank"
rel="noopener noreferrer"
onClick={ () =>
recordEvent(
'details_panel_preheader_help_text_link_clicked'
)
}
/>
),
}
);
return (
<PanelBody
title={ __( 'Details', 'mailpoet' ) }
@@ -25,7 +95,50 @@ export function DetailsPanel() {
recordEvent( 'details_panel_body_toggle', { opened: data } )
}
>
<>{ <SidebarExtensionComponent /> }</>
<RichTextWithButton
attributeName="subject"
label={ __( 'Subject', 'mailpoet' ) }
labelSuffix={
<ExternalLink
href="https://kb.mailpoet.com/article/435-a-guide-to-personalisation-tags-for-tailored-newsletters#list"
onClick={ () =>
recordEvent(
'details_panel_personalisation_tags_guide_link_clicked'
)
}
>
{ __( 'Guide', 'mailpoet' ) }
</ExternalLink>
}
help={ subjectHelp }
placeholder={ __( 'Eg. The summer sale is here!', 'mailpoet' ) }
/>
<RichTextWithButton
attributeName="preheader"
label={ __( 'Preview text', 'mailpoet' ) }
labelSuffix={
<span
className={ classnames(
'mailpoet-settings-panel__preview-text-length',
{
'mailpoet-settings-panel__preview-text-length-warning':
previewTextLength >
previewTextRecommendedLength,
'mailpoet-settings-panel__preview-text-length-error':
previewTextLength > previewTextMaxLength,
}
) }
>
{ previewTextLength }/{ previewTextMaxLength }
</span>
}
help={ preheaderHelp }
placeholder={ __(
"Add a preview text to capture subscribers' attention and increase open rates.",
'mailpoet'
) }
/>
</PanelBody>
);
}

View File

@@ -5,7 +5,6 @@ import { useMemo } from '@wordpress/element';
import { parse } from '@wordpress/blocks';
import { BlockInstance } from '@wordpress/blocks/index';
import { useSelect } from '@wordpress/data';
import { applyFilters } from '@wordpress/hooks';
/**
* Internal dependencies
@@ -164,11 +163,6 @@ export function usePreviewTemplates(
const allEmailPosts = useMemo( () => {
return emailPosts?.map( ( post: EmailEditorPostType ) => {
const preferredTitle = applyFilters(
'mailpoet_email_editor_preferred_template_title',
'',
post
);
const { postTemplateContent } = generateTemplateContent(
post,
allTemplates
@@ -186,8 +180,9 @@ export function usePreviewTemplates(
const template = {
...post,
title: {
raw: post.title.raw,
rendered: preferredTitle || post.title.rendered,
raw: post?.mailpoet_data?.subject || post.title.raw,
rendered:
post?.mailpoet_data?.subject || post.title.rendered, // use MailPoet subject as title
},
};
return {

View File

@@ -134,6 +134,29 @@ export function* saveEditedEmail() {
} );
}
export function* updateEmailMailPoetProperty( name: string, value: string ) {
const postId = select( storeName ).getEmailPostId();
// There can be a better way how to get the edited post data
const editedPost = select( coreDataStore ).getEditedEntityRecord(
'postType',
editorCurrentPostType,
postId
);
// @ts-expect-error Property 'mailpoet_data' does not exist on type 'Updatable<Attachment<any>>'.
const mailpoetData = editedPost?.mailpoet_data || {};
yield dispatch( coreDataStore ).editEntityRecord(
'postType',
editorCurrentPostType,
postId,
{
mailpoet_data: {
...mailpoetData,
[ name ]: value,
},
}
);
}
export const setTemplateToPost =
( templateSlug ) =>
async ( { registry } ) => {
@@ -145,7 +168,10 @@ export const setTemplateToPost =
} );
};
export function* requestSendingNewsletterPreview( email: string ) {
export function* requestSendingNewsletterPreview(
newsletterId: number,
email: string
) {
// If preview is already sending do nothing
const previewState = select( storeName ).getPreviewState();
if ( previewState.isSendingPreviewEmail ) {
@@ -166,6 +192,7 @@ export function* requestSendingNewsletterPreview( email: string ) {
path: '/mailpoet-email-editor/v1/send_preview_email',
method: 'POST',
data: {
newsletterId,
email,
postId,
},
@@ -186,9 +213,6 @@ export function* requestSendingNewsletterPreview( email: string ) {
state: {
sendingPreviewStatus: SendingPreviewStatus.ERROR,
isSendingPreviewEmail: false,
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
errorMessage: JSON.stringify( errorResponse?.error ),
},
};
}

View File

@@ -96,8 +96,13 @@ export const isEmpty = createRegistrySelector( ( select ) => (): boolean => {
return true;
}
const { content, title } = post;
return ! content.raw && ! title.raw;
const { content, mailpoet_data: mailpoetData, title } = post;
return (
! content.raw &&
! mailpoetData.subject &&
! mailpoetData.preheader &&
! title.raw
);
} );
export const hasEmptyContent = createRegistrySelector(

View File

@@ -202,7 +202,6 @@ export type State = {
isModalOpened: boolean;
isSendingPreviewEmail: boolean;
sendingPreviewStatus: SendingPreviewStatus | null;
errorMessage?: string;
};
personalizationTags: {
list: PersonalizationTag[];
@@ -210,6 +209,13 @@ export type State = {
};
};
export type MailPoetEmailData = {
id: number;
subject: string;
preheader: string;
preview_url: string;
};
export type EmailTemplate = {
id: string;
slug: string;
@@ -261,6 +267,7 @@ export type MailPoetEmailPostContentExtended = {
export type EmailEditorPostType = Omit< Post, 'type' > & {
type: string;
mailpoet_data?: MailPoetEmailPostContentExtended;
};
export type EmailContentValidationAction = {

View File

@@ -75,3 +75,5 @@ We may add, update and delete any of them.
| `mailpoet_email_editor_send_preview_email` | `Array` $postData | `boolean` Result of processing. Was email sent successfully? | Allows override of the send preview mail function. Folks may choose to use custom implementation |
| `mailpoet_email_editor_post_sent_status_args` | `Array` `sent` post status args | `Array` register_post_status args | Allows update of the argument for the sent post status |
## TODO
- We use `mailpoet_data` in some section of the codebase. This will be updated.

View File

@@ -66,6 +66,7 @@ class Email_Api_Controller {
* $data - Post Data
* format
* [_locale] => user
* [newsletterId] => NEWSLETTER_ID
* [email] => Provided email address
* [postId] => POST_ID
*/

View File

@@ -75,7 +75,7 @@ services:
- mailhog-data:/mailhog-data
wordpress:
image: wordpress:${WORDPRESS_IMAGE_VERSION:-6.7.1-php8.3}
image: wordpress:${WORDPRESS_IMAGE_VERSION:-6.7.2-php8.3}
container_name: wordpress_${CIRCLE_NODE_INDEX:-default}
depends_on:
smtp: