Compare commits

..

1 Commits

Author SHA1 Message Date
1340e36d9d Release 3.78.0 2022-01-25 09:29:05 +01:00
2094 changed files with 121116 additions and 106348 deletions

View File

@ -7,7 +7,7 @@ slack-fail-post-step: &slack-fail-post-step
post-steps:
- slack/notify:
channel: mailpoet-dev-feeds
branch_pattern: 'trunk,release'
branch_pattern: 'master,release'
event: fail
custom: |
{
@ -64,11 +64,11 @@ anchors:
environment:
TZ: /usr/share/zoneinfo/Etc/UTC
only_trunk_and_release: &only_trunk_and_release
only_master_and_release: &only_master_and_release
filters:
branches:
only:
- trunk
- master
- release
multisite_acceptance_config: &multisite_acceptance_config
@ -76,13 +76,13 @@ anchors:
requires:
- unit_tests
- static_analysis_php8
<<: *only_trunk_and_release
<<: *only_master_and_release
executors:
wpcli_php_oldest:
<<: *default_job_config
docker:
- image: mailpoet/wordpress:7.2_20220309.1
- image: mailpoet/wordpress:7.2_20211213.1
wpcli_php_max_wporg:
<<: *default_job_config
@ -92,20 +92,20 @@ executors:
wpcli_php_latest:
<<: *default_job_config
docker:
- image: mailpoet/wordpress:8.1_20220718.1
- image: mailpoet/wordpress:8.0_20211028.1
wpcli_php_mysql_oldest:
<<: *default_job_config
docker:
- image: mailpoet/wordpress:7.2_20220309.1
- image: cimg/mysql:5.7
- image: mailpoet/wordpress:7.2_20211213.1
- image: circleci/mysql:5.5-ram
wpcli_php_mysql_latest:
<<: *default_job_config
docker:
- image: mailpoet/wordpress:8.1_20220718.1
- image: cimg/mysql:8.0
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_520_ci
- image: mailpoet/wordpress:8.0_20211028.1
- image: circleci/mysql:8.0-ram
command: [--default-authentication-plugin=mysql_native_password]
jobs:
build:
@ -116,10 +116,7 @@ jobs:
- checkout:
path: /home/circleci/mailpoet
- run:
name: 'Set PNPM store directory'
command: pnpm config set store-dir ~/.pnpm-store
- run:
name: 'Compute checksum for prefixer'
name: "Compute checksum for prefixer"
command: find prefixer -type f -not -path 'prefixer/build/*' -not -path 'prefixer/vendor/*' | sort | xargs cat | sha512sum > prefixer-checksum
- restore_cache:
key: tools-{{ checksum "tools/install.php" }}
@ -133,11 +130,12 @@ jobs:
key: composer-prefixed-{{ checksum "prefixer-checksum" }}
- restore_cache:
keys:
- pnpm-{{ checksum "../pnpm-lock.yaml" }}
- pnpm- # fallback to most recent pnpm-* if not found by checksum
- npm-{{ checksum "package-lock.json" }}
- npm- # fallback to most recent npm-* if not found by checksum
- run:
name: 'Set up test environment'
name: "Set up test environment"
command: |
# install plugin dependencies
COMPOSER_DEV_MODE=1 php tools/install.php
./tools/vendor/composer.phar validate --no-check-all --no-check-publish
./tools/vendor/composer.phar validate --no-check-all --no-check-publish --working-dir=prefixer
@ -146,10 +144,6 @@ jobs:
./do compile:all --env production
./do doctrine:generate-cache
vendor/bin/codecept build
./do twig:generate-cache
- run:
name: 'Check Prettier formatting'
command: ./do qa:prettier-check
- save_cache:
key: tools-{{ checksum "tools/install.php" }}
paths:
@ -173,35 +167,32 @@ jobs:
- prefixer/vendor
- vendor-prefixed
- save_cache:
key: pnpm-{{ checksum "../pnpm-lock.yaml" }}
key: npm-{{ checksum "package-lock.json" }}
paths:
- ~/.pnpm-store
- ~/.npm
- run:
name: Download additional WP Plugins for tests
command: |
./do download:woo-commerce-zip 7.1.0
./do download:woo-commerce-subscriptions-zip 4.6.0
./do download:woo-commerce-memberships-zip 1.23.1
./do download:woo-commerce-blocks-zip 8.8.2
./do download:woo-commerce-zip 6.0.0
./do download:woo-commerce-subscriptions-zip 3.0.14
- run:
name: Dump tests ENV variables for acceptance tests
command: |
(printenv | grep WP_TEST_ > .env) || true
- persist_to_workspace:
root: /home/circleci
root: /home/circleci/mailpoet
paths:
- .node
- mailpoet
- .
build_premium:
executor: wpcli_php_latest
resource_class: medium
working_directory: /home/circleci/mailpoet
steps:
- attach_workspace:
at: /home/circleci
at: /home/circleci/mailpoet
- add_ssh_keys
- run:
name: 'Install Premium plugin'
name: "Install Premium plugin"
command: |
# Add GitHub to known_hosts because there is no checkout step in this job
echo "github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts
@ -211,7 +202,7 @@ jobs:
- restore_cache:
key: premium-composer-{{ checksum "mailpoet-premium/composer.json" }}-{{ checksum "mailpoet-premium/composer.lock" }}
- run:
name: 'Set up test environment'
name: "Set up test environment"
command: |
# install Premium dependencies
MAILPOET_FREE_PATH=$(pwd)/mailpoet
@ -230,11 +221,9 @@ jobs:
paths:
- mailpoet-premium/vendor
- persist_to_workspace:
root: /home/circleci
root: /home/circleci/mailpoet
paths:
- .node
- mailpoet
- .
static_analysis:
executor: wpcli_php_latest
resource_class: medium
@ -244,90 +233,84 @@ jobs:
type: integer
default: 70200
steps:
- attach_workspace:
at: /home/circleci
- run:
name: 'Static analysis'
command: ./do qa:phpstan --php-version=<< parameters.php_version >>
- attach_workspace:
at: /home/circleci/mailpoet
- run:
name: "Static analysis"
command: ./do qa:phpstan --php-version=<< parameters.php_version >>
qa_js:
executor: wpcli_php_latest
working_directory: /home/circleci/mailpoet/mailpoet
steps:
- attach_workspace:
at: /home/circleci
at: /home/circleci/mailpoet
- run:
name: 'QA Frontend Assets'
name: "QA Frontend Assets"
command: ./do qa:frontend-assets
qa_php:
executor: wpcli_php_latest
working_directory: /home/circleci/mailpoet/mailpoet
steps:
- attach_workspace:
at: /home/circleci
at: /home/circleci/mailpoet
- run:
name: 'QA PHP'
name: "QA PHP"
command: ./do qa:php
qa_php_oldest:
executor: wpcli_php_oldest
working_directory: /home/circleci/mailpoet/mailpoet
steps:
- attach_workspace:
at: /home/circleci
at: /home/circleci/mailpoet
- run:
name: 'QA PHP'
name: "QA PHP"
command: ./do qa:php
qa_php_max_wporg:
executor: wpcli_php_max_wporg
steps:
- attach_workspace:
at: /home/circleci
at: /home/circleci/mailpoet
- run:
name: 'QA PHP'
name: "QA PHP"
command: ./do qa:php-max-wporg
js_tests:
executor: wpcli_php_latest
working_directory: /home/circleci/mailpoet/mailpoet
steps:
- attach_workspace:
at: /home/circleci
- run:
name: 'Preparing test results folder'
command: mkdir test-results
- run:
name: 'JS Newsletter Editor Tests'
command: |
mkdir test-results/mocha
./do t:newsletter-editor test-results/mocha/newsletter_editor_junit.xml
- run:
name: 'JS Tests'
command: |
./do t:j test-results/mocha/junit.xml
- store_test_results:
path: test-results/mocha
- store_artifacts:
path: test-results/mocha
destination: mocha
- attach_workspace:
at: /home/circleci/mailpoet
- run:
name: "Preparing test results folder"
command: mkdir test-results
- run:
name: "JS Newsletter Editor Tests"
command: |
mkdir test-results/mocha
./do t:newsletter-editor test-results/mocha/newsletter_editor_junit.xml
- run:
name: "JS Tests"
command: |
./do t:j test-results/mocha/junit.xml
- store_test_results:
path: test-results/mocha
- store_artifacts:
path: test-results/mocha
destination: mocha
acceptance_tests:
parallelism: 20
working_directory: /home/circleci/mailpoet/mailpoet
machine:
image: ubuntu-2204:2022.10.2
image: ubuntu-2004:202111-01
parameters:
multisite:
type: integer
default: 0
group:
type: string
default: ''
mysql_command:
type: string
default: ''
mysql_image_version:
type: string
default: ''
codeception_image_version:
type: string
default: ''
wordpress_image_version:
type: string
default: ''
@ -337,31 +320,18 @@ jobs:
woo_subscriptions_version:
type: string
default: ''
woo_memberships_version:
type: string
default: ''
woo_blocks_version:
type: string
default: ''
enable_cot:
type: integer
default: 0
enable_cot_sync:
type: integer
default: 0
environment:
MYSQL_COMMAND: << parameters.mysql_command >>
MYSQL_IMAGE_VERSION: << parameters.mysql_image_version >>
CODECEPTION_IMAGE_VERSION: << parameters.codeception_image_version >>
WORDPRESS_IMAGE_VERSION: << parameters.wordpress_image_version >>
steps:
- attach_workspace:
at: /home/circleci
at: /home/circleci/mailpoet
- run:
name: 'Set up virtual host'
name: "Set up virtual host"
command: echo 127.0.0.1 mailpoet.loc | sudo tee -a /etc/hosts
- run:
name: 'Pull test docker images'
name: "Pull acceptance test docker images"
# Pull docker images with 3 retries
command: i='0';while ! docker-compose -f tests/docker/docker-compose.yml pull && ((i < 3)); do sleep 3 && i=$[$i+1]; done
- when:
@ -370,74 +340,37 @@ jobs:
- run:
name: Download WooCommerce Core
command: |
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-zip << parameters.woo_core_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-zip << parameters.woo_core_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception
- when:
condition: << parameters.woo_subscriptions_version >>
steps:
- run:
name: Download WooCommerce Subscriptions
command: |
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-subscriptions-zip << parameters.woo_subscriptions_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
- when:
condition: << parameters.woo_memberships_version >>
steps:
- run:
name: Download WooCommerce Memberships
command: |
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-memberships-zip << parameters.woo_memberships_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
- when:
condition: << parameters.woo_blocks_version >>
steps:
- run:
name: Download WooCommerce Blocks
command: |
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-blocks-zip << parameters.woo_blocks_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception_acceptance
cd tests/docker
docker-compose run --rm -w /project --entrypoint "./do download:woo-commerce-subscriptions-zip << parameters.woo_subscriptions_version >>" --no-deps -e WP_GITHUB_USERNAME=${WP_GITHUB_USERNAME} -e WP_GITHUB_TOKEN=${WP_GITHUB_TOKEN} codeception
- run:
name: Group acceptance tests
command: |
# Convert test result filename values to be relative paths because the circleci CLI's split command requires exact matches
if [ -e $CIRCLE_INTERNAL_TASK_DATA/circle-test-results/results.json ]; then
sed -i.bak 's#/wp-core/wp-content/plugins/mailpoet/##g' $CIRCLE_INTERNAL_TASK_DATA/circle-test-results/results.json
fi
sed -i.bak 's#/wp-core/wp-content/plugins/mailpoet/##g' $CIRCLE_INTERNAL_TASK_DATA/circle-test-results/results.json
# `circleci tests split` returns different values based on the container it's run on
# in case group is defined find only tests containing the group
if [[ -n '<< parameters.group >>' ]]; then
grep -rw 'tests/acceptance' -e '@group << parameters.group >>' | sed -e "s/:.*//" | circleci tests split --split-by=timings > tests/acceptance/_groups/circleci_split_group
else
circleci tests glob "tests/acceptance/**/*Cest.php" | circleci tests split --split-by=timings > tests/acceptance/_groups/circleci_split_group
fi
circleci tests glob "tests/acceptance/**/*Cest.php" | circleci tests split --split-by=timings > tests/acceptance/_groups/circleci_split_group
cat tests/acceptance/_groups/circleci_split_group
- run:
name: Run acceptance tests
command: |
mkdir -m 777 -p tests/_output/exceptions
cd tests/docker
args=(
--steps
--debug
-vvv
--html
--xml
-g circleci_split_group
)
docker-compose run -e SKIP_DEPS=1 \
-e CIRCLE_BRANCH=${CIRCLE_BRANCH} \
-e CIRCLE_JOB=${CIRCLE_JOB} \
-e MULTISITE=<< parameters.multisite >> \
-e ENABLE_COT=<< parameters.enable_cot >> \
-e ENABLE_COT_SYNC=<< parameters.enable_cot_sync >> \
codeception_acceptance "${args[@]}"
mkdir -m 777 -p tests/_output/exceptions
cd tests/docker
docker-compose run -e SKIP_DEPS=1 -e CIRCLE_BRANCH=${CIRCLE_BRANCH} -e CIRCLE_JOB=${CIRCLE_JOB} -e MULTISITE=<< parameters.multisite >> codeception -g circleci_split_group --steps --debug -vvv --html --xml
- run:
name: Check exceptions
command: |
if [ "$(ls tests/_output/exceptions/*.html)" ]; then
echo "There were some exceptions during the tests run"
exit 1
fi
if [ "$(ls tests/_output/exceptions/*.html)" ]; then
echo "There were some exceptions during the tests run"
exit 1
fi
- store_artifacts:
path: tests/_output
- store_test_results:
@ -451,18 +384,18 @@ jobs:
executor: << parameters.executor >>
steps:
- attach_workspace:
at: /home/circleci
at: /home/circleci/mailpoet
- run:
name: 'Set up virtual host'
name: "Set up virtual host"
command: echo 127.0.0.1 mailpoet.loc | sudo tee -a /etc/hosts
- run:
name: 'Prepare example.com for testing'
name: "Prepare example.com for testing"
command: echo 127.0.0.1 example.com | sudo tee -a /etc/hosts
- run:
name: 'Set up test environment'
name: "Set up test environment"
command: source ../.circleci/setup.bash && setup php7
- run:
name: 'PHP Unit tests'
name: "PHP Unit tests"
command: |
./do t:u --xml
- store_test_results:
@ -474,102 +407,57 @@ jobs:
path: /tmp/fake-mailer/
destination: fake-mailer
integration_tests:
working_directory: /home/circleci/mailpoet/mailpoet
machine:
image: ubuntu-2204:2022.10.2
environment:
CODECEPTION_IMAGE_VERSION: << parameters.codeception_image_version >>
parameters:
codeception_image_version:
executor:
type: string
default: ''
group:
default: wpcli_php_mysql_latest
setup_command:
type: string
default: ''
skip_group:
default: source ../.circleci/setup.bash && setup php7
run_command:
type: string
default: ''
skip_plugins:
type: integer
default: 0
enable_cot:
type: integer
default: 0
enable_cot_sync:
type: integer
default: 0
multisite:
type: integer
default: 0
default: ./do test:integration --xml
executor: << parameters.executor >>
steps:
- attach_workspace:
at: /home/circleci
at: /home/circleci/mailpoet
- run:
name: 'Pull test docker images'
# Pull docker images with 3 retries
command: i='0';while ! docker-compose -f tests/docker/docker-compose.yml pull && ((i < 3)); do sleep 3 && i=$[$i+1]; done
name: "Set up virtual host"
command: echo 127.0.0.1 mailpoet.loc | sudo tee -a /etc/hosts
- run:
name: 'PHP Integration tests'
command: |
mkdir -m 777 -p tests/_output/exceptions
cd tests/docker
args=(
--steps
--debug
-vvv
--html
--xml
)
if [[ -n '<< parameters.group >>' ]]; then
args+=(--group << parameters.group >>)
fi
if [[ -n '<< parameters.skip_group >>' ]]; then
args+=(--skip-group << parameters.skip_group >>)
fi
docker-compose run -e SKIP_DEPS=1 \
-e CIRCLE_BRANCH=${CIRCLE_BRANCH} \
-e CIRCLE_JOB=${CIRCLE_JOB} \
-e SKIP_PLUGINS=<< parameters.skip_plugins >> \
-e WP_TEST_MAILER_ENABLE_SENDING=${WP_TEST_MAILER_ENABLE_SENDING} \
-e WP_TEST_ENABLE_NETWORK_TESTS=${WP_TEST_ENABLE_NETWORK_TESTS} \
-e WP_TEST_MAILER_MAILPOET_API=${WP_TEST_MAILER_MAILPOET_API} \
-e WP_TEST_MAILER_SENDGRID_API=${WP_TEST_MAILER_SENDGRID_API} \
-e WP_TEST_MAILER_AMAZON_ACCESS=${WP_TEST_MAILER_AMAZON_ACCESS} \
-e WP_TEST_MAILER_AMAZON_REGION=${WP_TEST_MAILER_AMAZON_REGION} \
-e WP_TEST_MAILER_AMAZON_SECRET=${WP_TEST_MAILER_AMAZON_SECRET} \
-e WP_TEST_IMPORT_MAILCHIMP_API=${WP_TEST_IMPORT_MAILCHIMP_API} \
-e WP_TEST_IMPORT_MAILCHIMP_LISTS=${WP_TEST_IMPORT_MAILCHIMP_LISTS} \
-e WP_TEST_MAILER_SMTP_HOST=${WP_TEST_MAILER_SMTP_HOST} \
-e WP_TEST_MAILER_SMTP_LOGIN=${WP_TEST_MAILER_SMTP_LOGIN} \
-e WP_TEST_MAILER_SMTP_PASSWORD=${WP_TEST_MAILER_SMTP_PASSWORD} \
-e MULTISITE=<< parameters.multisite >> \
-e ENABLE_COT=<< parameters.enable_cot >> \
-e ENABLE_COT_SYNC=<< parameters.enable_cot_sync >> \
codeception_integration "${args[@]}"
name: "Prepare example.com for testing"
command: echo 127.0.0.1 example.com | sudo tee -a /etc/hosts
- run:
name: "Set up test environment"
command: << parameters.setup_command >>
- run:
name: "PHP Integration tests"
command: << parameters.run_command >>
- store_test_results:
path: tests/_output
- store_artifacts:
path: tests/_output
destination: codeception
- store_artifacts:
path: /mailhog-data
destination: mailhog-data
path: /tmp/fake-mailer/
destination: fake-mailer
build_release_zip:
executor: wpcli_php_mysql_latest
resource_class: medium+
steps:
- attach_workspace:
at: /home/circleci
at: /home/circleci/mailpoet
- run:
name: 'Set up environment'
name: "Set up environment"
command: |
source ../.circleci/setup.bash && setup php7
sudo apt-get update
sudo apt-get install gettext
sudo apt-get install python3-pip gettext
sudo pip3 install transifex-client
sed -i 's/^WP_ROOT=.*$/WP_ROOT=\/home\/circleci\/mailpoet\/wordpress/g' .env
echo ${CIRCLE_BUILD_NUM} > release_zip_build_number.txt
- run:
name: 'Build'
name: "Build"
command: ./build.sh
- store_artifacts:
path: /home/circleci/mailpoet/mailpoet/mailpoet.zip
@ -624,86 +512,12 @@ workflows:
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_tests_woo_cot_sync
group: woo
enable_cot: 1
enable_cot_sync: 1
requires:
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_tests_woo_cot_no_sync
group: woo
enable_cot: 1
enable_cot_sync: 0
requires:
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_tests_woo_cot_off
group: woo
requires:
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- js_tests:
<<: *slack-fail-post-step
requires:
- build
- integration_tests:
<<: *slack-fail-post-step
group: woo
name: integration_test_woocommerce
requires:
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- integration_tests:
<<: *slack-fail-post-step
group: woo
enable_cot: 1
enable_cot_sync: 1
name: integration_test_woo_cot_sync
requires:
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- integration_tests:
<<: *slack-fail-post-step
group: woo
enable_cot: 1
enable_cot_sync: 0
name: integration_test_woo_cot_no_sync
requires:
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- integration_tests:
<<: *slack-fail-post-step
group: woo
name: integration_test_woo_cot_off
requires:
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- integration_tests:
<<: *slack-fail-post-step
skip_group: woo
skip_plugins: 1
name: integration_test_base
requires:
- unit_tests
- static_analysis_php8
@ -715,9 +529,10 @@ workflows:
name: acceptance_tests_multisite
- integration_tests:
<<: *slack-fail-post-step
<<: *only_trunk_and_release
multisite: 1
<<: *only_master_and_release
name: integration_tests_multisite
setup_command: source ../.circleci/setup.bash && setup php7_multisite
run_command: ./do test:multisite-integration --xml
requires:
- unit_tests
- static_analysis_php7
@ -730,23 +545,16 @@ workflows:
- build
- acceptance_tests
- js_tests
- integration_test_woocommerce
- integration_test_base
- integration_test_woo_cot_no_sync
- integration_test_woo_cot_off
- integration_test_woo_cot_sync
- acceptance_tests_woo_cot_sync
- acceptance_tests_woo_cot_off
- acceptance_tests_woo_cot_no_sync
- integration_tests
nightly:
triggers:
- schedule:
cron: '0 22 * * 1-5'
cron: "0 22 * * 1-5"
filters:
branches:
only:
- trunk
- master
jobs:
- build:
<<: *slack-fail-post-step
@ -755,21 +563,16 @@ workflows:
name: acceptance_latest
woo_core_version: latest
woo_subscriptions_version: latest
woo_memberships_version: latest
woo_blocks_version: latest
requires:
- build
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_oldest
woo_core_version: 6.8.0
woo_subscriptions_version: 4.3.0
woo_memberships_version: 1.21.0
woo_blocks_version: 6.8.0
woo_core_version: 4.0.1
woo_subscriptions_version: 3.0.10
mysql_command: --max_allowed_packet=100M
mysql_image_version: 5.7.36
codeception_image_version: 7.4-cli_20220605.0
wordpress_image_version: wp-5.8_php7.3_20221104.1
mysql_image_version: 5.5-ram
wordpress_image_version: wp-5.3_php7.2_20211213.1
requires:
- build
- unit_tests:
@ -791,7 +594,7 @@ workflows:
- integration_tests:
<<: *slack-fail-post-step
name: integration_oldest
codeception_image_version: 7.2-cli_20220605.0
executor: wpcli_php_mysql_oldest
requires:
- build
- build_premium:

View File

@ -6,3 +6,4 @@ sendmail_path = /usr/local/bin/fake-sendmail.php
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone = UTC

View File

@ -12,7 +12,7 @@ function setup {
sudo cp "$script_dir/fake-sendmail.php" /usr/local/bin/
# configure Apache
sudo cp "$script_dir/mailpoet_php.ini" /etc/php.d/
sudo cp "$script_dir/mailpoet_php.ini" /usr/local/etc/php/conf.d/
sudo cp "$script_dir/apache/mailpoet.loc.conf" /etc/apache2/sites-available
sudo a2dissite 000-default.conf
sudo a2ensite mailpoet.loc
@ -29,12 +29,14 @@ function setup {
wp core download $wp_cli_wordpress_path $wp_cli_allow_root --version=${2:-latest}
# Generate `wp-config.php` file with debugging enabled
wp config create --dbname=wordpress --dbuser=root --dbhost=127.0.0.1 --dbprefix='mp_' $wp_cli_wordpress_path $wp_cli_allow_root
wp config set WP_DEBUG true --raw $wp_cli_wordpress_path $wp_cli_allow_root
echo "define(\"WP_DEBUG\", true);" | wp core config --dbname=wordpress --dbuser=root --dbhost=127.0.0.1 --extra-php $wp_cli_wordpress_path $wp_cli_allow_root
# Disable WP Cron so that it doesn't interfere with tests
wp config set DISABLE_WP_CRON true --raw $wp_cli_wordpress_path $wp_cli_allow_root
# Change default table prefix
sed -i "s/\$table_prefix = 'wp_';/\$table_prefix = 'mp_';/" "$root_dir/wordpress/wp-config.php"
# Install WordPress
if [[ $version == "php7_multisite" ]]; then
# Configure multisite environment
@ -70,9 +72,4 @@ function setup {
# Activate MailPoet Premium
wp plugin activate mailpoet-premium --path="$root_dir/wordpress"
fi
# Fix WP formatting file for compatibility with PHP8.1
sed -i "s|if ( strlen( \$email ) < 6 ) {|if ( strlen( (string) \$email ) < 6 ) {|" ../wordpress/wp-includes/formatting.php
sed -i "s|return rtrim( \$string, '/\\\\\\\\' );|return rtrim( (string) \$string, '/\\\\\\\\' );|" ../wordpress/wp-includes/formatting.php
sed -i "s|return \$wp_hasher->HashPassword( trim( \$password ) );|return \$wp_hasher->HashPassword( trim( (string) \$password ) );|" ../wordpress/wp-includes/pluggable.php
}

View File

@ -7,51 +7,3 @@ insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
ij_smart_tabs = false
max_line_length = off
[*.php]
ij_php_align_key_value_pairs = false
ij_php_align_multiline_chained_methods = false
ij_php_align_assignments = false
ij_php_align_class_constants = false
ij_php_align_multiline_parameters = false
ij_php_align_multiline_ternary_operation = false
ij_php_align_inline_comments = false
ij_php_align_multiline_for = true
ij_php_align_named_arguments = false
ij_php_align_multiline_array_initializer_expression = false
ij_php_align_phpdoc_comments = false
ij_php_blank_lines_after_class_header = 0
ij_php_blank_lines_around_class = 1
ij_php_blank_lines_before_class_end = 0
ij_php_blank_lines_around_method = 1
ij_php_blank_lines_after_opening_tag = 0
ij_php_keep_indents_on_empty_lines = false
ij_php_keep_blank_lines_after_lbrace = 0
ij_php_keep_blank_lines_before_right_brace = 0
ij_php_keep_blank_lines_in_declarations = 1
ij_php_spaces_around_arrow = false
ij_php_space_after_type_cast = false
ij_php_blank_lines_after_function = 1
ij_any_space_after_colon = true
ij_any_space_before_comma = false
ij_any_space_after_comma = true
ij_php_space_before_catch_left_brace = true
ij_php_space_before_if_left_brace = true
ij_php_space_before_if_parentheses = true
ij_php_space_after_quest = true
ij_php_space_after_unary_not = false
ij_php_space_before_quest = true
ij_php_anonymous_brace_style = end_of_line
ij_php_space_before_method_parentheses = false
ij_php_space_before_method_call_parentheses = false
ij_php_spaces_around_assignment_in_declare = true
ij_php_method_parameters_new_line_after_left_paren = true
ij_php_method_brace_style = end_of_line
ij_php_blank_lines_before_method_body = 0
ij_php_space_before_method_left_brace = true
ij_php_space_after_for_semicolon = true
ij_php_space_after_colon_in_return_type = true
ij_php_space_before_else_keyword = true
ij_php_for_statement_new_line_after_left_paren = true

View File

@ -37,5 +37,3 @@ e66c76133ec3ef667e382203426d91a4b4aa5174
# Updating rule name in php:cs ignore comments
65b834a9fff72b1ec5fc81ac383ebb27321da9dc
# Prettier autoformatting
ab27eaee2df740c0add4331a7f8c115a87ecfa2b

View File

@ -4,6 +4,7 @@ about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
@ -11,7 +12,6 @@ A clear and concise description of what the bug is.
**To reproduce**
Steps to reproduce the behavior:
1. Go to ...
2. Click on ...
3. Scroll down to ...
@ -26,7 +26,6 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Versions (please complete the following information):**
- WordPress version: [e.g: 5.3.2]
- PHP version: [e.g: 7.4.2]
- MailPoet version: [e.g: 3.46.13]

View File

@ -4,6 +4,7 @@ about: https://feedback.mailpoet.com/
title: ''
labels: ''
assignees: ''
---
Please use https://feedback.mailpoet.com/ for feature requests.

22
.github/SECURITY.md vendored
View File

@ -4,7 +4,7 @@ Full details of the Automattic Security Policy can be found on [automattic.com/s
## Supported Versions
Generally, _only the latest version of MailPoet has continued support_. If a critical vulnerability is found in the current version of MailPoet, we may opt to backport any patches to previous versions.
Generally, *only the latest version of MailPoet has continued support*. If a critical vulnerability is found in the current version of MailPoet, we may opt to backport any patches to previous versions.
## Reporting a Vulnerability
@ -14,9 +14,9 @@ Generally, _only the latest version of MailPoet has continued support_. If a cri
Our most critical targets are:
- MailPoet plugin (this repository)
- MailPoet Premium
- mailpoet.com -- the primary site, and all of it subdomains, e.g. [account.mailpoet.com](https://account.mailpoet.com/)
* MailPoet plugin (this repository)
* MailPoet Premium
* mailpoet.com -- the primary site, and all of it subdomains, e.g. [account.mailpoet.com](https://account.mailpoet.com/)
For more targets, see the `In Scope` section on [HackerOne](https://hackerone.com/automattic).
@ -26,12 +26,12 @@ _Please note that the **WordPress software is a separate entity** from Automatti
We're committed to working with security researchers to resolve the vulnerabilities they discover. You can help us by following these guidelines:
- Follow [HackerOne's disclosure guidelines](https://www.hackerone.com/disclosure-guidelines).
- Pen-testing Production:
- Please **setup a local environment** instead whenever possible. Most of our code is open source (see above).
- If that's not possible, **limit any data access/modification** to the bare minimum necessary to reproduce a PoC.
- **_Don't_ automate form submissions!** That's very annoying for us, because it adds extra work for the volunteers who manage those systems, and reduces the signal/noise ratio in our communication channels.
- To be eligible for a bounty, please follow all of these guidelines.
- Be Patient - Give us a reasonable time to correct the issue before you disclose the vulnerability.
* Follow [HackerOne's disclosure guidelines](https://www.hackerone.com/disclosure-guidelines).
* Pen-testing Production:
* Please **setup a local environment** instead whenever possible. Most of our code is open source (see above).
* If that's not possible, **limit any data access/modification** to the bare minimum necessary to reproduce a PoC.
* **_Don't_ automate form submissions!** That's very annoying for us, because it adds extra work for the volunteers who manage those systems, and reduces the signal/noise ratio in our communication channels.
* To be eligible for a bounty, please follow all of these guidelines.
* Be Patient - Give us a reasonable time to correct the issue before you disclose the vulnerability.
We also expect you to comply with all applicable laws. You're responsible to pay any taxes associated with your bounties.

View File

@ -1,23 +0,0 @@
## Description
_N/A_
## Code review notes
_N/A_
## QA notes
_N/A_
## Linked PRs
_N/A_
## Linked tickets
_N/A_
## After-merge notes
_N/A_

View File

@ -3,14 +3,14 @@
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: 'CodeQL'
name: "CodeQL"
on:
push:
branches: [trunk]
branches: [master]
pull_request:
# The branches below must be a subset of the branches above
branches: [trunk]
branches: [master]
schedule:
- cron: '0 17 * * 4'
@ -29,43 +29,43 @@ jobs:
# 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
- 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' }}
# 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
# 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
# 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
# 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
# ✏️ 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
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@ -1,5 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged -c mailpoet/package.json --cwd mailpoet
npx lint-staged -c package.json
cd mailpoet && npx lint-staged

2
.npmrc
View File

@ -1,2 +0,0 @@
save-workspace-protocol=rolling
strict-peer-dependencies=false

1
.nvmrc
View File

@ -1 +0,0 @@
v17.9.1

View File

@ -1,27 +0,0 @@
*.hbs
*.scss
.mp_svn
_generated
_output
composer.json
composer.lock
node_modules
pnpm-lock.yaml
vendor
vendor-prefixed
/.mp_svn
/dev/data
/mailpoet/assets/dist
/mailpoet/assets/js/lib
/mailpoet/assets/js/src/newsletter_editor/behaviors/tinymce_icons.js
/mailpoet/generated
/mailpoet/lang
/mailpoet/lib/Newsletter/Renderer/Template.html
/mailpoet/lib-3rd-party
/mailpoet/plugin_repository
/mailpoet/temp
/mailpoet/tests/javascript_newsletter_editor/testBundles
/mailpoet/tests/plugins
/mailpoet/views
/mailpoet-premium
/wordpress

View File

@ -1,5 +0,0 @@
{
"printWidth": 80,
"singleQuote": true,
"trailingComma": "all"
}

View File

@ -1,7 +1,6 @@
# Contributing
## PHP Code
- Two spaces indentation.
- Space between keyword (if, for, switch...) and left bracket
- CamelCase for classes.
@ -16,25 +15,21 @@
- Cover your code in tests.
## SCSS Code
- camelCase for file name
- Components files are prefixed with underscore, to indicate, that they aren't compiled separately.
## JS Code
- Javascript code should follow the [Airbnb style guide](https://github.com/airbnb/javascript).
- Prefer named export before default export in JS and TS files
## Disabling linting rules
- we want to avoid using `eslint-disable`
- if we have to use it we need to use a comment explaining why do we need it:
`/* eslint-disable no-new -- this class has a side-effect in the constructor and it's a library's. */`
`/* eslint-disable no-new -- this class has a side-effect in the constructor and it's a library's. */`
- for PHP we do the same with the exception `// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps` which for now doesnt require an explanation
## Git flow
- Do not commit to trunk.
- Do not commit to master.
- Open a short-living feature branch.
- Open a pull request.
- Add Jira issue reference in the title of the Pull Request.
@ -44,13 +39,7 @@
- Wait for review from another developer.
## Issues creation
- Issues are managed on Jira.
- Discuss issues on public Slack chats, discuss code in pull requests.
- Open a small Jira issue only when it has been discussed.
## Migration from IdiORM to Doctrine
MailPoet used to use [IdiORM](https://github.com/j4mie/idiorm) as its object-relational mapper (ORM), but the project was abandoned a while ago, so we started a migration to [Doctrine](https://www.doctrine-project.org/). This is a significant effort that has been going on for quite some time. Although you will still see parts of the code that use IdioORM, we ask that all new code be added using Doctrine instead.
All IdioORM models live in [mailpoet/lib/Models](https://github.com/mailpoet/mailpoet/tree/trunk/mailpoet/lib/Models), should be considered deprecated and shouldn't be used by new code. We are moving everything to Doctrine entities and some auxiliary code when needed. You can find Doctrine entities in [mailpoet/lib/Entities](https://github.com/mailpoet/mailpoet/tree/trunk/mailpoet/lib/Entities).

View File

@ -1,29 +1,17 @@
# MailPoet
The **MailPoet** plugin monorepo.
To use our Docker-based development environment (recommended), continue with the steps below.
If you'd like to use the plugin code directly, see details in [the plugin's readme](mailpoet/README.md).
## 🔌 Initial setup
1) Run `./do setup` to pull everything and install necessary dependencies.
2) Add secrets to `.env` files in `mailpoet` and `mailpoet-premium` directories. Go to the Secret Store and look for "MailPoet: plugin .env"
3) Run `./do start` to start the stack.
4) Go to http://localhost:8888 to see the dashboard of the dev environment.
1. Run `./do setup` to pull everything and install necessary dependencies.
2. Add secrets to `.env` files in `mailpoet` and `mailpoet-premium` directories. Go to the Secret Store and look for "MailPoet: plugin .env"
3. Run `./do start` to start the stack.
4. Go to http://localhost:8888 to see the dashboard of the dev environment.
## ✅ Additional dependencies
Even though it possible to run everything using Docker, in the development workflow,
it may be faster and more convenient to run some tasks outside the container. Therefore,
the following tools are recommended:
1. **PHP** as per `composer.json` requirements.
2. **Node.js**, as specified by `.nvmrc`. For automatic management use [nvm](https://github.com/nvm-sh/nvm), [FNM](https://github.com/Schniz/fnm), or [Volta](https://github.com/volta-cli/volta).
3. **pnpm**, as specified in `package.json`. For automatic setup enable [Corepack](https://nodejs.org/docs/latest-v17.x/api/corepack.html) using `corepack enable`.
## 🔍 PHPStorm setup for XDebug
In `Languages & Preferences > PHP > Servers` set path mappings:
```shell
@ -39,42 +27,13 @@ To use XDebug inside the **cron**, you need to pass a URL argument `&XDEBUG_TRIG
[in the cron request](https://github.com/mailpoet/mailpoet/blob/bf7bd6d2d9090ed6ec7b8b575bb7d6b08e663a52/lib/Cron/CronHelper.php#L155-L166).
Alternatively, you can add `XDEBUG_TRIGGER: yes` to the `wordpress` service in `docker-compose.yml` and restart it (which will run XDebug also for all other requests).
## Xdebug develop mode
[Xdebug develop mode](https://xdebug.org/docs/develop) is disabled by default because it causes performance issues due to conflicts with the DI container.
It can be enabled when needed using the `XDEBUG_MODE` environment variable. For example, it is possible to enable it by adding the following to `docker-compose.override.yml`:
```
environment:
XDEBUG_MODE: debug, develop
```
## Xdebug for integration tests
- In Languages & Preferences > PHP > Servers create a new sever named `MailPoetTest`, set the host to `localhost` and port to `80` and set following path mappings:
```shell
wordpress -> /wp-core
mailpoet -> /wp-core/wp-content/plugins/mailpoet
mailpoet-premium -> /wp-core/wp-content/plugins/mailpoet-premium
mailpoet/vendor/bin/codecept -> /project/vendor/bin/codecept
mailpoet/vendor/bin/wp -> /usr/local/bin/wp
```
- Add `XDEBUG_TRIGGER: 1` environment to `mailpoet/tests/docker/docker-compose.yml` -> codeception service to start triggering Xdebug
- Make PHPStorm listen to connections by clicking on the phone icon
## 💾 NFS volume sharing for Mac
NFS volumes can bring more stability and performance on Docker for Mac. To setup NFS volume sharing run:
```shell
sudo sh dev/mac-nfs-setup.sh
```
Then create a Docker Compose override file with NFS settings and restart containers:
```shell
cp docker-compose.override.macos-sample.yml docker-compose.override.yml
@ -86,22 +45,18 @@ docker-compose up -d
outside your `Documents` folder, otherwise you may run into [file permission issues](https://objekt.click/2019/11/docker-the-problem-with-macos-catalina/).
# 🐶 Husky
We use [Husky](https://github.com/typicode/husky) to run automated checks in pre-commit hooks.
In case you're using [NVM](https://github.com/nvm-sh/nvm) for Node version management you may
need to create or update your `~/.huskyrc` file with:
```sh
# This loads nvm.sh and sets the correct PATH before running the hooks:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
```
Without it, you may experience errors in some Git clients.
## 🕹 Commands
The `./do` script define aliases for most of the commands you will need while working on plugins:
```shell
@ -123,28 +78,23 @@ Options:
You can access this help in your command line running `./do` without parameters.
## ✉️ Adding new templates to the plugin
[Read the article.](https://mailpoet.atlassian.net/wiki/spaces/MAILPOET/pages/629374977/Adding+new+templates+to+the+plugin)
## 🚥 Testing with PHP 7.4 or PHP 8.0
To switch the environment to PHP 7.4/8.0:
1. Configure the `wordpress` service in `docker-compose.override.yml` to build from the php74 Dockerfile:
## 🚥 Testing with PHP 7.4 or PHP 8.1
To switch the environment to PHP 7.4/8.1:
1) Configure the `wordpress` service in `docker-compose.override.yml` to build from the php74 Dockerfile:
```yaml
wordpress:
build:
context: .
dockerfile: dev/php74/Dockerfile # OR dev/php80/Dockerfile
dockerfile: docker/php74/Dockerfile # OR docker/php81/Dockerfile
```
3) Run `docker-compose build wordpress`.
4) Start the stack with `./do start`.
2. Run `docker-compose build wordpress`.
3. Start the stack with `./do start`.
To switch back to PHP 8.1 remove what was added in 1) and, run `docker-compose build wordpress` for application container and `docker-compose build test_wordpress` for tests container,
To switch back to PHP 8 remove what was added in 1) and, run `docker-compose build wordpress` for application container and `docker-compose build test_wordpress` for tests container,
and start the stack using `./do start`.
## ✅ TODO
- install woo commerce, members and other useful plugins by default

View File

@ -1,15 +1,15 @@
# Getting Support
Welcome to MailPoet!
This isn't the right place to get support for using MailPoet,
but the following resources are available below,
This isn't the right place to get support for using MailPoet,
but the following resources are available below,
thanks for understanding.
- [Support](https://www.mailpoet.com/support)
- [Feature Requests](https://feedback.mailpoet.com)
_DO NOT_ use the issue tracker to ask questions;
use the links above for that.
*DO NOT* use the issue tracker to ask questions;
use the links above for that.
Questions posed to the issue tracker will be closed.
When reporting an issue, please include the following details:
@ -17,7 +17,7 @@ When reporting an issue, please include the following details:
- A narrative description of what you are trying to accomplish.
- The expected results.
- The actual results received.
- We may ask for additional details: what version of the plugin you are using, and what PHP version
- We may ask for additional details: what version of the plugin you are using, and what PHP version
was used to reproduce the issue.
You may also submit a failing test case as a pull request.

View File

@ -1,93 +1,85 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>MailPoet dev environment</title>
<link rel="icon" href="favicon.png" />
<style>
body {
background: #ffe0d0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol';
}
p {
color: #071c6d;
font-weight: 600;
text-align: center;
text-transform: uppercase;
}
a {
color: #fe5301;
transition: all 0.25s ease-in-out;
}
a:hover {
color: #cb4201;
}
table {
margin: 2em auto;
}
table tr td {
color: #071c6d;
padding: 5px 10px;
}
table tr td:nth-child(2) {
font-weight: 600;
}
img {
margin: 3em auto 0;
width: 250px;
display: block;
}
</style>
</head>
<head>
<meta charset="utf-8" />
<title>MailPoet dev environment</title>
<link rel="icon" href="favicon.png" />
<style>
body {
background: #ffe0d0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
}
p {
color: #071c6d;
font-weight: 600;
text-align: center;
text-transform: uppercase;
}
a {
color: #fe5301;
transition: all 0.25s ease-in-out;
}
a:hover {
color: #cb4201;
}
table {
margin: 2em auto;
}
table tr td {
color: #071c6d;
padding: 5px 10px;
}
table tr td:nth-child(2) {
font-weight: 600;
}
img {
margin: 3em auto 0;
width: 250px;
display: block;
}
</style>
</head>
<body>
<a href="/"><img src="logo.svg" /></a>
<p>Dev environment</p>
<table>
<tbody>
<tr>
<td>🖥</td>
<td>
<a href="http://localhost:8002">WordPress</a>
[<a href="http://localhost:8002/wp-admin/">wp-admin</a>]
</td>
<td>App for development</td>
<td><a href="http://localhost:8002">http://localhost:8002</a></td>
</tr>
<tr>
<td>🚥</td>
<td>
<a href="http://localhost:8003">WordPress Tests</a>
[<a href="http://localhost:8003/wp-admin/">wp-admin</a>]
</td>
<td>App for E2E tests</td>
<td><a href="http://localhost:8003">http://localhost:8003</a></td>
</tr>
<tr>
<td>💾</td>
<td>
<a
href="http://localhost:8081?server=db&mysql=wordpress&username=wordpress"
>Adminer</a
>
</td>
<td>DB management</td>
<td>
<a
href="http://localhost:8081?server=db&mysql=wordpress&username=wordpress"
>http://localhost:8081</a
>
</td>
</tr>
<tr>
<td>📪</td>
<td><a href="http://localhost:8082">MailHog</a></td>
<td>Email catcher</td>
<td><a href="http://localhost:8082">http://localhost:8082</a></td>
</tr>
</tbody>
</table>
</body>
<body>
<a href="/"><img src="logo.svg" /></a>
<p>Dev environment</p>
<table>
<tbody>
<tr>
<td>🖥</td>
<td>
<a href="http://localhost:8002">WordPress</a>
[<a href="http://localhost:8002/wp-admin/">wp-admin</a>]
</td>
<td>App for development</td>
<td><a href="http://localhost:8002">http://localhost:8002</a></td>
</tr>
<tr>
<td>🚥</td>
<td>
<a href="http://localhost:8003">WordPress Tests</a>
[<a href="http://localhost:8003/wp-admin/">wp-admin</a>]
</td>
<td>App for E2E tests</td>
<td><a href="http://localhost:8003">http://localhost:8003</a></td>
</tr>
<tr>
<td>💾</td>
<td>
<a href="http://localhost:8081?server=db&mysql=wordpress&username=wordpress">Adminer</a>
</td>
<td>DB management</td>
<td>
<a href="http://localhost:8081?server=db&mysql=wordpress&username=wordpress">http://localhost:8081</a>
</td>
</tr>
<tr>
<td>📪</td>
<td><a href="http://localhost:8082">MailHog</a></td>
<td>Email catcher</td>
<td><a href="http://localhost:8082">http://localhost:8082</a></td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@ -5,19 +5,23 @@ ARG GID=1000
# additinal extensions
RUN apt-get update \
&& apt-get install -y git zlib1g-dev wget gnupg msmtp gettext zip subversion \
&& apt-get install -y git zlib1g-dev wget gnupg msmtp \
&& docker-php-ext-install pdo_mysql \
&& pecl install xdebug-2.9.8 && \
\
# Install NodeJS, enable Corepack
curl -sL https://deb.nodesource.com/setup_17.x | bash - && \
# Install NodeJS + NPM
curl -sL https://deb.nodesource.com/setup_16.x | bash - && \
apt-get install -y nodejs build-essential && \
corepack enable && \
\
# Install WP-CLI
curl -o /usr/local/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
chmod +x /usr/local/bin/wp && \
\
# Installing Transifex Client
apt-get update && \
apt-get install -y python3-pip gettext zip subversion && \
pip install transifex-client && \
\
# Clean up
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
@ -36,6 +40,5 @@ RUN cat /tmp/xdebug.ini >> $XDEBUGINI_PATH
# allow .htaccess files (between <Directory /var/www/> and </Directory>, which is WordPress installation)
RUN sed -i '/<Directory \/var\/www\/>/,/<\/Directory>/ s/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf
# ensure existing content in /var/www/html respects UID and GID, give Node permissions for Corepack
RUN chown -R ${UID}:${GID} /var/www/html && \
mkdir -p /.node && chown -R ${UID}:${GID} /.node
# ensure existing content in /var/www/html respects UID and GID
RUN chown -R ${UID}:${GID} /var/www/html

View File

@ -5,17 +5,21 @@ ARG GID=1000
# additinal extensions
RUN apt-get update \
&& apt-get install -y git zlib1g-dev libzip-dev zip wget gnupg msmtp libpng-dev gettext subversion \
&& apt-get install -y git zlib1g-dev libzip-dev zip wget gnupg msmtp libpng-dev \
&& \
# Install NodeJS, enable Corepack
curl -sL https://deb.nodesource.com/setup_17.x | bash - && \
# Install NodeJS + NPM
curl -sL https://deb.nodesource.com/setup_16.x | bash - && \
apt-get install -y nodejs build-essential && \
corepack enable && \
\
# Install WP-CLI
curl -o /usr/local/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
chmod +x /usr/local/bin/wp && \
\
# Installing Transifex Client
apt-get update && \
apt-get install -y python3-pip gettext subversion && \
pip3 install transifex-client && \
\
# Clean up
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
@ -40,6 +44,5 @@ RUN docker-php-ext-install pdo_mysql
# allow .htaccess files (between <Directory /var/www/> and </Directory>, which is WordPress installation)
RUN sed -i '/<Directory \/var\/www\/>/,/<\/Directory>/ s/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf
# ensure existing content in /var/www/html respects UID and GID, give Node permissions for Corepack
RUN chown -R ${UID}:${GID} /var/www/html && \
mkdir -p /.node && chown -R ${UID}:${GID} /.node
# ensure existing content in /var/www/html respects UID and GID
RUN chown -R ${UID}:${GID} /var/www/html

View File

@ -5,17 +5,21 @@ ARG GID=1000
# additinal extensions
RUN apt-get update \
&& apt-get install -y git zlib1g-dev libzip-dev zip wget gnupg msmtp libpng-dev gettext subversion \
&& apt-get install -y git zlib1g-dev libzip-dev zip wget gnupg msmtp libpng-dev \
&& \
# Install NodeJS, enable Corepack
curl -sL https://deb.nodesource.com/setup_17.x | bash - && \
# Install NodeJS + NPM
curl -sL https://deb.nodesource.com/setup_16.x | bash - && \
apt-get install -y nodejs build-essential && \
corepack enable && \
\
# Install WP-CLI
curl -o /usr/local/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
chmod +x /usr/local/bin/wp && \
\
# Installing Transifex Client
apt-get update && \
apt-get install -y python3-pip gettext subversion && \
pip3 install transifex-client && \
\
# Clean up
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
@ -40,6 +44,5 @@ RUN docker-php-ext-install pdo_mysql
# allow .htaccess files (between <Directory /var/www/> and </Directory>, which is WordPress installation)
RUN sed -i '/<Directory \/var\/www\/>/,/<\/Directory>/ s/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf
# ensure existing content in /var/www/html respects UID and GID, give Node permissions for Corepack
RUN chown -R ${UID}:${GID} /var/www/html && \
mkdir -p /.node && chown -R ${UID}:${GID} /.node
# ensure existing content in /var/www/html respects UID and GID
RUN chown -R ${UID}:${GID} /var/www/html

11
do
View File

@ -65,7 +65,7 @@ elif [ "$1" = "acceptance" ]; then
else
cd mailpoet
fi
COMPOSE_HTTP_TIMEOUT=200 docker-compose run codeception_acceptance -e KEEP_DEPS=1 --steps --debug -vvv
COMPOSE_HTTP_TIMEOUT=200 docker-compose run codeception -e KEEP_DEPS=1 --steps --debug -vvv
cd ..
elif [ "$1" = "build" ]; then
@ -82,16 +82,13 @@ else
docker_service="wordpress"
plugin_directory="mailpoet"
params=("$@")
if [ "$1" = "--test" -o "$2" = "--test" ]; then
if [ "$1" = "--test" -o "$2" = "--test" ]; then
docker_service="test_wordpress"
params=("${params[@]:1}")
cd mailpoet
./do ${params[*]}
exit 1
fi
if [ "$1" = "--premium" -o "$2" = "--premium" ]; then
plugin_directory="mailpoet-premium"
params=("${params[@]:1}")
fi
ssh_and_run $docker_service "cd wp-content/plugins/$plugin_directory && ./do ${params[*]}"
ssh_and_run $docker_service "cd wp-content/plugins/$plugin_directory && ./do ${params[@]}"
fi

View File

@ -1,46 +0,0 @@
# MailPoet Documentation for Integrators
This is a place where we put documentation for developers who want to build an extension for MailPoet plugin.
If you are a user looking for a user guide please visit our [knowledge base](https://kb.mailpoet.com/).
## MailPoet API
MailPoet API is the officially supported way to integrate with the MailPoet plugin. It focuses on functionality for managing subscribers.
Developers integrating MailPoet functionality in their own plugins or projects are strongly discouraged against using other functions and classes within MailPoet codebase! We are continually refactoring as part of our rapid development process, and backward compatibility is not guaranteed.
### Basics
MailPoet API is distributed within MailPoet3 plugin and it is implemented as a PHP class.
Currently supported version is `v1`.
### Instantiation
```php
if (class_exists(\MailPoet\API\API::class)) {
$mailpoet_api = \MailPoet\API\API::MP('v1');
}
```
Class `\MailPoet\API\API` becomes available once MailPoet plugin is loaded by WordPress.
### Available API Methods
- [Add List (addList)](api_methods/AddList.md)
- [Add Subscriber (addSubscriber)](api_methods/AddSubscriber.md)
- [Add Subscriber Field (addSubscriberField)](api_methods/AddSubscriberField.md)
- [Delete List (deleteList)](api_methods/DeleteList.md)
- [Get Lists (getLists)](api_methods/GetLists.md)
- [Get Subscriber (getSubscriber)](api_methods/GetSubscriber.md)
- [Get Subscribers (getSubscribers)](api_methods/GetSubscribers.md)
- [Get Subscribers Count (getSubscribersCount)](api_methods/GetSubscribersCount.md)
- [Get Subscriber Fields (getSubscriberFields)](api_methods/GetSubscriberFields.md)
- [Is Setup Complete (isSetupComplete)](api_methods/IsSetupComplete.md)
- [Subscribe to List (subscribeToList)](api_methods/SubscribeToList.md)
- [Subscribe to Lists (subscribeToLists)](api_methods/SubscribeToLists.md)
- [Unsubscribe from List (unsubscribeFromList)](api_methods/UnsubscribeFromList.md)
- [Unsubscribe from Lists (unsubscribeFromLists)](api_methods/UnsubscribeFromLists.md)
- [Update List (updateList)](api_methods/UpdateList.md)
### Usage examples
You can check some basic examples [here](UsageExamples.md).

View File

@ -1,35 +0,0 @@
[back to list](../Readme.md)
# Add Subscriber
## `array addList(array $list)`
In MailPoet, subscribers are organized into lists. This method provides functionality for creating a new list.
It returns the new list. See [Get Lists](GetLists.md) for a list data structure description.
## Arguments
### `$list` (required)
An associative array which contains list data.
| Property | Type | Limits | Description |
| ---------------------- | ------------ | --------- | -------------------------- |
| name (required) | string | 90 chars | A name of the list. |
| description (optional) | string\|null | 250 chars | A description of the list. |
## Error handling
All expected errors from the API are exceptions of class `\MailPoet\API\MP\v1\APIException`.
Code of the exception is populated to distinguish between different errors.
An exception of base class `\Exception` can be thrown when something unexpected happens.
Codes description:
| Code | Description |
| ---- | -------------------------------------------- |
| 14 | Missing list name |
| 15 | Trying to create a list that already exists |
| 16 | The list couldnt be created in the database |

View File

@ -1,66 +0,0 @@
[back to list](../Readme.md)
# Add Subscriber
## `array addSubscriber(array $subscriber [, array $list_ids = [], array $options = []])`
This method allows a subscriber to be created, adds them into lists, and handles confirmation email and admin notification email sending and welcome email scheduling.
If sign-up confirmation (double opt-in) is enabled in the MailPoet settings a subscriber is created with status `unconfirmed` otherwise the status is set to `subscribed`.
- _A confirmation email_ is an email which is sent to a subscriber so that they can confirm his subscription. It is sent only if sign-up confirmation is enabled in the MailPoet settings.
- _A welcome email_ is an automatic email which is sent to a new subscriber. This email is scheduled only if sign-up confirmation is disabled and a welcome email is configured for some of given lists. In case of required sign-up confirmation, it is scheduled later after a subscriber confirms the subscription.
- _An admin notification email_ is sent to the site admin to inform them about a new subscription. It is sent only if the notification feature is enabled in the MailPoet setting.
All these emails can be disabled using `$options`.
A subscriber can be added only once. This method throws an `\Exception` in case of adding an existing subscriber.
This method also throws an `\Exception` in case that some of `$list_ids` is invalid. In such a case a subscriber is created, but is not subscribed to any list.
There might be other `\Exceptions` because of some invalid input data such a invalid email address etc.
It returns a new subscriber. See [Get Subscriber](GetSubscriber.md) for a subscriber data structure.
## Arguments
### `$subscriber` (required)
An associative array containing subscriber data which contains default properties (email, first_name, last_name) and custom subscriber fields which were defined in MailPoet.
It has to contain an email and all required custom fields. To get defined custom fields see [Get Subscriber Fields](GetSubscriberFields.md)
| Property | Type | Limits | Description |
| -------------------------- | ------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| email (required) | string | 150 chars | a valid email address |
| first_name (optional) | string/null | 255 chars | Fist name of the subscriber. |
| last_name (optional) | string/null | 255 chars | Last name of the subscriber. |
| cf\_\* (optional/required) | string/boolean/null | 65K chars | A custom field (see [Get Subscriber Fields](GetSubscriberFields.md)). <br> If a custom field is a checkbox, send truthy or falsy value (`true`/`false, `1`/`0`or`"1"`\`"0"`). |
### `$list_ids` (optional)
An array containing list ids into which subscriber will be added.
In case that the list is empty a subscriber will be created; but sending a confirmation email, notification email and scheduling welcome email will be skipped.
### `$options` (optional)
All options are optional. If omitted a default value is used.
| Option | Type | Default | Description |
| ---------------------------- | ------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| send_confirmation_email | boolean | true | Can be used to disable a confirmation email. Otherwise, a confirmation email is sent as described above. It is strongly recommended to keep this option set to `true` so that MailPoet settings for sign-up confirmation are respected. Turning it to `false` might lead that subscriber to be added as `unconfirmed`. |
| schedule_welcome_email | boolean | true | Can be used to disable a welcome email. Otherwise, a welcome email is scheduled as described above. |
| skip_subscriber_notification | boolean | false | Can be used to disable an admin notification email. Otherwise, an admin notification email is sent as described above. |
## Error handling
All expected errors from the API are exceptions of class `\MailPoet\API\MP\v1\APIException`.
Code of the exception is populated to distinguish between different errors.
An exception of base class `\Exception` can be thrown when something unexpected happens.
Codes description:
| Code | Description |
| ---- | -------------------------------------------------- |
| 11 | Missing email address |
| 12 | Trying to create a subscriber that already exists |
| 13 | The subscriber couldnt be created in the database |
| 17 | Welcome email failed to send |

View File

@ -1,87 +0,0 @@
[back to list](../Readme.md)
# Add Subscriber Field
## `array addSubscriberField(array $data)`
Using this method you can create custom properties that can be used for storing additional data for each subscriber.
See [Subscriber Fields for more details](GetSubscriberFields.md)
## Arguments
### `$data` (required)
| Property | Type | Limits | Description |
| ----------------- | ------ | -------- | ------------------------------------------------------------------------------------------------- |
| name (required) | string | 90 chars | Human readable name. Intended to be used, as an example, as a label for form input. |
| type (required) | string | - | Type of the field. Possible values are: `text`, `date`, `textarea`, `radio`, `checkbox`, `select` |
| params (optional) | array | - | Contains various information, see examples below. |
### `$params`
Params array differs for each type.
The common properties for all types:
| Property | Type | Description |
| -------- | ------ | ------------------------------------------------------------------------------------------- |
| required | string | Indicates if the value must be provided for each subscriber. Possible values are: "1" or "" |
| label | string | Label used for displaying the field to the end user. |
#### `$params` for text, textarea types
| Property | Type | Description |
| -------- | ------ | ------------------------------------------------------------------------------------------- |
| validate | string | Can be used for validating input values. Possible values are: `number`, `alphanum`, `phone` |
#### `$params` for checkbox types
| Property | Type | Description |
| -------- | ----- | ------------------------------------------------------------ |
| values | array | Same array as for radio type. Must contain exactly 1 element |
#### `$params` for radio, select types
| Property | Type | Description |
| -------- | ----- | --------------------------------------------------------------------------------------------------- |
| values | array | Contains a list of options. Each element must contain a string `value` and can contain `is_checked` |
#### `$params` for date type
| Property | Type | Description |
| ----------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| date_type | string | Possible values are: Values: `year_month_day`, `year_month`, `month`, `day` |
| date_format | string | Values: for year_month_day: `MM/DD/YYYY`, `DD/MM/YYYY`, `YYYY/MM/DD`, for year_month: `YYYY/MM`, `MM/YY`, for year: `YYYY`, for month: `MM` |
## Response
| Property | Type | Limits | Description |
| ---------- | ------------ | -------- | ------------------------------------------------------------------------------------------------- |
| id | string | 11 chars | Field Id |
| name | string | 90 chars | Human readable name. Intended to be used, as an example, as a label for form input. |
| type | string | - | Type of the field. Possible values are: `text`, `date`, `textarea`, `radio`, `checkbox`, `select` |
| params | array | - | Contains various information, see examples below. |
| created_at | string\|null | - | UTC time of creation in `Y-m-d H:i:s` format |
| updated_at | string | - | UTC time of last update in `Y-m-d H:i:s` format |
## Error handling
All expected errors from the API are exceptions of class `\MailPoet\API\MP\v1\APIException`.
Code of the exception is populated to distinguish between different errors.
An exception of base class `\Exception` can be thrown when something unexpected happens.
Codes description:
| Code | Description |
| ---- | ---------------------------------------------------------------------------------- |
| 1 | The subscriber couldnt be created in the database |
| 1001 | Missing a mandatory field in the `$data` argument |
| 1002 | A mandatory field in the `$data` argument has wrong type |
| 1003 | `$params` is not an array |
| 1004 | Attempting to create a field with an unknown type |
| 1005 | Incorrect validate parameter for text type |
| 1006 | Passing a `values` array for the checkbox type that has incorrect number of values |
| 1007 | Incorrect `date_format` value |
| 1008 | Incorrect `date_type` value |
| 1009 | Missing `values` for select or radio types |
| 1010 | Empty `value` for select or radio types |

View File

@ -1,27 +0,0 @@
[back to list](../Readme.md)
# Delete List
## `bool deleteList(string $list_id)`
This method provides functionality for deleting a list that is of the type 'default'.
It returns a boolean value.
## Error handling
All expected errors from the API are exceptions of class `\MailPoet\API\MP\v1\APIException`.
Code of the exception is populated to distinguish between different errors.
An exception of base class `\Exception` can be thrown when something unexpected happens.
Codes description:
| Code | Description |
| ---- | --------------------------------------------------------------- |
| 5 | List does not exist |
| 18 | List id is empty |
| 20 | List cannot be deleted because its used for an automatic email |
| 21 | List cannot be deleted because its used for a form |
| 22 | The list couldnt be deleted from the database |
| 23 | Only lists of the type 'default' can be deleted |

View File

@ -1,45 +0,0 @@
[back to list](../Readme.md)
# Get Lists
## `array getLists()`
In MailPoet, subscribers are organized into lists. This method returns an array of available lists.
### A list data structure
| Property | Type | Limits | Description |
| ----------- | ------------ | --------- | ----------------------------------------------------------------------------------------------------------- |
| id | string | 11 chars | Id of the list |
| name | string | 90 chars | Name of the list |
| type | string | - | Type of the list. Currently, there is only one supported value: `default` |
| description | string | 250 chars | Description of the list |
| created_at | string\|null | - | UTC time of creation in 'Y-m-d H:i:s' format |
| updated_at | string | - | UTC time of last update in 'Y-m-d H:i:s' format |
| deleted_at | string\|null | - | This property is not null only when the list is in the trash. It contains UTC time in 'Y-m-d H:i:s' format. |
### Response Example
```php
<?php
[
0 => [
'id' => '3',
'name' => 'Newsletter mailing list',
'type' => 'default',
'description' => 'This list is automatically created when you install MailPoet.',
'created_at' => '2019-05-07 07:24:37',
'updated_at' => '2019-05-07 07:24:37',
'deleted_at' => NULL,
],
1 => [
'id' => '5',
'name' => 'Second list',
'type' => 'default',
'description' => '',
'created_at' => '2019-05-15 11:38:46',
'updated_at' => '2019-05-15 11:41:25',
'deleted_at' => '2019-05-15 11:41:25',
],
]
```

View File

@ -1,136 +0,0 @@
[back to list](../Readme.md)
# Get Subscriber
## `array getSubscriber(string $subscriber_email)`
This method throws an `\Exception` in the event a subscriber with a given email address doesnt exist.
## Arguments
| Argument | Type | Description |
| ----------------- | ------ | --------------------- |
| $subscriber_email | string | a valid email address |
## A subscriber data structure
### Subscriber
| Property | Type | Limits | Description |
| ------------------------ | ------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------ |
| id | string | 11 chars | Id of the subscriber |
| wp_user_id | string\|null | 20 chars | Id of a WordPress user associated with the subscriber |
| is_woocommerce_user | string | - | A flag telling whether the user is also a WooCommerce customer. Possible values are: `1`, `0` |
| first_name | string | 255 chars | Fist name of the subscriber. |
| last_name | string | 255 chars | Last name of the subscriber. |
| email | string | 150 chars | Email address of the subscriber. |
| status | string | - | Status of the subscriber. Possible values are: `unconfirmed`, `subscribed`, `unsubscribed`, `bounced`, `inactive` |
| subscribed_ip | string\|null | 45 chars | An IP address used for subscription. |
| confirmed_ip | string\|null | 45 chars | An IP address used for confirmation. |
| confirmed_at | string\|null | - | UTC time of subscription confirmation in 'Y-m-d H:i:s' format |
| created_at | string\|null | - | UTC time of creation in 'Y-m-d H:i:s' format |
| updated_at | string | - | UTC time of last update in 'Y-m-d H:i:s' format |
| deleted_at | string\|null | - | This property in not null in case that list is in trash and contains UTC time in 'Y-m-d H:i:s' format. |
| unconfirmed_data | string\|null | 65K chars | May contain serialized subscriber data in case when there are pending changes waiting for a confirmation from a subscriber |
| source | string\|null | - | Possible values: `form`,`imported`,`administrator`,`api`,`wordpress_user`,`woocommerce_user`,`woocommerce_checkout`,`unknown`) |
| count_confirmations | string | 11 chars | Counter for confirmation emails |
| subscriptions | array | - | List of subcriber subscriptions |
| tags | array | - | List of subcriber tags |
| cf\_{custom_field['id']} | string | 65K chars | A custom subscriber field value (see [Get Subscriber Fields](GetSubscriberFields.md) |
### Subscriber's subscription
| Property | Type | Limits | Description |
| ------------- | ------ | -------- | ------------------------------------------------------------------------------------ |
| id | string | 11 chars | Id of relation |
| subscriber_id | string | 11 chars | Id of subscriber |
| segment_id | string | 11 chars | Id of a list |
| status | string | - | Status of a subscription for the list. Possible values: `subscribed`, `unsubscribed` |
| created_at | string | - | UTC time of creation in 'Y-m-d H:i:s' format |
| updated_at | string | - | UTC time of last update in 'Y-m-d H:i:s' format |
### Subscriber's tag
| Property | Type | Limits | Description |
| ------------- | ------ | -------- | ----------------------------------------------- |
| id | string | 11 chars | Id of relation |
| subscriber_id | string | 11 chars | Id of subscriber |
| tag_id | string | 11 chars | Id of a list |
| name | string | - | Name of a tag |
| created_at | string | - | UTC time of creation in 'Y-m-d H:i:s' format |
| updated_at | string | - | UTC time of last update in 'Y-m-d H:i:s' format |
### Response Example
```php
<?php
[
'id' => '10',
'wp_user_id' => '72',
'is_woocommerce_user' => '1',
'first_name' => 'John',
'last_name' => 'Doe',
'email' => 'email@example.com',
'status' => 'subscribed',
'subscribed_ip' => '127.0.0.1',
'confirmed_ip' => NULL,
'confirmed_at' => NULL,
'created_at' => '2019-05-07 07:24:37',
'updated_at' => '2019-05-14 08:43:08',
'deleted_at' => NULL,
'unconfirmed_data' => NULL,
'source' => 'woocommerce_user',
'count_confirmations' => '0',
'subscriptions' => [
0 => [
'id' => '3',
'subscriber_id' => '10',
'segment_id' => '1',
'status' => 'subscribed',
'created_at' => '2019-05-07 07:24:37',
'updated_at' => '2019-05-07 07:24:37',
],
1 => [
'id' => '13',
'subscriber_id' => '10',
'segment_id' => '2',
'status' => 'unsubscribed',
'created_at' => '2019-05-14 08:43:08',
'updated_at' => '2019-05-14 08:43:08',
],
],
'tags' => [
0 => [
'id' => '2',
'subscriber_id' => '10',
'tag_id' => '1',
'name' => 'Alpha',
'created_at' => '2019-05-17 05:24:37',
'updated_at' => '2019-05-17 05:24:37',
],
1 => [
'id' => '4',
'subscriber_id' => '10',
'tag_id' => '5',
'name' => 'Beta',
'created_at' => '2020-03-07 15:21:37',
'updated_at' => '2020-03-07 15:21:37',
],
],
'cf_1' => 'US',
'cf_2' => 'New York',
];
```
## Error handling
All expected errors from the API are exceptions of class `\MailPoet\API\MP\v1\APIException`.
Code of the exception is populated to distinguish between different errors.
An exception of base class `\Exception` can be thrown when something unexpected happens.
Codes description:
| Code | Description |
| ---- | -------------------------------------------- |
| 4 | Asking for a subscriber that does not exist. |

View File

@ -1,25 +0,0 @@
[back to list](../Readme.md)
# Get Subscribers
## `array getSubscribers(array $filter = [], int $limit = 50, int $offset = 0)`
This method returns a list of subscribers. To see the subscriber data structure, please check [getSubscriber()](GetSubscriber.md) documentation.
## Arguments
| Argument | Type | Default | Description |
| ------------------ | ----- | ------- | --------------------------------------- |
| $filter (optional) | array | empty | Filters to retrieve subscribers |
| $limit (optional) | int | 50 | The number of results that are returned |
| $offset (optional) | int | 0 | From where to start returning data |
### Filter
Filter argument supports following array keys.
| Key | Type | Description |
| ------------ | ------------ | ----------------------------------------------------------------------------------------------------------------- |
| status | string | Specific status of subscribers. One of values: `unconfirmed`, `subscribed`, `unsubscribed`, `bounced`, `inactive` |
| listId | int | List id or dynamic segment id |
| minUpdatedAt | DateTime\int | DateTime object or timestamp of the minimal last update of subscribers |

View File

@ -1,17 +0,0 @@
[back to list](../Readme.md)
# Get Subscribers Count
## `int getSubscribersCount(array $filter = [])`
This method returns the count of subscribers by a filter.
## Arguments
| Argument | Type | Default | Description |
| ------------------ | ----- | ------- | -------------------------------------------- |
| $filter (optional) | array | empty | Filters to retrieve the count of subscribers |
### Filter
To see supported filters, please check [getSubscribers()](GetSubscribers.md) documentation.

View File

@ -1,55 +0,0 @@
[back to list](../Readme.md)
# Subscribe to Lists
## `array subscribeToLists(string $subscriber_id, array $list_ids [, array $options = []])`
This method allows adding an existing subscriber into lists and handles confirmation email and admin notification email sending.
- _A confirmation email_ is an email which is sent to a subscriber so they can confirm their subscription. It is sent only if sign-up confirmation is enabled in MailPoet settings and subscriber has not received any confirmation email yet.
- _A welcome email_ is an automatic email which is sent to a new subscriber. This email is scheduled only if sign-up confirmation is disabled and some welcome email is configured for some of given lists.
- _An admin notification email_ is sent to the site admin to inform them about a new subscription. It is sent only if the notification feature is enabled in the MailPoet setting.
All these emails can be disabled using `$options`.
It returns a subscriber. See [Get Subscriber](GetSubscriber.md) for a subscriber data structure.
## Arguments
### string `$subscriber_id` (required)
An id or an email address. An `\Exception` is thrown when the value doesn't match any subscriber.
### array `$list_ids` (required)
An array of list ids. An `\Exception` is thrown if any of list ids are invalid. In such a case the subscriber isn't added to any list.
### array `$options` (optional)
All options are optional. If omitted, a default value is used.
| Option | Type | Default | Description |
| ---------------------------- | ------- | ------- | ---------------------------------------------------------------------------------------------------------------------- |
| send_confirmation_email | boolean | true | Can be used to disable confirmation email. Otherwise, a confirmation email is sent as described above. |
| schedule_welcome_email | boolean | true | Can be used to disable welcome email. Otherwise, a welcome email is scheduled as described above. |
| skip_subscriber_notification | boolean | false | Can be used to disable an admin notification email. Otherwise, an admin notification email is sent as described above. |
## Error handling
All expected errors from the API are exceptions of class `\MailPoet\API\MP\v1\APIException`.
Code of the exception is populated to distinguish between different errors.
An exception of base class `\Exception` can be thrown when something unexpected happens.
Codes description:
| Code | Description |
| ---- | ------------------------------------------------------- |
| 3 | No lists provided |
| 4 | Invalid subscriber that does not exist |
| 5 | Invalid list that does not exist |
| 6 | Trying to subscribe to a WordPress Users list |
| 7 | Trying to subscribe to a WooCommerce Customers list |
| 8 | Trying to subscribe to a list that doesnt support that |
| 10 | Confirmation email failed to send |
| 17 | Welcome email failed to send |

View File

@ -1,39 +0,0 @@
[back to list](../Readme.md)
# Add Subscriber
## `array updateList(array $list)`
This method provides functionality for updating a list name or description. Only lists of type 'default' are supported.
It returns the updated list. See [Get Lists](GetLists.md) for a list data structure description.
## Arguments
### `$list` (required)
An associative array which contains list data.
| Property | Type | Limits | Description |
| ---------------------- | ------------ | --------- | -------------------------- |
| id (required) | string | 11 chars | A id of the list. |
| name (required) | string | 90 chars | A name of the list. |
| description (optional) | string\|null | 250 chars | A description of the list. |
## Error handling
All expected errors from the API are exceptions of class `\MailPoet\API\MP\v1\APIException`.
Code of the exception is populated to distinguish between different errors.
An exception of base class `\Exception` can be thrown when something unexpected happens.
Codes description:
| Code | Description |
| ---- | ----------------------------------------------- |
| 5 | The list was not found by id |
| 14 | Missing list name |
| 15 | Trying to use a list name that is already used |
| 18 | Missing list id |
| 19 | The list couldnt be updated in the database |
| 23 | Only lists of the type 'default' can be updated |

View File

@ -22,16 +22,16 @@ volumes:
driver_opts:
type: nfs
o: addr=host.docker.internal,nolock
device: ':/System/Volumes/Data${PWD}/wordpress'
device: ":/System/Volumes/Data${PWD}/wordpress"
nfs-mailpoet:
driver: local
driver_opts:
type: nfs
o: addr=host.docker.internal,nolock
device: ':/System/Volumes/Data${PWD}/mailpoet'
device: ":/System/Volumes/Data${PWD}/mailpoet"
nfs-mailpoet-premium:
driver: local
driver_opts:
type: nfs
o: addr=host.docker.internal,nolock
device: ':/System/Volumes/Data${PWD}/mailpoet-premium'
device: ":/System/Volumes/Data${PWD}/mailpoet-premium"

View File

@ -26,13 +26,12 @@ services:
container_name: mp-wp
build:
context: .
dockerfile: dev/php81/Dockerfile
dockerfile: dev/php80/Dockerfile
args:
UID: ${UID:-1000}
GID: ${GID:-1000}
ports:
- '8002:80'
- '8083:8083' # Storybook port number, see package.json
- "8002:80"
depends_on:
- db
- smtp
@ -43,32 +42,26 @@ services:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
PHP_IDE_CONFIG: 'serverName=Mailpoet'
COMPOSER_HOME: '/tmp/.composer'
NPM_CONFIG_CACHE: '/tmp/.npm'
PHP_IDE_CONFIG: "serverName=Mailpoet"
COMPOSER_HOME: "/tmp/.composer"
NPM_CONFIG_CACHE: "/tmp/.npm"
MAILPOET_DEV_SITE: 1
volumes:
- './wordpress:/var/www/html'
- './tsconfig.base.json:/var/www/html/wp-content/plugins/tsconfig.base.json:ro'
- './package.json:/var/www/html/wp-content/plugins/package.json'
- './pnpm-lock.yaml:/var/www/html/wp-content/plugins/pnpm-lock.yaml'
- './pnpm-workspace.yaml:/var/www/html/wp-content/plugins/pnpm-workspace.yaml'
- './patches:/var/www/html/wp-content/plugins/patches'
- './mailpoet:/var/www/html/wp-content/plugins/mailpoet'
- './mailpoet-premium:/var/www/html/wp-content/plugins/mailpoet-premium'
- './packages:/var/www/html/wp-content/plugins/packages'
- './templates:/var/www/templates'
- "./wordpress:/var/www/html"
- "./mailpoet:/var/www/html/wp-content/plugins/mailpoet"
- "./mailpoet-premium:/var/www/html/wp-content/plugins/mailpoet-premium"
- "./templates:/var/www/templates"
test_wordpress:
container_name: mp-test-wp
build:
context: .
dockerfile: dev/php81/Dockerfile
dockerfile: dev/php80/Dockerfile
args:
UID: ${UID:-1000}
GID: ${GID:-1000}
ports:
- '8003:80'
- "8003:80"
depends_on:
- db
- smtp
@ -78,11 +71,10 @@ services:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
PHP_IDE_CONFIG: 'serverName=Mailpoet'
PHP_IDE_CONFIG: "serverName=Mailpoet"
volumes:
- './mailpoet:/var/www/html/wp-content/plugins/mailpoet'
- './mailpoet-premium:/var/www/html/wp-content/plugins/mailpoet-premium'
- './packages:/var/www/html/wp-content/plugins/packages'
- "./mailpoet:/var/www/html/wp-content/plugins/mailpoet"
- "./mailpoet-premium:/var/www/html/wp-content/plugins/mailpoet-premium"
smtp:
container_name: mp-mailhog
@ -92,9 +84,9 @@ services:
MH_STORAGE: maildir
MH_MAILDIR_PATH: /output
volumes:
- './dev/data/mailhog:/output'
- "./dev/data/mailhog:/output"
ports:
- '8082:8025'
- "8082:8025"
adminer:
container_name: mp-adminer
@ -102,9 +94,9 @@ services:
depends_on:
- db
ports:
- '8081:8080'
- "8081:8080"
volumes:
- './dev/php.ini:/usr/local/etc/php/conf.d/custom.ini'
- "./dev/php.ini:/usr/local/etc/php/conf.d/custom.ini"
volumes:
my-datavolume:

View File

@ -1,10 +1,13 @@
{
"presets": [
"@babel/preset-typescript",
["@babel/preset-react", { "runtime": "automatic" }],
"@babel/preset-react",
"@babel/preset-env"
],
"plugins": [
"@babel/plugin-proposal-nullish-coalescing-operator",
"babel-plugin-typescript-to-proptypes",
"@babel/plugin-proposal-class-properties",
[
"@babel/plugin-transform-runtime",
{
@ -12,7 +15,18 @@
"corejs": 3
}
],
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-syntax-import-meta",
"@babel/plugin-proposal-json-strings",
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
"@babel/plugin-proposal-function-sent",
"@babel/plugin-proposal-export-namespace-from",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-throw-expressions"
]
}

View File

@ -4,7 +4,7 @@ WP_TEST_MAILER_ENABLE_SENDING=true
WP_TEST_ENABLE_NETWORK_TESTS=true
# Optional: for multisite acceptance tests
WP_ROOT_MULTISITE=/var/www/html
WP_ROOT_MULTISITE=/var/www/wordpress
WP_TEST_MULTISITE_SLUG=
HTTP_HOST= # URL of your site (used for multisite env, equals to DOMAIN_CURRENT_SITE from wp-config.php)

View File

@ -1,11 +1,9 @@
{
"extends": ["airbnb/legacy", "prettier"],
"extends": "airbnb/legacy",
"env": {
"amd": true,
"browser": true
},
"plugins": ["eslint-plugin-import"],
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
@ -13,6 +11,6 @@
"rules": {
"import/prefer-default-export": 0, // we want to stop using default exports and start using named exports
"no-underscore-dangle": 0, // Backbone uses underscores, we cannot remove them
"import/no-default-export": 1 // no default exports
"comma-dangle": ["error", "always-multiline"]
}
}

View File

@ -1,18 +1,21 @@
{
"extends": ["airbnb", "plugin:react/jsx-runtime", "prettier"],
"extends": "airbnb",
"env": {
"amd": true,
"browser": true,
"mocha": true
},
"parser": "@babel/eslint-parser",
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 6,
"ecmaFeatures": {
"jsx": true
}
},
"plugins": ["react-hooks", "no-only-tests"],
"plugins": [
"react-hooks",
"no-only-tests"
],
"settings": {
"import/resolver": "webpack"
},
@ -21,28 +24,26 @@
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
// Exceptions
"arrow-parens": ["error", "always"],
"comma-dangle": ["error", "always-multiline"],
"no-only-tests/no-only-tests": 2,
"no-script-url": 0,
"class-methods-use-this": 0,
"react/jsx-props-no-spreading": 0,
"import/extensions": 0, // we wouldn't be able to import jQuery without this line
"import/prefer-default-export": 0, // we want to stop using default exports and start using named exports
"react/destructuring-assignment": 0, // that would be too many changes to fix this one
"prefer-destructuring": 0, // that would be too many changes to fix this one
"jsx-a11y/label-has-for": [
2,
{
"required": { "some": ["nesting", "id"] } // some of our labels are hidden and we cannot nest those
}
],
"jsx-a11y/label-has-for": [2, {
"required": {"some": ["nesting", "id"]} // some of our labels are hidden and we cannot nest those
}],
"jsx-a11y/anchor-is-valid": 0, // cannot fix this one, it would break wprdpress themes
"jsx-a11y/label-has-associated-control": [
2,
{
"either": "either" // control has to be either nested or associated via htmlFor
}
],
"import/no-default-export": 1 // no default exports
"jsx-a11y/label-has-associated-control": [ 2, {
"either": "either" // control has to be either nested or associated via htmlFor
}],
"indent": ["error", 2, {// bug in babel eslint https://github.com/babel/babel-eslint/issues/681#issuecomment-451336031 we can remove this whole exception in the future when the bug is fixed
"ignoredNodes": ["TemplateLiteral"],
"SwitchCase": 1
}],
"template-curly-spacing": "off"// bug in babel eslint https://github.com/babel/babel-eslint/issues/681#issuecomment-623101005 we can remove this whole exception in the future when the bug is fixed
},
"overrides": [
{
@ -53,3 +54,4 @@
}
]
}

View File

@ -1,10 +1,9 @@
{
"extends": ["airbnb/legacy", "prettier"],
"extends": "airbnb/legacy",
"env": {
"amd": true,
"mocha": true
},
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
@ -13,6 +12,7 @@
"no-only-tests/no-only-tests": 2,
// Exceptions
"func-names": 0,
"comma-dangle": ["error", "always-multiline"],
// Temporary
"no-underscore-dangle": 0
},

View File

@ -1,12 +1,9 @@
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"airbnb",
"airbnb-typescript",
"plugin:react/jsx-runtime",
"prettier"
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking"
],
"env": {
"amd": true,
@ -22,7 +19,11 @@
"jsx": true
}
},
"plugins": ["react-hooks", "no-only-tests", "@typescript-eslint"],
"plugins": [
"react-hooks",
"no-only-tests",
"@typescript-eslint"
],
"settings": {
"import/resolver": "webpack",
"import/core-modules": [
@ -41,7 +42,6 @@
]
},
"rules": {
"react/no-unstable-nested-components": ["error", { "allowAsProps": true }],
// PropTypes
"react/prop-types": 0,
"react/jsx-props-no-spreading": 0,
@ -50,55 +50,44 @@
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
// Exceptions
"@typescript-eslint/no-explicit-any": "error", // make it an error instead of warning - we treat them the same, this is more visible
"no-void": 0, // can conflict with @typescript-eslint/no-floating-promises
"react/jsx-no-useless-fragment": [
"@typescript-eslint/no-explicit-any": "error", // make it an error instead of warning - we treat them the same, this is more visible
"no-use-before-define": 0, //use the typescript version
"camelcase": 0, //use the typescript version
"no-shadow": 0, //use the typescript version
"@typescript-eslint/naming-convention": [
"error",
{
"allowExpressions": true
}
{ "selector": "classProperty", "format": [] },
{ "selector": "typeProperty", "format": [] },
{ "selector": "objectLiteralProperty", "format": [] },
{ "selector": "variableLike", "format": ["UPPER_CASE", "camelCase", "PascalCase"] }
],
"react/jsx-filename-extension": 0,
"class-methods-use-this": 0,
"arrow-parens": ["error", "always"],
"comma-dangle": ["error", "always-multiline"],
"no-only-tests/no-only-tests": 2,
"no-script-url": 0,
"@typescript-eslint/no-unsafe-return": 0, // we need to disable it for wordpress select :(
"@typescript-eslint/no-unsafe-member-access": 0, // this needs to be off until we have typed assignments :(
"@typescript-eslint/no-unsafe-call": 0, // this needs to be off until we have typed assignments :(
"@typescript-eslint/no-unsafe-assignment": 0, // this needs to be off until we have typed assignments :(
"@typescript-eslint/no-unsafe-member-access": 0, // this needs to be off until mailpoet.js is converted to typescript
"@typescript-eslint/no-unsafe-call": 0, // this needs to be off until mailpoet.js is converted to typescript
"@typescript-eslint/no-unsafe-assignment": 0, // this needs to be off until mailpoet.js is converted to typescript
"import/extensions": 0, // we wouldn't be able to import jQuery without this line
"import/no-named-as-default": 0, // we use named default exports at the moment
"import/prefer-default-export": 0, // we want to stop using default exports and start using named exports
"react/destructuring-assignment": 0, // that would be too many changes to fix this one
"prefer-destructuring": 0, // that would be too many changes to fix this one
"jsx-a11y/label-has-for": [
2,
{
"required": { "some": ["nesting", "id"] } // some of our labels are hidden and we cannot nest those
}
],
"jsx-a11y/label-has-for": [2, {
"required": {"some": ["nesting", "id"]} // some of our labels are hidden and we cannot nest those
}],
"jsx-a11y/anchor-is-valid": 0, // cannot fix this one, it would break wprdpress themes
"jsx-a11y/label-has-associated-control": [
2,
{
"either": "either" // control has to be either nested or associated via htmlFor
}
],
"import/no-default-export": 1 // no default exports
"jsx-a11y/label-has-associated-control": [ 2, {
"either": "either" // control has to be either nested or associated via htmlFor
}],
"@typescript-eslint/explicit-module-boundary-types": "error"
},
"overrides": [
{
"files": ["*.spec.ts"],
"rules": {
"no-unused-expressions": "off"
}
},
{
"files": ["**/_stories/*.tsx"],
"rules": {
"import/no-extraneous-dependencies": [
"error",
{ "devDependencies": true }
],
"import/no-default-export": 0
"import/no-extraneous-dependencies": ["error", { "devDependencies": true }]
}
},
{

1
mailpoet/.gitignore vendored
View File

@ -8,6 +8,7 @@ tests/_output/*
tests/_support/_generated/*
tests/plugins
.env
.transifexrc
/views/cache/**
temp
mailpoet.zip

View File

@ -1 +1 @@
v17.9.1
v16.13.0

View File

@ -1,6 +1,6 @@
const path = require('path');
const modulesDir = path.join(__dirname, '../node_modules');
const modulesDir = path.join( __dirname, '../node_modules' );
console.log('NODE', modulesDir);
// Workaround for Emotion 11
// https://github.com/storybookjs/storybook/pull/13300#issuecomment-783268111

View File

@ -6,9 +6,4 @@ import '../assets/dist/css/mailpoet-plugin.css';
import '../assets/dist/css/mailpoet-form-editor.css';
addDecorator(withPerformance);
addDecorator((story) => (
<div className="wp-core-ui" id="wpbody">
<div id="mailpoet-modal"></div>
{story()}
</div>
));
addDecorator(story => <div className="wp-core-ui" id="wpbody"><div id="mailpoet-modal"></div>{story()}</div>);

View File

@ -1,106 +1,110 @@
{
'plugins': ['stylelint-order', 'stylelint-scss'],
'customSyntax': 'postcss-scss',
'rules':
{
'at-rule-empty-line-before':
['always', { except: ['first-nested', 'blockless-after-blockless'] }],
'at-rule-name-case': 'lower',
'at-rule-semicolon-newline-after': 'always',
'block-closing-brace-empty-line-before': 'never',
'block-closing-brace-newline-after': 'always',
'block-closing-brace-newline-before': 'always-multi-line',
'block-closing-brace-space-before': 'always-single-line',
'block-no-empty': true,
'block-opening-brace-newline-after': 'always-multi-line',
'block-opening-brace-space-after': 'always-single-line',
'block-opening-brace-space-before': 'always',
'color-hex-case': 'lower',
'color-hex-length': 'short',
'color-no-invalid-hex': true,
'comment-no-empty': true,
'comment-whitespace-inside': 'always',
'declaration-bang-space-after': 'never',
'declaration-bang-space-before': 'always',
'declaration-block-no-duplicate-properties':
[true, { ignore: ['consecutive-duplicates-with-different-values'] }],
'declaration-block-no-redundant-longhand-properties':
[true, { ignoreShorthands: [/flex/, /grid/] }],
'declaration-block-semicolon-newline-after': 'always-multi-line',
'declaration-block-semicolon-space-after': 'always-single-line',
'declaration-block-semicolon-space-before': 'never',
'declaration-block-single-line-max-declarations': 1,
'declaration-colon-newline-after': 'always-multi-line',
'declaration-colon-space-after': 'always-single-line',
'declaration-colon-space-before': 'never',
'declaration-empty-line-before': 'never',
'font-family-no-duplicate-names': true,
'function-comma-space-after': 'always-single-line',
'function-comma-space-before': 'never',
'function-max-empty-lines': 0,
'function-name-case': 'lower',
'function-parentheses-newline-inside': 'always-multi-line',
'function-parentheses-space-inside': 'never-single-line',
'function-url-quotes': 'always',
'function-whitespace-after': 'always',
'indentation': 2,
'keyframe-declaration-no-important': true,
'length-zero-no-unit': true,
'max-empty-lines': 1,
'media-feature-colon-space-after': 'always',
'media-feature-colon-space-before': 'never',
'media-feature-name-case': 'lower',
'media-feature-name-no-unknown': true,
'media-feature-parentheses-space-inside': 'never',
'media-feature-range-operator-space-after': 'always',
'media-query-list-comma-newline-after': 'always-multi-line',
'media-query-list-comma-space-after': 'always-single-line',
'media-query-list-comma-space-before': 'never',
'no-duplicate-selectors': true,
'no-eol-whitespace': true,
'no-extra-semicolons': true,
'no-missing-end-of-source-newline': true,
'number-leading-zero': 'never',
'number-no-trailing-zeros': true,
'order/properties-alphabetical-order': true,
'property-case': 'lower',
'property-no-unknown': true,
'rule-empty-line-before':
[
'always-multi-line',
{ except: ['first-nested'], ignore: ['after-comment'] },
],
'scss/at-rule-no-unknown': true,
'scss/dollar-variable-colon-space-after': 'always',
'scss/dollar-variable-colon-space-before': 'never',
'scss/operator-no-newline-after': true,
'scss/operator-no-newline-before': true,
'scss/operator-no-unspaced': true,
'scss/selector-no-redundant-nesting-selector': true,
'selector-attribute-brackets-space-inside': 'never',
'selector-attribute-operator-space-after': 'never',
'selector-attribute-operator-space-before': 'never',
'selector-combinator-space-after': 'always',
'selector-combinator-space-before': 'always',
'selector-list-comma-newline-after': 'always',
'selector-list-comma-space-before': 'never',
'selector-max-empty-lines': 0,
'selector-nested-pattern': '^(?!&-|&_).*',
'selector-pseudo-class-case': 'lower',
'selector-pseudo-class-no-unknown': true,
'selector-pseudo-class-parentheses-space-inside': 'never',
'selector-pseudo-element-case': 'lower',
'selector-pseudo-element-colon-notation': 'single',
'selector-pseudo-element-no-unknown': true,
'selector-type-case': 'lower',
'shorthand-property-no-redundant-values': true,
'string-no-newline': true,
'string-quotes': 'single',
'unit-case': 'lower',
'unit-no-unknown': true,
'value-list-comma-newline-after': 'always-multi-line',
'value-list-comma-space-after': 'always-single-line',
'value-list-comma-space-before': 'never',
'value-list-max-empty-lines': 0,
},
"plugins": [
"stylelint-order",
"stylelint-scss"
],
"customSyntax": "postcss-scss",
"rules": {
"at-rule-empty-line-before": ["always", {
except: ["first-nested", "blockless-after-blockless"],
}],
"at-rule-name-case": "lower",
"at-rule-semicolon-newline-after": "always",
"block-closing-brace-empty-line-before": "never",
"block-closing-brace-newline-after": "always",
"block-closing-brace-newline-before": "always-multi-line",
"block-closing-brace-space-before": "always-single-line",
"block-no-empty": true,
"block-opening-brace-newline-after": "always-multi-line",
"block-opening-brace-space-after": "always-single-line",
"block-opening-brace-space-before": "always",
"color-hex-case": "lower",
"color-hex-length": "short",
"color-no-invalid-hex": true,
"comment-no-empty": true,
"comment-whitespace-inside": "always",
"declaration-bang-space-after": "never",
"declaration-bang-space-before": "always",
"declaration-block-no-duplicate-properties": [true, {
ignore: ["consecutive-duplicates-with-different-values"],
}],
"declaration-block-no-redundant-longhand-properties": [true, {
ignoreShorthands: [/flex/, /grid/]
}],
"declaration-block-semicolon-newline-after": "always-multi-line",
"declaration-block-semicolon-space-after": "always-single-line",
"declaration-block-semicolon-space-before": "never",
"declaration-block-single-line-max-declarations": 1,
"declaration-colon-newline-after": "always-multi-line",
"declaration-colon-space-after": "always-single-line",
"declaration-colon-space-before": "never",
"declaration-empty-line-before": "never",
"font-family-no-duplicate-names": true,
"function-comma-space-after": "always-single-line",
"function-comma-space-before": "never",
"function-max-empty-lines": 0,
"function-name-case": "lower",
"function-parentheses-newline-inside": "always-multi-line",
"function-parentheses-space-inside": "never-single-line",
"function-url-quotes": "always",
"function-whitespace-after": "always",
"indentation": 2,
"keyframe-declaration-no-important": true,
"length-zero-no-unit": true,
"max-empty-lines": 1,
"media-feature-colon-space-after": "always",
"media-feature-colon-space-before": "never",
"media-feature-name-case": "lower",
"media-feature-name-no-unknown": true,
"media-feature-parentheses-space-inside": "never",
"media-feature-range-operator-space-after": "always",
"media-query-list-comma-newline-after": "always-multi-line",
"media-query-list-comma-space-after": "always-single-line",
"media-query-list-comma-space-before": "never",
"no-duplicate-selectors": true,
"no-eol-whitespace": true,
"no-extra-semicolons": true,
"no-missing-end-of-source-newline": true,
"number-leading-zero": "never",
"number-no-trailing-zeros": true,
"order/properties-alphabetical-order": true,
"property-case": "lower",
"property-no-unknown": true,
"rule-empty-line-before": ["always-multi-line", {
except: ["first-nested"],
ignore: ["after-comment"]
}],
"scss/at-rule-no-unknown": true,
"scss/dollar-variable-colon-space-after": "always",
"scss/dollar-variable-colon-space-before": "never",
"scss/operator-no-newline-after": true,
"scss/operator-no-newline-before": true,
"scss/operator-no-unspaced": true,
"scss/selector-no-redundant-nesting-selector": true,
"selector-attribute-brackets-space-inside": "never",
"selector-attribute-operator-space-after": "never",
"selector-attribute-operator-space-before": "never",
"selector-combinator-space-after": "always",
"selector-combinator-space-before": "always",
"selector-list-comma-newline-after": "always",
"selector-list-comma-space-before": "never",
"selector-max-empty-lines": 0,
"selector-nested-pattern": "^(?!&-|&_).*",
"selector-pseudo-class-case": "lower",
"selector-pseudo-class-no-unknown": true,
"selector-pseudo-class-parentheses-space-inside": "never",
"selector-pseudo-element-case": "lower",
"selector-pseudo-element-colon-notation": "single",
"selector-pseudo-element-no-unknown": true,
"selector-type-case": "lower",
"shorthand-property-no-redundant-values": true,
"string-no-newline": true,
"string-quotes": "single",
"unit-case": "lower",
"unit-no-unknown": true,
"value-list-comma-newline-after": "always-multi-line",
"value-list-comma-space-after": "always-single-line",
"value-list-comma-space-before": "never",
"value-list-max-empty-lines": 0,
},
}

View File

@ -1,9 +1,9 @@
[main]
host = https://www.transifex.com
[o:wysija:p:mp3:r:mailpoet]
file_filter = lang/mailpoet-<lang>.po
source_file = lang/mailpoet.pot
source_lang = en_US
type = PO
[mp3.mailpoet]
file_filter = lang/mailpoet-<lang>.po
minimum_perc = 30
source_file = lang/mailpoet.pot
source_lang = en_US
type = PO

View File

@ -1,5 +1,4 @@
# MailPoet
The **MailPoet** plugin.
To use the official Docker-based development environment, see details
@ -17,13 +16,11 @@ below.
## Setup
### Requirements
- PHP >= 7.3 (only for the development environment, to run the plugin PHP >= 7.2 is required)
- NodeJS
- WordPress
### Installation
The instructions below assume you already have a working WordPress development environment:
```bash
@ -150,7 +147,7 @@ which will create a `storybook-static` folder with all necessary files. Don't fo
### DI
We use Symfony/dependency-injection container. Container configuration can be found in `lib/DI/ContainerFactory.php`
We use Symfony/dependency-injection container. Container configuration can be found in `libs/DI/ContainerFactory.php`
The container is configured and used with minimum sub-dependencies to keep final package size small.
You can check [the docs](https://symfony.com/doc/3.4/components/dependency_injection.html) to learn more about Symfony Container.
@ -174,7 +171,8 @@ _x('text to translate', 'context for translators', 'mailpoet');
**in Twig views**
```html
<%= __('text to translate') %> <%= _n('single text', 'plural text', $number) %>
<%= __('text to translate') %>
<%= _n('single text', 'plural text', $number) %>
<%= _x('text to translate', 'context for translators') %>
```
@ -185,8 +183,12 @@ The domain `mailpoet` will be added automatically by the Twig functions.
First add the string to the translations block in the Twig view:
```html
<% block translations %> <%= localize({ 'key': __('string to translate'), ... })
%> <% endblock %>
<% block translations %>
<%= localize({
'key': __('string to translate'),
...
}) %>
<% endblock %>
```
Then use `MailPoet.I18n.t('key')` to get the translated string on your Javascript code.
@ -195,11 +197,9 @@ Then use `MailPoet.I18n.t('key')` to get the translated string on your Javascrip
To run the whole acceptance testing suite you need the docker daemon to be running and after that use a command: `./do test:acceptance`.
If you want to run only a single test use the parameter `--file`:
```bash
./do test:acceptance --skip-deps --file tests/acceptance/ReceiveStandardEmailCest.php
```
The argument `--skip-deps` is useful locally to speed up the run.
If there are some unexpected errors you can delete all the runtime and start again.

View File

@ -1,10 +1,6 @@
<?php
// phpcs:disable PSR1.Classes.ClassDeclaration
// phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
use MailPoetVendor\Twig\Loader\FilesystemLoader as TwigFileSystem;
use Robo\Symfony\ConsoleIO;
// phpcs:ignore PSR1.Classes.ClassDeclaration
class RoboFile extends \Robo\Tasks {
const ZIP_BUILD_PATH = __DIR__ . '/mailpoet.zip';
@ -23,23 +19,15 @@ class RoboFile extends \Robo\Tasks {
return $this->taskExecStack()
->stopOnFail()
->exec('./tools/vendor/composer.phar install')
->exec('cd .. && pnpm install --frozen-lockfile --prefer-offline')
->addCode([$this, 'cleanupCachedFiles'])
->exec('npm ci --prefer-offline')
->run();
}
public function cleanupCachedFiles() {
$this->say('Cleaning up generated folder.');
$this->_exec('rm -rf ' . __DIR__ . '/generated/*');
$this->say('Cleaning up PHPStan cache.');
$this->_exec('rm -rf ' . __DIR__ . '/temp/*');
}
public function update() {
return $this->taskExecStack()
->stopOnFail()
->exec('./tools/vendor/composer.phar update')
->exec('pnpm update')
->exec('npm update')
->run();
}
@ -50,8 +38,8 @@ class RoboFile extends \Robo\Tasks {
$file = $changedFile->getResource()->getResource();
$this->taskExecStack()
->stopOnFail()
->exec('pnpm run scss')
->exec('pnpm run autoprefixer')
->exec('npm run scss')
->exec('npm run autoprefixer')
->run();
})
->run();
@ -90,11 +78,9 @@ class RoboFile extends \Robo\Tasks {
// Clean up folder from previous files
array_map('unlink', glob("assets/dist/css/*.*"));
$compilationResult = $this->taskExecStack()
->exec('pnpm run stylelint-check -- "assets/css/src/**/*.scss"')
->exec('pnpm run scss')
->exec('pnpm run autoprefixer')
->run();
$this->_exec('npm run stylelint -- "assets/css/src/**/*.scss"');
$this->_exec('npm run scss');
$compilationResult = $this->_exec('npm run autoprefixer');
// Create manifest file
$manifest = [];
@ -116,87 +102,30 @@ class RoboFile extends \Robo\Tasks {
return $compilationResult;
}
public function translationsInit() {
// Define WP_TRANSIFEX_API_TOKEN env. variable
return $this->_exec('./tasks/transifex_init.sh');
}
public function translationsBuild() {
$exclude = implode(',', [
'.mp_svn',
'assets/css',
'assets/img',
'assets/js',
'generated',
'lang',
'lib-3rd-party',
'mailpoet-premium',
'node_modules',
'plugin_repository',
'prefixer',
'tasks',
'temp',
'tests',
'tools',
'vendor',
'vendor-prefixed',
]);
$headers = escapeshellarg(
json_encode([
'Report-Msgid-Bugs-To' => 'http://support.mailpoet.com/',
'Last-Translator' => 'MailPoet i18n (https://www.transifex.com/organization/wysija)',
'Language-Team' => 'MailPoet i18n <https://www.transifex.com/organization/wysija>',
'Plural-Forms' => 'nplurals=2; plural=(n != 1);',
])
);
$this->collectionBuilder()
->taskExec('mkdir -p ' . __DIR__ . '/lang')
->taskExec(
'php tasks/makepot/grunt-makepot.php wp-plugin . lang/mailpoet.pot mailpoet .mp_svn,assets,lang,node_modules,plugin_repository,tasks,tests,vendor'
)->run();
}
// HTML, HBS
->taskExec("php -d memory_limit=-1 tasks/makepot/makepot-views.php . > lang/mailpoet.pot")
// PHP, JS/TS
->taskExec("vendor/bin/wp i18n make-pot --merge --slug=mailpoet --domain=mailpoet --exclude=$exclude --headers=$headers . lang/mailpoet.pot")
public function translationsPack() {
return $this->collectionBuilder()
->addCode([$this, 'translationsInit'])
->taskExec('./tasks/pack_translations.sh')
->run();
}
public function translationsGetPotFileFromBuild() {
$potFilePathInsideZip = 'mailpoet/lang/mailpoet.pot';
$potFilePath = 'lang/mailpoet.pot';
if (!is_file(self::ZIP_BUILD_PATH)) {
$this->yell('mailpoet.zip file is missing. You must first download it using `./do release:download-zip`.', 40, 'red');
exit(1);
}
if (!file_exists(__DIR__ . '/lang')) {
$this->taskExec('mkdir -p ' . __DIR__ . '/lang')->run();
}
$zip = new ZipArchive();
if ($zip->open(self::ZIP_BUILD_PATH) === true) {
$potFileContent = $zip->getFromName($potFilePathInsideZip);
if ($potFileContent) {
file_put_contents($potFilePath, $potFileContent);
$this->say('mailpoet.pot extracted from the zip file to ' . $potFilePath);
} else {
$this->yell('Unable to find mailpoet.pot inside the zip file.', 40, 'red');
exit(1);
}
} else {
$this->yell('Unable to open the zip file.', 40, 'red');
exit(1);
}
}
public function translationsPush() {
$tokenEnvName = 'WP_TRANSIFEX_API_TOKEN';
$token = getenv($tokenEnvName);
if (!$token) {
throw new \Exception("Please provide '$tokenEnvName' environment variable");
}
return $this->collectionBuilder()
->taskExec('php ' . __DIR__ . '/tools/transifex.php push -s')
->env('TX_TOKEN', $token)
->addCode([$this, 'translationsInit'])
->taskExec('tx push -s')
->run();
}
@ -218,20 +147,36 @@ class RoboFile extends \Robo\Tasks {
return $this->_exec($command);
}
public function testIntegration(array $opts = ['file' => null, 'group' => null, 'skip-group' => null, 'xml' => false, 'multisite' => false, 'debug' => false, 'skip-deps' => false, 'skip-plugins' => false, 'enable-cot' => false, 'enable-cot-sync' => false]) {
return $this->runTestsInContainer(array_merge($opts, ['test_type' => 'integration']));
public function testIntegration(array $opts = ['file' => null, 'xml' => false, 'multisite' => false, 'debug' => false]) {
if (getenv('MAILPOET_DEV_SITE')) {
$run = $this->confirm("You are about to run tests on the development site. Your DB data will be erased. \nDo you want to proceed?", false);
if (!$run) {
return;
}
}
$command = 'vendor/bin/codecept run integration -vvv';
if ($opts['multisite']) {
$command = 'MULTISITE=true ' . $command;
}
if ($opts['file']) {
$command .= ' -f ' . $opts['file'];
}
if ($opts['xml']) {
$command .= ' --xml';
}
if ($opts['debug']) {
$command .= ' --debug';
}
return $this->_exec($command);
}
public function testMultisiteIntegration($opts = ['file' => null, 'group' => null, 'skip-group' => null, 'xml' => false, 'multisite' => true, 'skip-deps' => false, 'skip-plugins' => false, 'enable-cot' => false, 'enable-cot-sync' => false]) {
return $this->runTestsInContainer(array_merge($opts, ['test_type' => 'integration']));
}
public function testWooIntegration(array $opts = ['file' => null, 'xml' => false, 'multisite' => false, 'debug' => false, 'enable-cot' => false, 'enable-cot-sync' => false]) {
return $this->runTestsInContainer(array_merge($opts, ['test_type' => 'integration', 'group' => 'woo', 'skip-deps' => true, 'skip-plugins' => false]));
}
public function testBaseIntegration(array $opts = ['file' => null, 'xml' => false, 'multisite' => false, 'debug' => false]) {
return $this->runTestsInContainer(array_merge($opts, ['test_type' => 'integration', 'skip-group' => 'woo', 'skip-deps' => true, 'skip-plugins' => true]));
public function testMultisiteIntegration($opts = ['file' => null, 'xml' => false, 'multisite' => true]) {
return $this->testIntegration($opts);
}
public function testCoverage($opts = ['file' => null, 'xml' => false]) {
@ -273,7 +218,7 @@ class RoboFile extends \Robo\Tasks {
}
public function testJavascript($xmlOutputFile = null) {
$command = './node_modules/.bin/mocha --recursive --require tests/javascript/babel_register.js tests/javascript --extension spec.js --extension spec.ts';
$command = './node_modules/.bin/mocha --require tests/javascript/babel_register.js tests/javascript/**/*.spec.js';
if (!empty($xmlOutputFile)) {
$command .= sprintf(
@ -293,29 +238,30 @@ class RoboFile extends \Robo\Tasks {
return $this->testIntegration($opts);
}
public function testAcceptance($opts = ['file' => null, 'skip-deps' => false, 'group' => null, 'timeout' => null, 'enable-cot' => false, 'enable-cot-sync' => false]) {
return $this->runTestsInContainer($opts);
}
public function testAcceptanceMultisite($opts = ['file' => null, 'skip-deps' => false, 'group' => null, 'timeout' => null, 'enable-cot' => false, 'enable-cot-sync' => false]) {
return $this->runTestsInContainer(array_merge($opts, ['multisite' => true]));
}
/**
* Deletes docker stuff related to tests including docker images.
*/
public function deleteDocker() {
public function testAcceptance($opts = ['file' => null, 'skip-deps' => false, 'timeout' => null]) {
return $this->taskExec(
'docker-compose down -v --remove-orphans --rmi all'
'COMPOSE_HTTP_TIMEOUT=200 docker-compose run ' .
($opts['skip-deps'] ? '-e SKIP_DEPS=1 ' : '') .
($opts['timeout'] ? '-e WAIT_TIMEOUT=' . (int)$opts['timeout'] . ' ' : '') .
'codeception --steps --debug -vvv ' .
'-f ' . ($opts['file'] ? $opts['file'] : '')
)->dir(__DIR__ . '/tests/docker')->run();
}
/**
* Deletes docker containers and volumes used in tests
*/
public function resetTestDocker() {
public function testAcceptanceMultisite($opts = ['file' => null, 'skip-deps' => false, 'timeout' => null]) {
return $this->taskExec(
'docker-compose down -v --remove-orphans'
'COMPOSE_HTTP_TIMEOUT=200 docker-compose run ' .
($opts['skip-deps'] ? '-e SKIP_DEPS=1 ' : '') .
($opts['timeout'] ? '-e WAIT_TIMEOUT=' . (int)$opts['timeout'] . ' ' : '') .
'-e MULTISITE=1 ' .
'codeception --steps --debug -vvv ' .
'-f ' . ($opts['file'] ? $opts['file'] : '')
)->dir(__DIR__ . '/tests/docker')->run();
}
public function deleteDocker() {
return $this->taskExec(
'docker-compose down -v --remove-orphans --rmi all'
)->dir(__DIR__ . '/tests/docker')->run();
}
@ -385,25 +331,6 @@ class RoboFile extends \Robo\Tasks {
$this->say("Validator metadata generated to: $validatorMetadataDir");
}
public function migrationsNew() {
$generator = new \MailPoet\Migrator\Repository();
$result = $generator->create();
$path = realpath($result['path']);
$this->output->writeln('MAILPOET DATABASE MIGRATIONS');
$this->output->writeln("============================\n");
$this->output->writeln("New migration created ✔\n");
$this->output->writeln(" Name: {$result['name']}");
$this->output->writeln(" Path: $path");
}
public function migrationsStatus() {
return $this->taskExec('vendor/bin/wp mailpoet:migrations:status');
}
public function migrationsRun() {
return $this->taskExec('vendor/bin/wp mailpoet:migrations:run');
}
public function qa() {
$collection = $this->collectionBuilder();
$collection->addCode([$this, 'qaPhp']);
@ -411,14 +338,6 @@ class RoboFile extends \Robo\Tasks {
return $collection->run();
}
public function qaPrettierCheck() {
return $this->taskExec('npx prettier --check .')->dir(dirname(__DIR__));
}
public function qaPrettierWrite() {
return $this->taskExec('npx prettier --write .')->dir(dirname(__DIR__));
}
public function qaPhp() {
$collection = $this->collectionBuilder();
$collection->addCode([$this, 'qaLint']);
@ -487,25 +406,22 @@ class RoboFile extends \Robo\Tasks {
}
public function qaLintJavascript() {
return $this->_exec('pnpm run check-types && pnpm run lint');
return $this->_exec('npm run check-types && npm run lint');
}
public function qaLintCss() {
return $this->_exec('pnpm run stylelint-check -- "assets/css/src/**/*.scss"');
return $this->_exec('npm run stylelint-check -- "assets/css/src/**/*.scss"');
}
public function qaCodeSniffer(array $filesToCheck, $opts = ['severity' => 'all']) {
$severityFlag = $opts['severity'] === 'all' ? '-w' : '-n';
$task = implode(' ', [
'php -d memory_limit=-1',
'./tasks/code_sniffer/vendor/bin/phpcs',
'--extensions=php',
$severityFlag,
'--standard=tasks/code_sniffer/MailPoet',
'-s',
]);
$ignorePaths = [
$foldersToIgnore = [
'.mp_svn',
'assets',
'doc',
@ -528,17 +444,11 @@ class RoboFile extends \Robo\Tasks {
'vendor-prefixed',
'views',
];
// the "--ignore" arg takes a list of regexes, we need to anchor and escape them
$ignorePatterns = array_map(function (string $path): string {
return '^' . preg_quote(__DIR__ . DIRECTORY_SEPARATOR . $path);
}, $ignorePaths);
$stringFilesToCheck = !empty($filesToCheck) ? implode(' ', $filesToCheck) : '.';
return $this
->taskExec($task)
->arg('--ignore=' . implode(',', $ignorePatterns))
->arg('--ignore=' . implode(',', $foldersToIgnore))
->rawArg($stringFilesToCheck)
->run();
}
@ -559,7 +469,7 @@ class RoboFile extends \Robo\Tasks {
// fix ESLint using ES6 rules
return $this->collectionBuilder()
->taskExec(
'npx ../eslint-config/node_modules/.bin/eslint -c ../eslint-config/.eslintrc.es6.json ' .
'npx eslint -c .eslintrc.es6.json ' .
'--max-warnings 0 ' .
'--fix ' .
$filePath
@ -570,7 +480,7 @@ class RoboFile extends \Robo\Tasks {
// fix ESLint using TS rules
return $this->collectionBuilder()
->taskExec(
'npx ../eslint-config/node_modules/.bin/eslint -c ../eslint-config/.eslintrc.ts.json ' .
'npx eslint -c .eslintrc.ts.json ' .
'--max-warnings 0 ' .
'--fix ' .
$filePath
@ -581,7 +491,7 @@ class RoboFile extends \Robo\Tasks {
// fix ESLint using tests rules
return $this->collectionBuilder()
->taskExec(
'npx ../eslint-config/node_modules/.bin/eslint -c ../eslint-config/.eslintrc.tests_newsletter_editor.json ' .
'npx eslint -c .eslintrc.tests_newsletter_editor.json ' .
'--max-warnings 0 ' .
'--fix ' .
$filePath
@ -592,7 +502,7 @@ class RoboFile extends \Robo\Tasks {
// fix ESLint using ES5 rules
return $this->collectionBuilder()
->taskExec(
'npx ../eslint-config/node_modules/.bin/eslint -c ../eslint-config/.eslintrc.es5.json ' .
'npx eslint -c .eslintrc.es5.json ' .
'--max-warnings 0 ' .
'--fix ' .
$filePath
@ -618,6 +528,9 @@ class RoboFile extends \Robo\Tasks {
// PHPStan must be run out of main plugin directory to avoid its autoloading
// from vendor/autoload.php where some dev dependencies cause conflicts.
return $this->collectionBuilder()
// temp dir
->taskExec('mkdir -p ' . __DIR__ . '/temp')
->taskExec('rm -rf ' . __DIR__ . '/temp/phpstan')
->taskExec($task)
->rawArg(
implode(' ', [
@ -634,11 +547,11 @@ class RoboFile extends \Robo\Tasks {
}
public function storybookBuild() {
return $this->_exec('pnpm run build-storybook');
return $this->_exec('npm run build-storybook');
}
public function storybookWatch() {
return $this->_exec('pnpm run storybook');
return $this->_exec('npm run storybook');
}
public function svnCheckout() {
@ -799,9 +712,6 @@ class RoboFile extends \Robo\Tasks {
->addCode(function () use ($version) {
$this->releaseCreatePullRequest($version);
})
->addCode(function () use ($version) {
$this->releaseRerunCircleWorkflow(\MailPoetTasks\Release\CircleCiController::PROJECT_PREMIUM);
})
->addCode(function () use ($version) {
$this->translationsPrepareLanguagePacks($version);
})
@ -832,10 +742,10 @@ class RoboFile extends \Robo\Tasks {
$this->yell('Please make sure your working directory is clean before running release.', 40, 'red');
exit(1);
}
// checkout trunk and pull from remote
// checkout master and pull from remote
$this->taskGitStack()
->stopOnFail()
->checkout('trunk')
->checkout('master')
->exec('git pull --ff-only')
->run();
// make sure release branch doesn't exist on github
@ -918,7 +828,7 @@ class RoboFile extends \Robo\Tasks {
return $this->releaseDownloadZip();
})
->addCode(function () {
return $this->translationsGetPotFileFromBuild();
return $this->translationsBuild();
})
->addCode(function () {
return $this->translationsPush();
@ -941,79 +851,6 @@ class RoboFile extends \Robo\Tasks {
->run();
}
/**
* This command displays how many pull request each person did recently
*/
public function displayReviewers(ConsoleIO $io) {
$io->progressStart(2);
$freePluginGithubController = $this->createGitHubController();
$logins = $freePluginGithubController->calculateReviewers();
$io->progressAdvance();
$shopGithubController = $this->createGitHubController(\MailPoetTasks\Release\GitHubController::PROJECT_SHOP);
$loginsShop = $shopGithubController->calculateReviewers();
$io->progressFinish();
$printReviewers = function ($logins, $header) use ($io) {
$io->title($header);
$outputList = [];
foreach ($logins as $login => $num) {
$outputList[] = [$login => $num];
}
$io->definitionList(...$outputList);
};
arsort($logins);
$printReviewers($logins, 'Free plugin');
arsort($loginsShop);
$printReviewers($loginsShop, 'Shop');
foreach ($loginsShop as $loginShop => $num) {
if (!isset($logins[$loginShop])) {
$logins[$loginShop] = 0;
}
$logins[$loginShop] += $num;
}
arsort($logins);
$printReviewers($logins, 'Full');
}
public function displayCreatedPullRequests(ConsoleIO $io, int $months = 6) {
$projects = [
\MailPoetTasks\Release\GitHubController::PROJECT_SHOP,
\MailPoetTasks\Release\GitHubController::PROJECT_MAILPOET,
\MailPoetTasks\Release\GitHubController::PROJECT_PREMIUM,
];
$io->progressStart(count($projects));
$counts = [];
foreach ($projects as $project) {
$githubController = $this->createGitHubController($project);
$countsProject = $githubController->calculatePRcounts($months);
foreach ($countsProject as $login => $num) {
if (!isset($counts[$login])) {
$counts[$login] = 0;
}
$counts[$login] += $num;
}
$io->progressAdvance();
}
$io->progressFinish();
arsort($counts);
$io->title('Pull Request counts');
$outputList = [];
foreach ($counts as $login => $num) {
$outputList[] = [
$login,
$num,
round($num / $months, 2),
];
}
$io->table(['Login', 'Count', 'Per month'], $outputList);
}
public function releaseCheckPullRequest($version) {
$this->createGitHubController()
->checkReleasePullRequestPassed($version);
@ -1040,7 +877,7 @@ class RoboFile extends \Robo\Tasks {
public function releaseVersionAssign($version = null, $opts = []) {
$version = $this->releaseVersionGetNext($version);
try {
[$version, $output] = $this->getReleaseVersionController()
list($version, $output) = $this->getReleaseVersionController()
->assignVersionToCompletedTickets($version);
} catch (\Exception $e) {
$this->yell($e->getMessage(), 40, 'red');
@ -1119,32 +956,6 @@ class RoboFile extends \Robo\Tasks {
$this->say("Release '$version[name]' info was published on Slack.");
}
public function releaseRerunCircleWorkflow(string $project = null) {
$circleciController = $this->createCircleCiController();
$result = $circleciController->rerunLatestWorkflow($project);
// Sometimes can be useful to know which Circle project workflow was restarted
$project = $project ? " for the project '{$project}'" : '';
if (!$result) {
$this->yell("Circle Workflow{$project} was not restarted", 40, 'red');
} else {
$this->say("Circle Workflow{$project} was started from the beginning");
}
}
public function downloadWooCommerceBlocksZip($tag = null) {
$this->createWpOrgDownloader('woo-gutenberg-products-block')
->downloadPluginZip('woo-gutenberg-products-block.zip', __DIR__ . '/tests/plugins/', $tag);
}
public function downloadWooCommerceMembershipsZip($tag = null) {
if (!getenv('WP_GITHUB_USERNAME') && !getenv('WP_GITHUB_TOKEN')) {
$this->yell("Skipping download of WooCommerce Memberships", 40, 'red');
exit(0); // Exit with 0 since it is a valid state for some environments
}
$this->createGithubClient('woocommerce/woocommerce-memberships')
->downloadReleaseZip('woocommerce-memberships.zip', __DIR__ . '/tests/plugins/', $tag);
}
public function downloadWooCommerceSubscriptionsZip($tag = null) {
if (!getenv('WP_GITHUB_USERNAME') && !getenv('WP_GITHUB_TOKEN')) {
$this->yell("Skipping download of WooCommerce Subscriptions", 40, 'red');
@ -1185,21 +996,6 @@ class RoboFile extends \Robo\Tasks {
$generator->run($generatorName);
}
public function twigGenerateCache() {
$templatePath = __DIR__ . '/views/'; // \MailPoet\Config\Env::$viewsPath . '/'
$renderer = new \MailPoet\Config\Renderer(
false,
__DIR__ . '/generated/twig',
new TwigFileSystem($templatePath)
);
$twig = $renderer->getTwig();
foreach ($this->rsearch($templatePath, ['html','hbs','txt']) as $template) {
$path = substr($template, strlen($templatePath));
$twig->load($path);
}
}
protected function rsearch($folder, $extensions = []) {
$dir = new RecursiveDirectoryIterator($folder);
$iterator = new RecursiveIteratorIterator($dir);
@ -1261,12 +1057,12 @@ class RoboFile extends \Robo\Tasks {
);
}
protected function createGitHubController($project = \MailPoetTasks\Release\GitHubController::PROJECT_MAILPOET) {
protected function createGitHubController() {
$help = "Use your GitHub username and a token from https://github.com/settings/tokens with 'repo' scopes.";
return new \MailPoetTasks\Release\GitHubController(
$this->getEnv('WP_GITHUB_USERNAME', $help),
$this->getEnv('WP_GITHUB_TOKEN', $help),
$project
\MailPoetTasks\Release\GitHubController::PROJECT_MAILPOET
);
}
@ -1319,10 +1115,7 @@ class RoboFile extends \Robo\Tasks {
private function createDoctrineEntityManager() {
define('ABSPATH', getenv('WP_ROOT') . '/');
if (\MailPoet\Config\Env::$dbPrefix === null) {
/**
* Ensure some prefix is set
*/
\MailPoet\Config\Env::$dbPrefix = '';
\MailPoet\Config\Env::$dbPrefix = ''; // ensure some prefix is set
}
$annotationReaderProvider = new \MailPoet\Doctrine\Annotations\AnnotationReaderProvider();
$configuration = (new \MailPoet\Doctrine\ConfigurationFactory($annotationReaderProvider, true))->createConfiguration();
@ -1332,23 +1125,4 @@ class RoboFile extends \Robo\Tasks {
'platform' => new $platformClass,
], $configuration);
}
private function runTestsInContainer(array $opts) {
$testType = $opts['test_type'] ?? 'acceptance';
$this->doctrineGenerateCache();
return $this->taskExec(
'COMPOSE_HTTP_TIMEOUT=200 docker-compose run ' .
(isset($opts['skip-deps']) && $opts['skip-deps'] ? '-e SKIP_DEPS=1 ' : '') .
(isset($opts['enable-cot']) && $opts['enable-cot'] ? '-e ENABLE_COT=1 ' : '') .
(isset($opts['enable-cot-sync']) && $opts['enable-cot-sync'] ? '-e ENABLE_COT_SYNC=1 ' : '') .
(isset($opts['skip-plugins']) && $opts['skip-plugins'] ? '-e SKIP_PLUGINS=1 ' : '') .
(isset($opts['timeout']) && $opts['timeout'] ? '-e WAIT_TIMEOUT=' . (int)$opts['timeout'] . ' ' : '') .
(isset($opts['multisite']) && $opts['multisite'] ? '-e MULTISITE=1 ' : '-e MULTISITE=0 ') .
"codeception_{$testType} --steps --debug -vvv " .
(isset($opts['xml']) && $opts['xml'] ? '--xml ' : '') .
(isset($opts['group']) && $opts['group'] ? '--group ' . $opts['group'] . ' ' : '') .
(isset($opts['skip-group']) && $opts['skip-group'] ? '--skip-group ' . $opts['skip-group'] . ' ' : '') .
'-f ' . (isset($opts['file']) && $opts['file'] ? $opts['file'] : '')
)->dir(__DIR__ . '/tests/docker')->run();
}
}

View File

@ -0,0 +1,22 @@
@font-face {
font-family: 'mailpoet-icon';
font-style: normal;
font-weight: normal;
src: url('data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAYcAAsAAAAABdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABCAAAAGAAAABgDxIFHGNtYXAAAAFoAAAAVAAAAFQXVtKHZ2FzcAAAAbwAAAAIAAAACAAAABBnbHlmAAABxAAAAhQAAAIU239UpGhlYWQAAAPYAAAANgAAADYYSCB9aGhlYQAABBAAAAAkAAAAJAelA8ZobXR4AAAENAAAABQAAAAUCeMAAGxvY2EAAARIAAAADAAAAAwAKAEebWF4cAAABFQAAAAgAAAAIAAIAMJuYW1lAAAEdAAAAYYAAAGGmUoJ+3Bvc3QAAAX8AAAAIAAAACAAAwAAAAMC8gGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAA6QADwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADgAAAAKAAgAAgACAAEAIOkA//3//wAAAAAAIOkA//3//wAB/+MXBAADAAEAAAAAAAAAAAAAAAEAAf//AA8AAQAAAAAAAAAAAAIAADc5AQAAAAABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAgAA/8AD4wPAAGQAvwAAEzI2Nz4BNTQwOQEREx4BFzEeATM4ATMyNjcjPgE3MRMRHAExFBYXMR4BMzI2Nz4BNTA0OQERPAE1NCYnMS4BIyoBIyIGBzMOAQcVCwEuASc1LgEjKgEjIgYHMw4BFREUFhceATMFJy4BIyIGBzEOASsBOAExIgYHMQcnLgErAS4BJxcuASMiBgcxBw4BFTEcATEUFhcxHgEXMTM4ATEyFhcdARQWMzI2PQE+ATM4ATEzPgE3Iz4BNTwBOQEuASc19xEYBgYHbwQNCAgXEAEKEwkBCg0DdggGBxcPEhcHBgcMCgodEQEDAg8dDQEMEQSBhgQPCgscEwEDAQ8bDAELDAcGBxcQAtkQBg8JCRAHECoYjDJZIQcHIVkyjRgpEQEHEAkJDwYQCAoICCBSL40sRAwUJCMUDEQsjS9TIAEICAEKCAF5BwgHEQoBASv+2QsRBwcGBAUFEQoBSP6+AQILEwcHCAgHBxIKAQHdAQEBDBYGBwcHBggWDgH+gwGADRQHAQcHBwcHGBD+LA4UBwYHtAwFBQYGDhAmIQgHISYBEA4BBgcGBQwGEwsBAQsSBh0hATUoAQEEGRkEASk1ASEdBhMKAQELEwYBAAEAAAAAAACzy1ndXw889QALBAAAAAAA2qNuAAAAAADao24AAAD/wAPjA8AAAAAIAAIAAAAAAAAAAQAAA8D/wAAABAAAAAAAA+MAAQAAAAAAAAAAAAAAAAAAAAUEAAAAAAAAAAAAAAACAAAAA+MAAAAAAAAACgAUAB4BCgABAAAABQDAAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAADgCuAAEAAAAAAAEABwAAAAEAAAAAAAIABwBgAAEAAAAAAAMABwA2AAEAAAAAAAQABwB1AAEAAAAAAAUACwAVAAEAAAAAAAYABwBLAAEAAAAAAAoAGgCKAAMAAQQJAAEADgAHAAMAAQQJAAIADgBnAAMAAQQJAAMADgA9AAMAAQQJAAQADgB8AAMAAQQJAAUAFgAgAAMAAQQJAAYADgBSAAMAAQQJAAoANACkaWNvbW9vbgBpAGMAbwBtAG8AbwBuVmVyc2lvbiAxLjAAVgBlAHIAcwBpAG8AbgAgADEALgAwaWNvbW9vbgBpAGMAbwBtAG8AbwBuaWNvbW9vbgBpAGMAbwBtAG8AbwBuUmVndWxhcgBSAGUAZwB1AGwAYQByaWNvbW9vbgBpAGMAbwBtAG8AbwBuRm9udCBnZW5lcmF0ZWQgYnkgSWNvTW9vbi4ARgBvAG4AdAAgAGcAZQBuAGUAcgBhAHQAZQBkACAAYgB5ACAASQBjAG8ATQBvAG8AbgAuAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==') format('woff');
}
#wpbody {
padding-bottom: 20px;
}
/* menu icon */
#adminmenu #toplevel_page_mailpoet-newsletters .wp-menu-image:before {
content: '\e900';
font-family: 'mailpoet-icon';
font-style: normal;
font-weight: normal;
}
#adminmenu .wp-menu-image img {
max-width: 20px;
}

View File

@ -1,21 +0,0 @@
.mailpoet-automation-editor-add-step-button {
appearance: none;
background: #dcdcde;
border: none;
border-radius: 2px;
box-shadow: 0 0 0 4px #fbfbfb;
cursor: pointer;
fill: #2b3337;
height: 16px;
margin: 0;
padding: 0;
text-align: left;
width: 16px;
&:focus {
box-shadow:
0 0 0 1px #fbfbfb, // space
0 0 0 calc(var(--wp-admin-border-width-focus) + 1px) var(--wp-admin-theme-color), // focus ring
0 0 0 4px #fbfbfb; // separator space
}
}

View File

@ -1,19 +0,0 @@
.mailpoet-automation-add-trigger {
align-items: center;
border: 1px dashed #c3c4c7;
border-radius: 4px;
color: #757575;
cursor: pointer;
display: flex;
fill: #757575;
height: 73px;
justify-content: center;
margin: 4px auto;
padding: 20px 32px;
&:focus {
box-shadow:
0 0 0 1px #fbfbfb, // space
0 0 0 calc(var(--wp-admin-border-width-focus) + 1px) var(--wp-admin-theme-color), // focus ring
}
}

View File

@ -1,37 +0,0 @@
.mailpoet-automation-editor-automation {
background: #fbfbfb;
flex-grow: 1;
}
.mailpoet-automation-editor-automation-wrapper {
display: grid;
padding: 50px 20px;
}
.mailpoet-automation-editor-automation-end {
background: #8c8f94;
border-radius: 999999px;
fill: white;
height: 18px;
margin: 4px auto;
padding: 3px;
width: 18px;
}
.mailpoet-automation-editor-stats {
margin: 0 auto 32px;
max-width: 480px;
width: 100%;
.mailpoet-automation-stats-item {
line-height: 22px;
}
.mailpoet-automation-stats-label {
color: #787c82;
}
.mailpoet-automation-stats-value {
font-size: 14px;
}
}

View File

@ -1,34 +0,0 @@
// See: https://github.com/WordPress/gutenberg/blob/af7da80dd54d7fe52772890e2cc1b65073db9655/packages/block-editor/src/components/block-icon/style.scss
.block-editor-block-icon {
align-items: center;
display: flex;
height: 24px;
justify-content: center;
width: 24px;
&.has-colors {
svg {
fill: currentColor;
// Optimize for high contrast modes.
// See also https://blogs.windows.com/msedgedev/2020/09/17/styling-for-windows-high-contrast-with-new-standards-for-forced-colors/.
@media (forced-colors: active) {
fill: CanvasText;
}
}
}
// Icons with width/height attributes below 20px will be sized up to 20px,
// and icons with width/height attributes above 24px will be sized down to
// 24px. Icons with width/height >=20px and <=24px will display at the
// indicated size.
// See: https://github.com/WordPress/gutenberg/pull/9828
svg {
max-height: 24px;
max-width: 24px;
min-height: 20px;
min-width: 20px;
}
}

View File

@ -1,27 +0,0 @@
.mailpoet-automation-chip {
align-items: center;
background: #fcf0f1;
border-radius: 9999px;
color: #8a2424;
cursor: pointer;
display: flex;
font-size: 13px;
height: 20px;
padding: 0 8px;
&.chip-small {
font-size: 13px;
height: 20px;
}
&.chip-medium {
font-size: 13px;
height: 24px;
}
&.chip-large {
font-size: 14px;
height: 32px;
padding: 0 12px;
}
}

View File

@ -1,44 +0,0 @@
.mailpoet-automatoin-deactivate-modal {
color: #1d2327;
font-size: 13px;
line-height: 21px;
max-width: 480px;
.mailpoet-automation-options {
li {
margin-bottom: 12px;
}
}
.mailpoet-automation-option {
border: 2px solid #dcdcde;
border-radius: 4px;
color: #646970;
display: grid;
font-size: 12px;
grid-gap: 8px;
grid-template-columns: 20px auto;
line-height: 16px;
padding: 8px;
&.active {
border-color: #2271b1;
}
strong {
color: #1d2327;
display: block;
font-size: 13px;
font-weight: normal;
line-height: 21px;
}
}
.components-button {
float: right;
&.is-tertiary {
margin-right: 12px;
}
}
}

View File

@ -1,14 +0,0 @@
.mailpoet-automation-editor-dropdown-name-edit {
padding: 16px;
}
.mailpoet-automation-editor-dropdown-name-edit-title {
margin-bottom: 10px;
}
.mailpoet-automation-editor-dropdown-toggle-link {
display: inline-flex;
height: fit-content;
margin-top: 10px;
text-decoration: none;
}

View File

@ -1,7 +0,0 @@
.mailpoet-automation-editor-empty-automation {
align-items: center;
display: grid;
height: 100%;
justify-content: center;
width: 100%;
}

View File

@ -1,60 +0,0 @@
.mailpoet-automation-errors {
padding: 8px 0;
width: 280px;
}
.mailpoet-automation-errors-header {
font-weight: 600;
padding: 8px 12px;
}
.mailpoet-automation-step-error {
align-items: center;
appearance: none;
background: none;
border: none;
cursor: pointer;
display: grid;
gap: 12px;
grid-template-columns: auto 1fr;
padding: 9px 12px;
text-align: left;
width: 100%;
&:hover {
background: #f6f7f7;
}
&:focus-visible {
box-shadow: inset 0 0 0 1.5px #2271b1;
outline: none;
}
}
.mailpoet-automation-field__error {
position: relative;
input,
select,
textarea {
background: right top/26px no-repeat url('../../img/icons/alert.svg');
padding-right: 26px;
}
select,
input[type=number] {
background-position-x: calc(100% - 26px);
padding-right: 8px !important;
}
.components-base-control__help,
.mailpoet-automation-field-message {
color: #d63638;
}
.components-button.mailpoet-automation-button-sidebar-primary,
.components-button.mailpoet-automation-button-sidebar-primary.has-text,
.components-button.mailpoet-automation-button-sidebar-primary.has-icon {
background: #d63638;
}
}

View File

@ -1,23 +0,0 @@
// See: https://github.com/WordPress/gutenberg/blob/659377eac576ac34f68dc9762187eb2f6aec2151/packages/edit-navigation/src/components/notices/style.scss
.mailpoet-automation-editor-notices__snackbar-list {
bottom: 0;
padding: 20px;
position: fixed;
}
.mailpoet-automation-editor-notices__notice-list {
// Notices have some unusual margin and padding by default, reset that.
.components-notice {
border-bottom: 1px solid rgba(0, 0, 0, .2);
box-sizing: border-box;
margin: 0;
min-height: 60px;
padding: 0 12px;
// Make sure the close button is centered.
.components-button {
align-self: initial;
}
}
}

View File

@ -1,138 +0,0 @@
.mailpoet-automation-sidebar {
padding-bottom: 100px;
}
.components-panel__body-title.mailpoet-automation-panel-plain-body-title {
display: grid;
grid-template-columns: 1fr auto;
}
.mailpoet-automation-panel-plain-body-title-text {
font-size: 13px;
font-weight: 500;
line-height: normal;
padding: 16px 48px 16px 16px;
label & {
padding: 0;
}
}
.mailpoet-automation-panel-plain-body-title-action {
align-items: center;
display: flex;
padding: 8px 16px;
button {
height: auto;
padding: 4px;
}
}
.mailpoet-step-name-dropdown {
display: block;
h2 {
margin: 0;
}
.mailpoet-automation-panel-plain-body-title-text {
padding-left: 0;
padding-top: 0;
}
.mailpoet-automation-panel-plain-body-title-action {
margin-top: -10px;
padding-right: 0;
padding-top: 0;
}
}
.mailpoet-step-name-popover {
margin-top: -25px;
padding: 8px;
}
.mailpoet-step-name-input {
min-width: 208px;
}
.mailpoet-deactive {
color: #757575;
font-style: italic;
}
.mailpoet-automation-activate-panel {
animation: mailpoet-automation-activate-panel-animation .1s forwards;
background: #fff;
border-left: 1px solid #ddd;
bottom: 0;
height: 100%;
left: auto;
overflow: auto;
position: fixed;
right: 0;
top: 0;
transform: translateX(100%);
width: 281px;
z-index: 999999;
button {
justify-content: center;
width: 100%;
}
}
.mailpoet-automation-activate-panel__header {
align-content: space-between;
align-items: center;
display: flex;
height: 61px;
.has-icon {
margin-left: auto;
width: auto;
}
}
.mailpoet-automation-activate-panel__header,
.mailpoet-automation-activate-panel__section {
border-bottom: 1px solid #ddd;
}
.mailpoet-automation-activate-panel__header,
.mailpoet-automation-activate-panel__body {
padding-left: 16px;
padding-right: 16px;
.components-spinner {
display: block;
margin: 100px auto 0;
}
}
.mailpoet-automation-activate-panel__section {
margin-left: -16px;
margin-right: -16px;
padding: 16px;
}
.mailpoet-automation-activate-panel__header-activate-button,
.mailpoet-automation-activate-panel__header-cancel-button {
flex-grow: 1;
max-width: 160px;
}
.mailpoet-automation-activate-panel__header-activate-button {
padding-right: 4px;
}
.mailpoet-automation-activate-panel__header-cancel-button {
padding-left: 4px;
}
@keyframes mailpoet-automation-activate-panel-animation {
100% {
transform: translateX(0);
}
}

View File

@ -1,9 +0,0 @@
.mailpoet-automation-editor-separator {
align-items: center;
background: #c3c4c7;
display: grid;
height: 64px;
justify-content: center;
margin: auto;
width: 1px;
}

View File

@ -1,14 +0,0 @@
.mailpoet-automation-editor-chip-gray {
background-color: $color-chip-gray-bg !important;
color: $color-chip-gray-text;
}
.mailpoet-automation-editor-chip-success {
background-color: $color-chip-success-bg !important;
color: $color-chip-success-text;
}
.mailpoet-automation-editor-chip-danger {
background-color: $color-chip-danger-bg !important;
color: $color-chip-danger-text;
}

View File

@ -1,33 +0,0 @@
// See: https://github.com/WordPress/gutenberg/blob/af7da80dd54d7fe52772890e2cc1b65073db9655/packages/block-editor/src/components/block-card/style.scss
.block-editor-block-card {
align-items: flex-start;
display: flex;
padding: 16px;
}
.block-editor-block-card__content {
flex-grow: 1;
margin-bottom: 4px;
}
.block-editor-block-card__title {
font-weight: 500;
&.block-editor-block-card__title {
line-height: 24px;
margin: 0 0 4px;
}
}
.block-editor-block-card__description {
font-size: 13px;
}
.block-editor-block-card .block-editor-block-icon {
flex: 0 0 24px;
height: 24px;
margin-left: 0;
margin-right: 12px;
width: 24px;
}

View File

@ -1,81 +0,0 @@
.mailpoet-automation-editor-step-wrapper {
margin: auto;
position: relative;
width: 280px;
}
.mailpoet-automation-step-more-menu {
position: absolute;
right: 4px;
top: 14px;
button.components-button.is-small.has-icon {
height: 24px;
min-width: 24px;
padding: 3px;
width: 24px;
}
}
.mailpoet-automation-editor-step {
appearance: none;
background: white;
border: 1px solid #dcdcde;
border-radius: 4px;
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
display: grid;
grid-gap: 12px;
grid-template-columns: auto 1fr;
line-height: 1.4;
margin: 4px auto;
padding: 12px;
text-align: left;
width: 100%;
&.is-unknown-step {
background: #f0f0f1;
}
&:focus,
&.is-selected-step {
box-shadow:
0 0 0 1px #fbfbfb, // space
0 0 0 calc(var(--wp-admin-border-width-focus) + 1px) var(--wp-admin-theme-color), // focus ring
0 1px 2px rgba(0, 0, 0, .05); // original shadow
}
&:has(.mailpoet-automation-editor-step-footer) {
padding-bottom: 8px;
}
}
.mailpoet-automation-editor-step-icon {
display: flex;
}
.mailpoet-automation-editor-step-title {
color: $color-wordpress-grey-dark;
}
.mailpoet-automation-editor-step-subtitle {
color: inherit;
font-weight: 600;
}
.mailpoet-automation-editor-step-footer {
display: flex;
grid-column: 1 / -1;
}
.mailpoet-automation-editor-step-error {
margin-left: auto;
}
.mailpoet-automation-colored-icon {
border-radius: 50%;
box-sizing: content-box;
display: flex;
justify-content: center;
padding: 12px;
position: relative;
}

View File

@ -1,3 +0,0 @@
@import './mailpoet/button';
@import './mailpoet/edit';
@import './mailpoet/thumbnail';

View File

@ -1,37 +0,0 @@
.components-button.mailpoet-automation-button-sidebar-primary,
.components-button.mailpoet-automation-button-sidebar-primary.has-text,
.components-button.mailpoet-automation-button-sidebar-primary.has-icon {
background: #1d2327;
width: 100%;
&:hover:not(:disabled) {
background: #1d2327;
}
&:disabled {
color: rgba(255, 255, 255, .4);
}
&.is-busy {
--background-color-1: #2c3236;
--background-color-2: #535659;
background-image:
linear-gradient(
-45deg,
var(--background-color-1) 33%,
var(--background-color-2) 33%,
var(--background-color-2) 70%,
var(--background-color-1) 70%
);
}
}
.components-button.mailpoet-automation-button-centered,
.components-button.mailpoet-automation-button-centered.has-text,
.components-button.mailpoet-automation-button-centered.has-icon {
justify-content: center;
svg {
margin-right: 0;
}
}

View File

@ -1,9 +0,0 @@
.mailpoet-automation-email-content-separator {
height: 16px;
}
.mailpoet-automation-email-buttons {
display: grid;
gap: 8px;
grid-template-columns: 1fr 1fr;
}

View File

@ -1,29 +0,0 @@
.mailpoet-automation-thumbnail-box {
align-items: center;
background: #f6f7f7;
border: 1px solid #2c3338;
display: flex;
height: 280px;
justify-content: center;
margin-bottom: 16px;
width: 100%;
}
.mailpoet-automation-thumbnail-spinner {
height: 32px;
width: 32px;
}
.mailpoet-automation-thumbnail-wrapper {
display: flex;
height: 100%;
justify-content: center;
overflow: hidden;
width: 100%;
}
.mailpoet-automation-thumbnail-image {
display: block;
margin: auto;
max-width: 192px;
}

View File

@ -1,15 +0,0 @@
.mailpoet-automation-listing .components-card__header {
padding-left: 16px;
}
.mailpoet-automation-listing .woocommerce-table__actions {
margin-left: 0;
}
.mailpoet-automation-listing .woocommerce-table__actions > div {
width: auto;
&:last-child {
flex-grow: 1;
}
}

View File

@ -1,85 +0,0 @@
#mailpoet_automation * {
box-sizing: border-box;
.mailpoet-add-new-button {
padding-right: 12px;
}
}
.mailpoet-automation-is-onboarding {
.notice {
display: none;
}
}
.mailpoet-automation-listing-heading {
margin-bottom: 16px;
}
.mailpoet-automation-listing {
box-shadow: none;
margin-bottom: 0;
}
.mailpoet-automation-listing-cell-name {
position: relative;
width: 100%;
> a:only-child {
bottom: 2px;
display: flex;
left: 0;
padding: 16px 24px;
position: absolute;
right: 0;
top: 0;
}
}
.mailpoet-filter-tab-panel {
background-color: #fff;
border: 1px solid #dcdcde;
border-radius: 2px;
.components-tab-panel__tabs {
box-shadow: inset 0 -1px 0 0 #dcdcde;
}
.components-tab-panel__tabs-item:focus {
box-shadow: none;
}
.components-tab-panel__tabs-item.is-active {
box-shadow: inset 0 -4px 0 0 var(--wp-admin-theme-color);
}
.components-tab-panel__tabs-item:focus-visible {
box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
}
.components-tab-panel__tabs-item.is-active:focus-visible {
box-shadow:
inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color),
inset 0 -4px 0 0 var(--wp-admin-theme-color);
}
.count {
background-color: #f0f0f1;
border-radius: 12px;
font-size: 11px;
font-weight: 400;
margin-left: 6px;
padding: 2px 5px;
}
}
.mailpoet-automation-listing-more-button button.components-button {
height: 36px;
padding: 0;
width: 36px;
svg {
height: 28px;
width: 28px;
}
}

View File

@ -1,10 +0,0 @@
.mailpoet-automation-listing-search.woocommerce-search.woocommerce-select-control > div {
border-color: $color-wordpress-heading;
border-radius: 2px;
box-shadow: none;
height: 36px;
svg {
transform: translateY(-50%) scaleX(-1);
}
}

View File

@ -1,201 +0,0 @@
@mixin full-width {
margin-left: -20px;
padding-left: 104px;
padding-right: 104px;
width: calc(100% + 60px);
@media screen and (max-width: 782px) {
margin-left: -10px;
width: calc(100% + 34px);
}
}
.mailpoet-automation-section {
@include full-width;
}
.mailpoet-automation-white-background {
background: #fff;
}
.mailpoet-automation-section-content {
display: block;
margin: auto;
max-width: 1072px;
padding: 65px 0;
h2 {
font-size: 23px;
font-weight: 400;
line-height: 32px;
margin: 0;
padding: 0 0 8px;
}
p {
font-size: 14px;
font-weight: 400;
line-height: 22px;
margin: 0;
padding: 0 0 40px;
}
}
.mailpoet-automation-section-hero {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin-top: -20px;
h1 {
font-size: 32px;
font-weight: 400;
line-height: 40px;
}
p {
font-size: 14px;
line-height: 22px;
margin-bottom: 32px;
}
> div {
width: 400px;
}
img {
margin-top: 16px;
max-width: 100%;
width: 532px;
@media screen and (min-width: 1305px) {
height: 100%;
margin-top: 0;
max-height: 294px;
width: auto;
}
}
}
.mailpoet-automation-preheading {
display: block;
font-size: 11px;
letter-spacing: .2px;
line-height: 16px;
margin-bottom: 32px;
text-transform: uppercase;
}
.mailpoet-section-templates {
padding: 48px 0;
.components-button {
display: block;
font-size: 16px;
font-weight: 400;
line-height: 25px;
text-align: center;
text-underline-offset: 5px;
}
}
.mailpoet-section-template-list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin-bottom: 40px;
> li {
flex-grow: 1;
margin-right: 8px;
max-width: 336px;
&:last-child {
margin-right: 0;
}
button {
background: #fff;
border: 1px solid #dcdcde;
border-radius: 0;
color: #1d2327;
cursor: pointer;
padding: 24px;
text-align: left;
h3 {
font-size: 16px;
font-weight: 600;
line-height: 24px;
}
}
}
}
.mailpoet-section-build-list-button {
background: transparent;
border: 0;
color: #000;
cursor: pointer;
font-size: 16px;
font-weight: 400;
line-height: 24px;
padding: 0;
text-align: left;
width: 100%;
}
.mailpoet-section-build-your-own {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
ol {
list-style: decimal-leading-zero inside;
margin: 0;
max-width: 373px;
padding: 0;
> li {
border-bottom: 1px solid #dcdcde;
display: grid;
grid-gap: 16px;
grid-template-columns: 16px auto;
margin-bottom: 16px;
padding-bottom: 16px;
&.open {
p {
display: block;
}
.mailpoet-section-build-list-button {
font-weight: 600;
}
}
&:last-of-type {
border: 0;
}
}
.marker {
color: #ff5301;
display: inline-block;
font-size: 16px;
font-weight: 600;
line-height: 24px;
}
p {
display: none;
padding: 0;
}
}
img {
height: auto;
max-width: 400px;
width: 100%;
}
}

View File

@ -1,7 +0,0 @@
.mailpoet-automation-listing-cell-actions {
align-items: center;
display: grid;
gap: 8px;
grid-auto-flow: column;
white-space: nowrap;
}

View File

@ -1,10 +0,0 @@
.mailpoet-automation-listing-cell-status {
align-items: center;
display: grid;
grid-auto-flow: column;
white-space: nowrap;
> div.components-base-control > div.components-base-control__field {
margin-bottom: 0;
}
}

View File

@ -1,25 +0,0 @@
.mailpoet-option-button {
display: flex;
margin-top: 8px;
position: relative;
}
.mailpoet-option-button-main {
border-radius: 2px 0 0 2px;
margin-right: 1px;
}
.mailpoet-option-button-opener {
background: var(--wp-admin-theme-color);
border-radius: 0 2px 2px 0;
color: white;
}
.mailpoet-option-button-opener svg {
fill: white;
}
.mailpoet-option-button-opener .is-opened svg {
transform: scale(-1, -1);
transform-origin: center 12.5px;
}

View File

@ -1,32 +0,0 @@
.mailpoet-automation-stats {
display: grid;
grid-auto-flow: column;
justify-content: space-between;
}
.mailpoet-automation-stats-item {
color: $color-wordpress-heading;
display: grid;
font-size: 12px;
line-height: 16px;
text-align: center;
}
.mailpoet-automation-stats-label {
color: #646970;
display: block;
&.display-after {
order: 1;
}
}
.mailpoet-automation-stats-value {
font-weight: 600;
}
.mailpoet-automation-stats-item-separator {
color: #a7aaad;
font-size: 20px;
margin: 0 16px;
}

View File

@ -12,12 +12,22 @@
}
}
.edit-post-layout .interface-interface-skeleton__content {
background-color: $color-white;
}
// Fix for settings toolbar placement in header
.edit-post-header {
flex-direction: row-reverse;
justify-content: space-between;
}
// Hide tabs (Blocks, Patterns, ...) in block inserter, because we don't have patterns
// They are always visible in case user adds a block in the top level
.block-editor-inserter__tabs .components-tab-panel__tabs {
display: none;
}
// Fix for default appender appearance
// We don't use any default block (WP Post editor has paragraph)
// and CSS distributed within packages is works only with the paragraph block
@ -48,11 +58,6 @@ h2 {
font-size: 1.7em;
}
// Fix for max width of fixed bar form in the block editor
.mailpoet-form-background {
box-sizing: border-box;
}
// Remove block margins for first block and also first block in columns
// This is done to improve WYSIWYG experience
.mailpoet-form-background .block-editor-block-list__block:first-child {
@ -83,14 +88,13 @@ h2 {
}
}
// Adjustments for family-font-select in popover
.mailpoet_toolbar_item {
.mailpoet-font-family-select {
height: 48px;
align-items: center;
background-color: white;
display: flex;
.components-input-control__container .components-custom-select-control__button {
width: 200px;
}
.mailpoet-font-family-select {
width: $grid-column-small;
}
// Force rendering of select arrow on the right

View File

@ -22,31 +22,18 @@
min-width: 5em;
}
.block-editor-panel-color-gradient-settings {
border: none;
padding: 10px 0;
h2 {
font-weight: normal;
}
}
hr {
margin: 0;
}
}
.mailpoet-font-family-select {
.components-flex {
height: auto;
}
.mailpoet-font-family-select {
button {
width: 100%;
}
.components-input-control__container {
width: 100%;
}
.components-custom-select-control__label {
font-weight: bold;
}
.components-custom-select-control__label {
font-weight: bold;
}
}

View File

@ -44,7 +44,7 @@ p.sender_email_address_warning.sender_email_address_warning a {
}
p.sender_email_address_warning:first-child {
margin-top: 0; // unify spacing with parsley errors
margin-top: 1em;
}
.button.mailpoet-button-bigger {
@ -88,37 +88,3 @@ p.sender_email_address_warning:first-child {
margin-left: 10px;
}
}
.mailpoet_manage_sender_domain {
.mailpoet_table_header {
font-weight: 700 !important;
text-align: center !important; // to prevent being overwritten by widefat table classes
}
.dns_record_type_column {
font-weight: 550 !important;
text-align: center !important; // to prevent being overwritten by widefat table classes
}
}
body .components-modal__screen-overlay {
z-index: 9999999; // increased to overlay Gutenberg block inserter
}
.mailpoet-premium-modal.components-modal__frame {
max-width: 500px;
}
.mailpoet-premium-modal-footer {
display: flex;
gap: 12px;
justify-content: flex-end;
margin-top: 16px;
padding-top: 12px;
}
.mailpoet-premium-modal-error {
display: flex;
justify-content: flex-end;
margin-top: $grid-gap-half;
}

View File

@ -35,10 +35,6 @@ textarea.regular-text {
width: 25em !important;
}
.regular-text-full-width {
width: 100%;
}
@include respond-to(small-screen) {
.select2-container {
width: 100% !important;
@ -221,18 +217,4 @@ progress::-moz-progress-bar {
.mailpoet-form-notice-message {
font-style: italic;
}
.parsley-errors-list {
left: 0;
margin-top: 2px;
}
}
// We need to hide the label because it doesn't fit to our form design, and it's added automatically by Gutenberg component
.mailpoet-form-field-tags label.components-form-token-field__label {
display: none;
}
.mailpoet-form-field-disabled {
cursor: not-allowed;
}

View File

@ -92,27 +92,6 @@ h1.title.mailpoet-newsletter-listing-heading {
margin-bottom: $grid-gap;
}
#mailpoet_editor_steps_heading {
.mailpoet-top-bar {
left: 0;
.mailpoet-top-bar-beamer {
top: 4px;
}
}
}
.mailpoet-newsletter-listing-heading-buttons {
position: absolute;
right: 20px;
top: 25px;
.link-button {
background-color: transparent;
border: 0;
}
}
.mailpoet-listing-schedule {
align-items: center;
display: flex;
@ -178,6 +157,8 @@ h1.title.mailpoet-newsletter-listing-heading {
}
.mailpoet-listing-status-unknown {
color: $color-text-light;
font-weight: 600;
white-space: nowrap;
.mailpoet-listing-status-percentage {

View File

@ -51,6 +51,10 @@
margin: 0 0 9px;
}
.mailpoet-listing-pages-num {
margin-right: 21px;
}
.mailpoet-listing-pages-links > span,
.mailpoet-listing-pages-links > a {
padding: 0 3px;
@ -116,7 +120,6 @@ div.mailpoet-listing-bulk-actions-container {
.mailpoet-listing-table {
border-spacing: 0;
box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
.mailpoet-listing & {
background: #fff;
@ -157,16 +160,18 @@ div.mailpoet-listing-bulk-actions-container {
thead th,
thead th a {
color: $color-text-dark !important;
color: $color-text-light !important;
font-size: $font-size-extra-small;
font-weight: 600;
letter-spacing: 1px;
line-height: 1.4em;
padding: 12px 8px;
padding: 12px 10px;
text-transform: uppercase;
}
thead th {
border-bottom: 1px solid $color-wordpress-border;
border-bottom: 1px solid $color-tertiary-light;
box-shadow: 0 4px 4px -2px rgba($color-tertiary-light, .5);
text-align: left;
white-space: nowrap;
@ -385,23 +390,26 @@ a.mailpoet-listing-title {
}
.mailpoet-listing-check-column {
border-left: 6px solid transparent;
padding: 8px 0 8px 10px;
width: $form-control-choice-height;
.mailpoet-form-checkbox-control {
margin-right: 0;
opacity: 0;
}
thead &,
tr:hover & {
tr:hover &,
input:checked + {
.mailpoet-form-checkbox-control {
border: 2px solid $color-input-border;
opacity: 1;
}
}
}
.mailpoet-listing-row-inactive {
background: $color-grey-0;
background: rgba($color-tertiary-light, .2);
}
.mailpoet-listing-row-selected {

View File

@ -1,9 +0,0 @@
// Fix preventing HelpScout beacon to overlay pagination on listing pages
#wpbody {
padding-bottom: 20px;
}
// Fix for 3rd party plugins icons in menu that might display broken because we block loading 3rd party CSS on mailepoet pages
#adminmenu .wp-menu-image img {
max-width: 20px;
}

View File

@ -0,0 +1,38 @@
#logger {
background-color: transparent;
border: 0;
border-top: 1px #aba9a9 solid;
font-size: .85em;
height: 300px;
margin-top: 20px;
overflow: scroll;
padding: 2px;
resize: both;
width: 100%;
}
#progressbar {
background-color: #d8d8d8;
border-radius: 5px;
width: 50%;
}
$progressbar_color: #fecf23;
$progressbar_gradient_to_color: #fd9215;
.ui-progressbar .ui-progressbar-value {
background-color: $progressbar_color;
background-image: linear-gradient(to bottom, $progressbar_color, $progressbar_gradient_to_color);
border: 0;
border-radius: 3px;
box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset;
height: 100%;
}
.mailpoet_progress_label {
font-size: 15px;
}
.error_msg {
color: #f00;
}

View File

@ -93,6 +93,19 @@ div.mailpoet-premium-page-section {
}
}
.mailpoet-premium-page-does-this-sound-like-you {
align-items: center;
grid-template-columns: 1fr 2fr;
.mailpoet-grid-two-columns {
grid-column-gap: 2 * $grid-gap-large;
}
img {
max-width: 100%;
}
}
.mailpoet-premium-page-upgrade-to-premium .mailpoet-grid-three-columns {
grid-gap: $grid-gap-large;
}
@ -185,34 +198,6 @@ div.mailpoet-premium-page-section {
}
}
.mailpoet-premium-three-columns-two-orphans {
@include respond-to(not-small-screen) {
grid-template-columns: repeat(6, 1fr);
> div {
grid-column: span 2;
}
> div:last-child:nth-child(3n - 1) {
grid-column-end: -2;
}
> div:nth-last-child(2):nth-child(3n + 1) {
grid-column-end: 4;
}
}
}
.mailpoet-premium-page-options-label-wrap {
height: 3em;
}
.mailpoet-premium-feature-list-heading {
align-self: flex-start;
color: $color-secondary;
margin-bottom: 0;
}
.mailpoet-premium-page-options-label {
background: $color-tertiary;
border-radius: 0 2px 2px 0;
@ -245,6 +230,47 @@ div.mailpoet-premium-page-section {
grid-template-columns: 3fr 2fr;
}
.mailpoet-premium-page-unlimited-websites {
display: inline-block;
font-weight: bold;
margin: 0 0 $grid-gap-half;
position: relative;
text-transform: uppercase;
z-index: 0;
&:after {
background-color: $color-secondary-light;
border-radius: 2px;
bottom: .2em;
content: '';
height: .8em;
left: 0;
position: absolute;
width: 100%;
z-index: -1;
}
}
.mailpoet-premium-page-satisfaction-guarantee {
.mailpoet-premium-page-text-large {
margin: 0;
}
}
.mailpoet-premium-page-mailpoet-works {
@include full-width-background(linear-gradient(to top, $color-white, $color-secondary-light));
.mailpoet-grid-three-columns {
grid-gap: $grid-gap-large;
margin-top: $grid-gap-large;
}
}
.mailpoet-premium-page-your-alternative {
align-items: center;
grid-template-columns: 2fr 3fr;
}
.mailpoet-premium-page-footer-image {
padding-bottom: 35%;
width: 100%;

View File

@ -100,12 +100,6 @@ ul.sending-method-benefits {
.mailpoet-form-input:not(:first-child) {
margin-top: $grid-gap-half;
}
&.mailpoet-import-tags {
label.components-form-token-field__label {
display: none;
}
}
}
.mailpoet-settings-inputs-row {

View File

@ -119,10 +119,6 @@
color: $color-stats-average;
}
.mailpoet-statistics-value-number-critical {
color: $color-stats-critical;
}
.mailpoet-statistics-value-number-excellent {
color: $color-stats-excellent;
}

View File

@ -63,23 +63,6 @@ $form-line-height: 1.4;
.mailpoet-has-font-size {
line-height: $form-line-height;
}
.mailpoet_submit {
white-space: normal;
word-wrap: break-word;
}
}
/* Reset fieldset styles in form for backward compatibility. */
.mailpoet_paragraph {
fieldset,
legend {
background: transparent;
border: 0;
color: inherit;
margin: 0;
padding: 0;
}
}
.mailpoet_textarea {
@ -537,38 +520,3 @@ h2.mailpoet-heading {
font-size: 85%;
}
}
// screen-reader-text CSS class only exists within the WordPress environment
// the class does not exist when using iFrame forms due to these being used outside WordPress
// prefixing with mailpoet-* to not interfere with the default WordPress screen-reader-text class
.mailpoet-screen-reader-text {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
-webkit-clip-path: inset(50%);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
word-wrap: normal !important;
}
.mailpoet-screen-reader-text:focus {
background-color: #ddd;
clip: auto !important;
-webkit-clip-path: none;
clip-path: none;
color: #444;
display: block;
font-size: 1em;
height: auto;
line-height: normal;
padding: 15px 23px 14px;
right: 5px;
text-decoration: none;
top: 5px;
width: auto;
z-index: 100000;
}

View File

@ -11,13 +11,13 @@ select.parsley-error,
textarea.parsley-error {
background-color: #f2dede;
border-color: #eed3d7;
color: #900;
color: #b94a48;
}
.parsley-errors-list {
color: #900;
font-size: 13px;
line-height: 1em;
color: #b94a48;
font-size: .9em;
line-height: .9em;
list-style-type: none;
margin: 8px 0 3px;
opacity: 0;
@ -38,7 +38,7 @@ textarea.parsley-error {
.parsley-required,
.parsley-custom-error-message {
color: #900;
color: #b94a48;
}
.mailpoet-form-errors {

View File

@ -41,15 +41,6 @@
}
}
.mailpoet-tag-critical {
border-color: $color-stats-critical;
color: $color-stats-critical;
&.mailpoet-tag-inverted {
background: $color-stats-critical;
}
}
.mailpoet-tag-good {
border-color: $color-stats-good;
color: $color-stats-good;
@ -77,17 +68,6 @@
}
}
.mailpoet-tag-wordpress {
background: $color-wordpress-button-background;
border-color: $color-wordpress-button-border;
color: $color-wordpress-button-border;
&.mailpoet-tag-inverted {
background: $color-wordpress-button-border;
color: $color-wordpress-button-background;
}
}
.mailpoet-tag-list {
background: rgba($color-tertiary-light, .7);
border-color: transparent;

View File

@ -3,7 +3,6 @@
box-shadow: 0 2px 4px 0 rgba(229, 233, 248, .4), 0 5px 30px 0 $color-tertiary-light;
max-width: 400px;
padding: $grid-gap-half;
z-index: 9990; // Allow tooltip to display over #adminmenuwrap (lefthand menu) core style
&.show {
opacity: 1;

View File

@ -3,14 +3,16 @@ $beamer-dot-size: 8px;
.mailpoet-top-bar {
align-items: center;
background-color: $color-white;
box-shadow: inset 0 -1px 0 $color-tertiary-light;
box-shadow:
0 -1px 0 0 $color-tertiary-light,
0 2px 4px 0 opacify($color-tertiary-light, .5);
display: flex;
flex-direction: row;
height: 64px;
justify-content: flex-start;
margin: 0 0 40px;
padding-left: 25px;
padding-right: 25px;
padding-left: $grid-gap;
padding-right: $grid-gap;
.wrap & {
left: -20px;
@ -27,24 +29,23 @@ $beamer-dot-size: 8px;
top: 46px;
}
}
}
.mailpoet-top-bar-logo {
cursor: pointer;
position: relative;
top: 2px;
z-index: 1;
.mailpoet-top-bar-logo {
cursor: pointer;
position: relative;
top: 2px;
svg {
max-height: 100%;
max-width: 100%;
}
svg {
max-height: 100%;
max-width: 100%;
}
}
.mailpoet-top-bar-logo-desktop {
display: block;
height: 23px;
width: 75px;
height: 30px;
width: 100px;
@include respond-to(small-screen) {
display: none;
@ -83,22 +84,14 @@ $beamer-dot-size: 8px;
.mailpoet-top-bar-beamer {
align-items: center;
background-color: $color-white;
border: none;
color: $color-wordpress-grey-dark;
border: solid 2px $color-tertiary-light;
border-radius: 4px;
cursor: pointer;
display: flex;
flex-direction: column;
height: 60px;
height: 40px;
justify-content: center;
position: relative;
text-align: center;
text-decoration: none;
width: 75px;
svg {
display: block;
width: 100%;
}
width: 40px;
}
.mailpoet-top-bar-beamer-dot:before {

View File

@ -8,22 +8,10 @@
vertical-align: middle;
input {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
visibility: hidden;
width: 1px;
word-wrap: normal !important;
&:focus {
~ .mailpoet-form-checkbox-control {
border: 2px solid $color-input-border;
}
}
}
&.mailpoet-full-width + .mailpoet-form-checkbox.mailpoet-full-width { margin-top: $grid-gap; }

View File

@ -61,7 +61,7 @@
margin-top: $grid-gap;
}
&:not(.mailpoet-full-width) + .mailpoet-form-input:not(.mailpoet-full-width):not(.mailpoet-form-select),
&:not(.mailpoet-full-width) + .mailpoet-form-input:not(.mailpoet-full-width),
&:not(.mailpoet-full-width) + .mailpoet-button:not(.mailpoet-full-width) {
margin-left: $grid-gap;
}

View File

@ -8,22 +8,10 @@
vertical-align: middle;
input {
border: 0;
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
visibility: hidden;
width: 1px;
word-wrap: normal !important;
&:focus {
~ .mailpoet-form-radio-control {
border: 2px solid $color-input-border;
}
}
}
&.mailpoet-full-width + .mailpoet-form-radio.mailpoet-full-width { margin-top: $grid-gap; }

View File

@ -134,9 +134,8 @@
background: $color-tertiary-light !important;
}
.mailpoet-form-react-select-option {
align-items: center;
display: flex;
.mailpoet-form-react-select-option > span {
vertical-align: top;
}
.mailpoet-form-react-select-tag {

View File

@ -1,25 +0,0 @@
.mailpoet-form-token-field {
background: $color-input-background;
border: 1px solid $color-input-border !important;
border-radius: $form-control-border-radius !important;
box-sizing: border-box;
max-width: 100%;
min-height: $form-control-height;
min-width: 0;
width: $grid-column;
// To align the left padding with the other inputs
input[type=text].components-form-token-field__input {
margin-left: 0;
min-height: 30px;
padding-left: 8px;
}
// For better fit when the last item is active
li:last-child {
border-radius: 0 0 $form-control-border-radius $form-control-border-radius;
}
// Resetting is-active because other input doesn't support it
&.components-form-token-field__input-container.is-active {
box-shadow: none;
outline: 0;
}
}

View File

@ -1,4 +1,5 @@
// Utilities
// Helpers and overrides.
@import 'components-admin/menu';
@import 'components-admin/3rd-party-plugins/members';

Some files were not shown because too many files have changed in this diff Show More