Compare commits

..

2 Commits

Author SHA1 Message Date
0585a6a36c Remove changelog entry, as we only added a hook for Divi team to fix the
issue, and they need to release the fix on their end
2021-05-25 10:57:10 +03:00
fd01014ba7 Release 3.62.0 2021-05-24 17:46:11 +03:00
5624 changed files with 398238 additions and 241620 deletions

32
.babelrc Normal file
View File

@ -0,0 +1,32 @@
{
"presets": [
"@babel/preset-typescript",
"@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",
{
"sourceType": "unambiguous",
"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

@ -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: |
{
@ -60,73 +60,57 @@ slack-fail-post-step: &slack-fail-post-step
anchors:
default_job_config: &default_job_config
resource_class: small
working_directory: /home/circleci/mailpoet/mailpoet
working_directory: /home/circleci/mailpoet
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
only_trunk_and_cot: &only_trunk_and_cot
filters:
branches:
only:
- trunk
- /^cot-.*/
multisite_acceptance_config: &multisite_acceptance_config
multisite: 1
requires:
- unit_tests
- static_analysis_php7
- 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
wpcli_php_max_wporg:
<<: *default_job_config
docker:
- image: mailpoet/wordpress:7.4_20210122.1
- image: mailpoet/wordpress:7.1_20201009.1
wpcli_php_latest:
<<: *default_job_config
docker:
- image: mailpoet/wordpress:8.1_20220718.1
- image: mailpoet/wordpress:8.0_20210218.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.1_20201009.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_20210218.1
- image: circleci/mysql:8.0-ram
command: [--default-authentication-plugin=mysql_native_password]
jobs:
build:
executor: wpcli_php_latest
resource_class: medium+
working_directory: /home/circleci/mailpoet/mailpoet
resource_class: medium
steps:
- checkout:
path: /home/circleci/mailpoet
- checkout
- 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" }}
@ -140,11 +124,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
@ -153,10 +138,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:
@ -180,161 +161,143 @@ 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: Group acceptance tests to run in parallel
command: |
./do test:acceptance-group-tests
- run:
name: Download additional WP Plugins for tests
command: |
./do download:woo-commerce-zip 6.8.2
./do download:woo-commerce-subscriptions-zip 4.5.1
./do download:woo-commerce-memberships-zip 1.23.0
./do download:woo-commerce-blocks-zip 8.4.0
./do download:woo-commerce-zip 5.2.2
./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
git clone ${MAILPOET_PREMIUM_REPO_URL} mailpoet-premium
git clone ${MAILPOET_PREMIUM_REPO_URL} mp3premium
- restore_cache:
key: premium-tools-{{ checksum "mailpoet-premium/tools/install.php" }}
key: premium-tools-{{ checksum "mp3premium/tools/install.php" }}
- restore_cache:
key: premium-composer-{{ checksum "mailpoet-premium/composer.json" }}-{{ checksum "mailpoet-premium/composer.lock" }}
key: premium-composer-{{ checksum "mp3premium/composer.json" }}-{{ checksum "mp3premium/composer.lock" }}
- run:
name: 'Set up test environment'
name: "Set up test environment"
command: |
# install Premium dependencies
MAILPOET_FREE_PATH=$(pwd)/mailpoet
cd mailpoet-premium
MAILPOET_FREE_PATH=$(pwd)
cd mp3premium
COMPOSER_DEV_MODE=1 php tools/install.php
echo "MAILPOET_FREE_PATH=${MAILPOET_FREE_PATH}" > .env
./tools/vendor/composer.phar validate --no-check-all --no-check-publish
./do install
./do compile:all --env production
cd ..
- save_cache:
key: premium-tools-{{ checksum "mailpoet-premium/tools/install.php" }}
key: premium-tools-{{ checksum "mp3premium/tools/install.php" }}
paths:
- mailpoet-premium/tools/vendor
- mp3premium/tools/vendor
- save_cache:
key: premium-composer-{{ checksum "mailpoet-premium/composer.json" }}-{{ checksum "mailpoet-premium/composer.lock" }}
key: premium-composer-{{ checksum "mp3premium/composer.json" }}-{{ checksum "mp3premium/composer.lock" }}
paths:
- mailpoet-premium/vendor
- mp3premium/vendor
- persist_to_workspace:
root: /home/circleci
root: /home/circleci/mailpoet
paths:
- .node
- mailpoet
- .
static_analysis:
executor: wpcli_php_latest
resource_class: medium
working_directory: /home/circleci/mailpoet/mailpoet
parameters:
php_version:
type: integer
default: 70200
default: 70100
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
- run:
name: 'QA PHP'
command: ./do qa:php-max-wporg
js_tests:
executor: wpcli_php_latest
working_directory: /home/circleci/mailpoet/mailpoet
executor: wpcli_php_oldest
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
working_directory: /home/circleci/mailpoet
machine:
image: ubuntu-2204:2022.07.1
image: ubuntu-2004:202101-01
parameters:
group_arg:
type: string
default: ''
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: ''
@ -344,124 +307,50 @@ 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
allow_fail:
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'
# 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:
condition: << parameters.woo_core_version >>
steps:
- 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
- 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
# `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
cat tests/acceptance/_groups/circleci_split_group
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: Run acceptance tests
command: |
mkdir -m 777 -p tests/_output/exceptions
cd tests/docker
args=(
--steps
--debug
-vvv
--html
--xml
-g circleci_split_group
)
if [[ << parameters.allow_fail >> == 1 ]]; then
args+=(--no-exit)
fi
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[@]}"
- when:
condition:
not:
equal: [1, << parameters.allow_fail >>]
steps:
- run:
name: Check exceptions
command: |
if [ "$(ls tests/_output/exceptions/*.html)" ]; then
echo "There were some exceptions during the tests run"
exit 1
fi
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 << parameters.group_arg >> --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
- store_artifacts:
path: tests/_output
- store_test_results:
path: tests/_output
unit_tests:
working_directory: /home/circleci/mailpoet/mailpoet
parameters:
executor:
type: string
@ -469,18 +358,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'
command: source ../.circleci/setup.bash && setup php7
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:
@ -492,126 +381,77 @@ jobs:
path: /tmp/fake-mailer/
destination: fake-mailer
integration_tests:
working_directory: /home/circleci/mailpoet/mailpoet
machine:
image: ubuntu-2204:2022.07.1
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
woo_core_version:
type: string
default: ''
allow_fail:
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
- when:
condition: << parameters.woo_core_version >>
steps:
- 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 codeception_integration
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
if [[ << parameters.allow_fail >> == 1 ]]; then
args+=(--no-exit)
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+
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
source ./.circleci/setup.bash && setup php7
sudo apt-get update
sudo apt-get install gettext
sed -i 's/^WP_ROOT=.*$/WP_ROOT=\/home\/circleci\/mailpoet\/wordpress/g' .env
sudo apt-get install python-pip gettext
sudo pip install transifex-client
mv wordpress ..
sed -i 's/^WP_ROOT=.*$/WP_ROOT=\/home\/circleci\/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
path: /home/circleci/mailpoet/mailpoet.zip
- persist_to_workspace:
root: /home/circleci/mailpoet
paths:
- mailpoet/release_zip_build_number.txt
- release_zip_build_number.txt
test_deployment:
executor: wpcli_php_latest
steps:
- attach_workspace:
at: /home/circleci/mailpoet
- run:
name: "Deploy"
command: |
RELEASE_ZIP_BUILD_NUMBER=`cat release_zip_build_number.txt`
curl "${MAILPOET_TEST_DEPLOY_HOST}/wp-admin/admin-ajax.php?action=mailpoet_test_deploy&key=${MAILPOET_TEST_DEPLOY_KEY}&build=${RELEASE_ZIP_BUILD_NUMBER}&plugin_name=${CIRCLE_PROJECT_REPONAME}" | tee deploy.log | grep "Done! Installed successfully"
- store_artifacts:
path: deploy.log
workflows:
build_and_test:
@ -626,7 +466,7 @@ workflows:
- static_analysis:
<<: *slack-fail-post-step
name: static_analysis_php7
php_version: 70200
php_version: 70100
requires:
- build
- static_analysis:
@ -647,54 +487,83 @@ workflows:
<<: *slack-fail-post-step
requires:
- build
- qa_php_max_wporg:
<<: *slack-fail-post-step
requires:
- build
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_tests
name: acceptance_tests_1
group_arg: -g acceptance_group_1
requires:
- unit_tests
- static_analysis_php7
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
<<: *only_trunk_and_cot
name: acceptance_tests_woo_cot_sync
group: woo
enable_cot: 1
enable_cot_sync: 1
allow_fail: 1
woo_core_version: woo-cot-beta # Temporarily force COT beta version
name: acceptance_tests_2
group_arg: -g acceptance_group_2
requires:
- unit_tests
- static_analysis_php7
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
<<: *only_trunk_and_cot
name: acceptance_tests_woo_cot_no_sync
group: woo
enable_cot: 1
enable_cot_sync: 0
allow_fail: 1
woo_core_version: woo-cot-beta # Temporarily force COT beta version
name: acceptance_tests_3
group_arg: -g acceptance_group_3
requires:
- unit_tests
- static_analysis_php7
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
<<: *only_trunk_and_cot
name: acceptance_tests_woo_cot_off
group: woo
woo_core_version: woo-cot-beta # Temporarily force COT beta version
name: acceptance_tests_4
group_arg: -g acceptance_group_4
requires:
- unit_tests
- static_analysis_php7
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_tests_5
group_arg: -g acceptance_group_5
requires:
- unit_tests
- static_analysis_php7
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_tests_6
group_arg: -g acceptance_group_6
requires:
- unit_tests
- static_analysis_php7
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_tests_7
group_arg: -g acceptance_group_7
requires:
- unit_tests
- static_analysis_php7
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
name: acceptance_tests_8
group_arg: -g acceptance_group_8
requires:
- unit_tests
- static_analysis_php7
- static_analysis_php8
- qa_js
- qa_php
@ -704,71 +573,58 @@ workflows:
- 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
<<: *only_trunk_and_cot
group: woo
enable_cot: 1
enable_cot_sync: 1
allow_fail: 1
woo_core_version: woo-cot-beta # Temporarily force COT beta version
name: integration_test_woo_cot_sync
requires:
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- integration_tests:
<<: *slack-fail-post-step
<<: *only_trunk_and_cot
group: woo
enable_cot: 1
enable_cot_sync: 0
allow_fail: 1
woo_core_version: woo-cot-beta # Temporarily force COT beta version
name: integration_test_woo_cot_no_sync
requires:
- unit_tests
- static_analysis_php8
- qa_js
- qa_php
- integration_tests:
<<: *slack-fail-post-step
<<: *only_trunk_and_cot
group: woo
woo_core_version: woo-cot-beta # Temporarily force COT beta version
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_php7
- static_analysis_php8
- qa_js
- qa_php
- acceptance_tests:
<<: *slack-fail-post-step
<<: *multisite_acceptance_config
name: acceptance_tests_multisite
name: acceptance_tests_multisite_1
group_arg: -g acceptance_group_1
- acceptance_tests:
<<: *slack-fail-post-step
<<: *multisite_acceptance_config
name: acceptance_tests_multisite_2
group_arg: -g acceptance_group_2
- acceptance_tests:
<<: *slack-fail-post-step
<<: *multisite_acceptance_config
name: acceptance_tests_multisite_3
group_arg: -g acceptance_group_3
- acceptance_tests:
<<: *slack-fail-post-step
<<: *multisite_acceptance_config
name: acceptance_tests_multisite_4
group_arg: -g acceptance_group_4
- acceptance_tests:
<<: *slack-fail-post-step
<<: *multisite_acceptance_config
name: acceptance_tests_multisite_5
group_arg: -g acceptance_group_5
- acceptance_tests:
<<: *slack-fail-post-step
<<: *multisite_acceptance_config
name: acceptance_tests_multisite_6
group_arg: -g acceptance_group_6
- acceptance_tests:
<<: *slack-fail-post-step
<<: *multisite_acceptance_config
name: acceptance_tests_multisite_7
group_arg: -g acceptance_group_7
- acceptance_tests:
<<: *slack-fail-post-step
<<: *multisite_acceptance_config
name: acceptance_tests_multisite_8
group_arg: -g acceptance_group_8
- 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
@ -779,19 +635,30 @@ workflows:
<<: *slack-fail-post-step
requires:
- build
- acceptance_tests
- acceptance_tests_1
- acceptance_tests_2
- acceptance_tests_3
- acceptance_tests_4
- acceptance_tests_5
- acceptance_tests_6
- acceptance_tests_7
- acceptance_tests_8
- js_tests
- integration_test_woocommerce
- integration_test_base
- integration_tests
- test_deployment:
<<: *slack-fail-post-step
<<: *only_master_and_release
requires:
- build_release_zip
nightly:
triggers:
- schedule:
cron: '0 22 * * 1-5'
cron: "0 22 * * 1-5"
filters:
branches:
only:
- trunk
- master
jobs:
- build:
<<: *slack-fail-post-step
@ -800,21 +667,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.2.2
woo_subscriptions_version: 4.3.0
woo_memberships_version: 1.21.0
woo_blocks_version: 5.3.2
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_20210126.1
wordpress_image_version: wp-5.6_php7.2_20220406.1
mysql_image_version: 5.5-ram
wordpress_image_version: wp-5.3_php7.1_20210129.1
requires:
- build
- unit_tests:
@ -836,7 +698,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

@ -1,19 +1,16 @@
#!/usr/bin/env bash
function setup {
local script_dir="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
local root_dir="$(dirname "$script_dir")"
local version=$1
local wp_cli_wordpress_path="--path=$root_dir/wordpress"
local wp_cli_wordpress_path="--path=wordpress"
local wp_cli_allow_root="--allow-root"
# Add a fake sendmail mailer
sudo cp "$script_dir/fake-sendmail.php" /usr/local/bin/
sudo cp ./.circleci/fake-sendmail.php /usr/local/bin/
# configure Apache
sudo cp "$script_dir/mailpoet_php.ini" /etc/php.d/
sudo cp "$script_dir/apache/mailpoet.loc.conf" /etc/apache2/sites-available
sudo cp ./.circleci/mailpoet_php.ini /usr/local/etc/php/conf.d/
sudo cp ./.circleci/apache/mailpoet.loc.conf /etc/apache2/sites-available
sudo a2dissite 000-default.conf
sudo a2ensite mailpoet.loc
sudo a2enmod rewrite
@ -29,33 +26,35 @@ 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_';/" ./wordpress/wp-config.php
# Install WordPress
if [[ $version == "php7_multisite" ]]; then
# Configure multisite environment
wp core multisite-install --admin_name=admin --admin_password=admin --admin_email=admin@mailpoet.loc --url=http://mailpoet.loc --title="WordPress MultiSite" $wp_cli_wordpress_path $wp_cli_allow_root
cp "$script_dir/wordpress/.htaccess" "$root_dir/wordpress/"
cp ./.circleci/wordpress/.htaccess ./wordpress/
# Add a second blog
wp site create --slug=php7_multisite $wp_cli_wordpress_path $wp_cli_allow_root
echo "WP_TEST_MULTISITE_SLUG=php7_multisite" >> "$root_dir/mailpoet/.env"
echo "WP_ROOT_MULTISITE=/home/circleci/mailpoet/wordpress" >> "$root_dir/mailpoet/.env"
echo "HTTP_HOST=mailpoet.loc" >> "$root_dir/mailpoet/.env"
echo "WP_TEST_MULTISITE_SLUG=php7_multisite" >> .env
echo "WP_ROOT_MULTISITE=/home/circleci/mailpoet/wordpress" >> .env
echo "HTTP_HOST=mailpoet.loc" >> .env
# Add a third dummy blog
wp site create --slug=dummy_multisite $wp_cli_wordpress_path $wp_cli_allow_root
else
wp core install --admin_name=admin --admin_password=admin --admin_email=admin@mailpoet.loc --url=http://mailpoet.loc --title="WordPress Single" $wp_cli_wordpress_path $wp_cli_allow_root
echo "WP_ROOT=/home/circleci/mailpoet/wordpress" >> "$root_dir/mailpoet/.env"
echo "WP_ROOT=/home/circleci/mailpoet/wordpress" >> .env
fi
# Softlink plugin to plugin path
ln -s ../../../mailpoet ../wordpress/wp-content/plugins/mailpoet
ln -s ../../.. wordpress/wp-content/plugins/mailpoet
# Activate plugin
if [[ $version == "php7_multisite" ]]; then
@ -66,13 +65,8 @@ function setup {
if [[ $CIRCLE_JOB == *"_with_premium_"* ]]; then
# Softlink MailPoet Premium to plugin path
ln -s ../../../mailpoet-premium ../wordpress/wp-content/plugins/mailpoet-premium
ln -s ../../../mp3premium wordpress/wp-content/plugins/mailpoet-premium
# Activate MailPoet Premium
wp plugin activate mailpoet-premium --path="$root_dir/wordpress"
wp plugin activate mailpoet-premium --path=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

@ -1,4 +0,0 @@
.idea
mailpoet
mailpoet-premium
wordpress

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

34
.env.sample Normal file
View File

@ -0,0 +1,34 @@
# Required
WP_ROOT="/var/www/wordpress"
WP_TEST_ENABLE_NETWORK_TESTS="false"
WP_TEST_MAILER_ENABLE_SENDING="false"
# Optional: for multisite acceptance tests
WP_ROOT_MULTISITE="/var/www/wordpress"
WP_TEST_MULTISITE_SLUG=""
HTTP_HOST="" # URL of your site (used for multisite env and equals to DOMAIN_CURRENT_SITE from wp-config.php)
# Optional: for sending tests
# These are required if WP_TEST_MAILER_ENABLE_SENDING is "true"
WP_TEST_IMPORT_MAILCHIMP_API=""
WP_TEST_IMPORT_MAILCHIMP_LISTS="" # (separated with comma)
WP_TEST_MAILER_AMAZON_ACCESS=""
WP_TEST_MAILER_AMAZON_SECRET=""
WP_TEST_MAILER_AMAZON_REGION=""
WP_TEST_MAILER_MAILPOET_API=""
WP_TEST_MAILER_SENDGRID_API=""
WP_TEST_MAILER_SMTP_HOST=""
WP_TEST_MAILER_SMTP_LOGIN=""
WP_TEST_MAILER_SMTP_PASSWORD=""
# Optional: for plugin deployment
WP_SVN_USERNAME=""
WP_SVN_PASSWORD=""
WP_TRANSIFEX_API_TOKEN=""
WP_JIRA_USER="" # JIRA username/email
WP_JIRA_TOKEN="" # JIRA token from https://id.atlassian.com/manage/api-tokens
WP_CIRCLECI_USERNAME="" # CircleCI organization or user
WP_CIRCLECI_TOKEN="" # CircleCI token from https://circleci.com/gh/{user|org}/{project}/edit#api
WP_GITHUB_USERNAME="" # GitHub username (not email)
WP_GITHUB_TOKEN="" # GitHub token from https://github.com/settings/tokens
WP_SLACK_WEBHOOK_URL="" # Webhook URL from https://mailpoet.slack.com/services/BHRB9AHSQ

16
.eslintrc.es5.json Normal file
View File

@ -0,0 +1,16 @@
{
"extends": "airbnb/legacy",
"env": {
"amd": true,
"browser": true
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
},
"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
"comma-dangle": ["error", "always-multiline"]
}
}

57
.eslintrc.es6.json Normal file
View File

@ -0,0 +1,57 @@
{
"extends": "airbnb",
"env": {
"amd": true,
"browser": true,
"mocha": true
},
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 6,
"ecmaFeatures": {
"jsx": true
}
},
"plugins": [
"react-hooks",
"no-only-tests"
],
"settings": {
"import/resolver": "webpack"
},
"rules": {
// Hooks
"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,
"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/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
}],
"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": [
{
"files": ["*.spec.js"],
"rules": {
"no-unused-expressions": "off"
}
}
]
}

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,26 +19,15 @@
"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": [
"@woocommerce/blocks-checkout",
"@woocommerce/settings",
"@wordpress/a11y",
"@wordpress/api-fetch",
"@wordpress/block-editor",
"@wordpress/compose",
"@wordpress/data",
"@wordpress/escape-html",
"@wordpress/hooks",
"@wordpress/keycodes",
"@wordpress/url",
"react"
]
"import/resolver": "webpack"
},
"rules": {
"react/no-unstable-nested-components": ["error", { "allowAsProps": true }],
// PropTypes
"react/prop-types": 0,
"react/jsx-props-no-spreading": 0,
@ -50,55 +36,43 @@
"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,
"@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 :(
"arrow-parens": ["error", "always"],
"comma-dangle": ["error", "always-multiline"],
"no-only-tests/no-only-tests": 2,
"no-script-url": 0,
"@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 }]
}
},
{
@ -301,7 +275,6 @@
"assets/js/src/form_editor/store/reducers/history_record.ts",
"assets/js/src/form_editor/store/reducers/toggle_form.ts",
"assets/js/src/form_editor/store/reducers/toggle_fullscreen.ts",
"assets/js/src/form_editor/store/reducers/toggle_sidebar.ts",
"assets/js/src/form_editor/store/reducers/tutorial_dismiss.ts",
"assets/js/src/form_editor/template_selection.tsx",
"assets/js/src/form_editor/translations.ts",

View File

@ -22,7 +22,7 @@ f49757bd4e129d44102a932246c5e892d362054d
# Convert properties not caught by Code Sniffer to camel case
94afd663259d6600e51c8e13084f7f126874d29e
# Exclude globals from camel case conversion
# Exclude globals from camel case conversion
6522635dc7455e39ca77370a18a9987de13c61b0
# Convert Doctrine specific code to camel case
@ -33,9 +33,3 @@ fbcaeaadbca33e6cc9aef0925be019e9b4923a93
# Exclude MailPoet data structures from camel case conversion
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

36
.gitignore vendored
View File

@ -1,10 +1,36 @@
.DS_Store
TODO
/vendor
/vendor-prefixed
/vendor_backup
/vendor-backup
/vendor-prefixed-backup
tests/_output/*
tests/_support/_generated/*
tests/plugins
node_modules
.env
npm-debug.log
!tasks/**
/views/cache/**
temp
.idea
.vscode
dev/data
mailpoet.zip
tests/javascript_newsletter_editor/testBundles
assets/dist
.vagrant
lang
.mp_svn
/nbproject/
tests/_data/acceptanceBackup.sql
lib/DI/CachedContainer.php
prefixer/vendor
prefixer/build
docker-compose.override.yml
node_modules
npm-debug.log
mailpoet-premium
wordpress
tasks/code_sniffer/vendor
tasks/phpstan/vendor
tasks/phpstan/_phpstan-wp-source.neon
/tools/vendor
/storybook-static
assets/js/src/newsletter_editor/behaviors/tinymce_icons.js

1
.husky/.gitignore vendored
View File

@ -1 +0,0 @@
_

View File

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

3
.npmrc
View File

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

2
.nvmrc
View File

@ -1 +1 @@
v17.9.1
v15.14.0

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"
}

29
.storybook/main.js Normal file
View File

@ -0,0 +1,29 @@
const path = require('path');
module.exports = {
stories: ['../assets/js/src/**/_stories/*.tsx'],
webpackFinal: (config) => ({
...config,
resolve: {
...config.resolve,
modules: ['node_modules', '../assets/js/src'],
},
}),
addons: [
'@storybook/addon-actions',
'@storybook/addon-links',
'storybook-addon-performance/register',
{
name: '@storybook/addon-storysource',
options: {
rule: {
test: [/_stories\/.*\.tsx?$/],
include: [path.resolve(__dirname, '../assets/js/src')],
},
loaderOptions: {
parser: 'typescript',
},
},
},
],
};

9
.storybook/preview.js Normal file
View File

@ -0,0 +1,9 @@
import React from 'react';
import { addDecorator } from '@storybook/react';
import { withPerformance } from 'storybook-addon-performance';
import '../assets/dist/css/mailpoet-font.css';
import '../assets/dist/css/mailpoet-plugin.css';
import '../assets/dist/css/mailpoet-form-editor.css';
addDecorator(withPerformance);
addDecorator(story => <div id="wpbody"><div id="mailpoet-modal"></div>{story()}</div>);

110
.stylelintrc Normal file
View File

@ -0,0 +1,110 @@
{
"plugins": [
"stylelint-order",
"stylelint-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-calc-no-invalid": 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,
},
}

9
.tx/config Normal file
View File

@ -0,0 +1,9 @@
[main]
host = https://www.transifex.com
[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,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. */`
- for PHP we do the same with the exception `// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps` which for now doesnt require an explanation
`/* 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.NotCamelCaps` 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).

271
README.md
View File

@ -1,150 +1,211 @@
# MailPoet
The **MailPoet** plugin monorepo.
MailPoet done the right way.
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).
# Contents
## 🔌 Initial setup
- [Setup](#setup)
- [Frameworks and libraries](#frameworks-and-libraries)
- [Workflow Commands](#workflow-commands)
- [Coding and Testing](#coding-and-testing)
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.
# Setup
## ✅ Additional dependencies
## Requirements
- PHP >= 7.3 (only for the development environment, to run the plugin PHP >= 7.1 is required)
- NodeJS
- WordPress
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:
## Installation
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`.
The instructions below assume you already have a working WordPress development environment.
## 🔍 PHPStorm setup for XDebug
In `Languages & Preferences > PHP > Servers` set path mappings:
```shell
wordpress -> /var/www/html
mailpoet -> /var/www/html/wp-content/plugins/mailpoet
mailpoet-premium -> /var/www/html/wp-content/plugins/mailpoet-premium
```bash
# go to WP plugins directory
$ cd path_to_wp_directory/wp-content/plugins
# clone this repository
$ git clone https://github.com/mailpoet/mailpoet.git
$ cd mailpoet
# create the .env file
$ cp .env.sample .env
# change the values on .env file
# install all dependencies (PHP and JS)
$ ./do install
# compile JS and CSS files
$ ./do compile:all
```
For PHP 8 and XDebug 3 we support **browser debugging extension**.
You can choose extension by your browser in [JetBrains documentation](https://www.jetbrains.com/help/phpstorm/browser-debugging-extensions.html).
# Frameworks and libraries
To use XDebug inside the **cron**, you need to pass a URL argument `&XDEBUG_TRIGGER=yes`
[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).
- [Paris ORM](https://github.com/j4mie/paris).
- [Symfony/dependency-injection](https://github.com/symfony/dependency-injection) ([docs for 3.4](https://symfony.com/doc/3.4/components/dependency_injection.html)).
- [PHP-Scoper](https://github.com/humbug/php-scoper) for moving dependencies into MP namespace
- [Twig](https://twig.symfony.com/) and [Handlebars](https://handlebarsjs.com/) are used for templates rendering.
- [Monolog](https://seldaek.github.io/monolog/) is used for logging.
- [Robo](https://robo.li/) is used to write and run workflow commands.
- [Codeception](https://codeception.com/) is used to write unit and acceptance tests.
- [Docker](https://www.docker.com/), [Docker Compose](https://docs.docker.com/compose/) and [Selenium](https://www.seleniumhq.org/) to run acceptance tests.
- [React](https://reactjs.org/) is used to create most of UIs.
- [Marionette](https://marionettejs.com/) is used to build the newsletters editor.
- [SCSS](http://sass-lang.com/) is used to write styles.
- [Mocha](https://mochajs.org/), [Chai](https://www.chaijs.com/) and [Sinon](https://sinonjs.org/) are used to write Javascript tests.
- [ESLint](https://eslint.org/) is used to lint JS files.
- [Webpack](https://webpack.js.org/) is used to bundle assets.
## Xdebug develop mode
# Workflow Commands
[Xdebug develop mode](https://xdebug.org/docs/develop) is disabled by default because it causes performance issues due to conflicts with the DI container.
```bash
$ ./do install # install PHP and JS dependencies
$ ./do update # update PHP and JS dependencies
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`:
$ ./do compile:css # compiles SCSS files into CSS.
$ ./do compile:js # bundles JS files for the browser.
$ ./do compile:all # compiles CSS and JS files.
```
environment:
XDEBUG_MODE: debug, develop
$ ./do watch:css # watch CSS files for changes and compile them.
$ ./do watch:js # watch JS files for changes and compile them.
$ ./do watch # watch CSS and JS files for changes and compile them.
$ ./do test:unit [--file=...] [--debug]
# runs the PHP unit tests.
# if --file specified then only tests on that file are executed.
# if --debug then tests are executed in debugging mode.
$ ./do test:integration [--file=...] [--multisite] [--debug]
# runs the PHP integration tests.
# if --file specified then only tests on that file are executed.
# if --multisite then tests are executed in a multisite wordpress setup.
# if --debug then tests are executed in debugging mode.
$ ./do test:multisite-integration # alias for ./do test:integration --multisite
$ ./do test:debug-unit # alias for ./do test:unit --debug
$ ./do test:debug-integration # alias for ./do test:integration --debug
$ ./do test:failed-unit # run the last failing unit test.
$ ./do test:failed-integration # run the last failing integration test.
$ ./do test:coverage # run tests and output coverage information.
$ ./do test:javascript # run the JS tests.
$ ./do test:acceptance [--file=...] [--skip-deps]
# run acceptances tests into a docker environment.
# if --file given then only tests on that file are executed.
# if --skip-deps then it skips installation of composer dependencies.
$ ./do test:acceptance-multisite [--file=...] [--skip-deps]
# download 3rd party plugins for tests
# if you pass tag it will attempt to download zip for the tag otherwise it downloads the latest release
# e.g. ./do download:woo-commerce-zip 5.20.0
$ ./do download:woo-commerce-zip [<tag>]
$ ./do download:woo-commerce-subscriptions-zip [<tag>]
# same as test:acceptance but runs into a multisite wordpress setup.
$ ./do delete:docker # stop and remove all running docker containers.
$ ./do qa:lint # PHP code linter.
$ ./do qa:lint-javascript # JS code linter.
$ ./do qa:phpstan # PHP code static analysis using PHPStan.
$ ./do qa # PHP and JS linters.
$ ./do release:changelog-get [--version-name=...] # Prints out changelog and release notes for given version or for newest version.
$ ./do release:changelog-update [--version-name=...] [--quiet] # Updates changelog in readme.txt for given version or for newest version.
$ ./do container:dump # Generates DI container cache.
$ ./do generate:data [<generatorName>] [<threads>] # Generates random usage data (Note: requires WooCommerce active) e.g. ./do generate:data past_revenues 4
```
## Xdebug for integration tests
# Storybook
- 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:
We use [Storybook.js](https://storybook.js.org/) to showcase our React components, which can be used throughout the plugin.
```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
## Usage
Currently, we don't have Storybook published publicly, so developers need to run or build it locally.
To run it locally (on `http://localhost:8083`) while watching the changes (recommended when developing new component), run
```bash
./do storybook:watch
```
- 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
To build the static version, which can be accessed via browser, run
## 💾 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
```bash
./do storybook:build
```
Then create a Docker Compose override file with NFS settings and restart containers:
which will create a `storybook-static` folder with all necessary files. Don't forget to rebuild it when new components are added.
```shell
cp docker-compose.override.macos-sample.yml docker-compose.override.yml
## Building new components
docker-compose down -v --remove-orphans
docker-compose up -d
- All stories should be located in `_stories` folder inside the component folder they belong to.
- Run `./do storybook:watch` so all changes are automatically reflected in `http://localhost:8083`.
- Examples are available in `assets/js/src/storybook_demo/_stories` folder.
# Coding and Testing
## DI
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.
## PHP-Scoper
We use PHP-Scoper package to prevent plugin libraries conflicts in PHP. Two plugins may be using different versions of a library. PHP-Scoper prefix dependencies namespaces and they are then moved into `vendor-prefixed` directory.
Dependencies handled by PHP-Scoper are configured in extra configuration files `prefixer/composer.json` and `prefixer/scoper.inc.php`. Installation and processing is triggered in post scripts of the main `composer.json` file.
## i18n
We use functions `__()`, `_n()` and `_x()` with domain `mailpoet` to translate strings.
**in PHP code**
```php
__('text to translate', 'mailpoet');
_n('single text', 'plural text', $number, 'mailpoet');
_x('text to translate', 'context for translators', 'mailpoet');
```
**NOTE:** If you are on MacOS Catalina or newer, make sure to put the repository
outside your `Documents` folder, otherwise you may run into [file permission issues](https://objekt.click/2019/11/docker-the-problem-with-macos-catalina/).
**in Twig views**
# 🐶 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"
```html
<%= __('text to translate') %>
<%= _n('single text', 'plural text', $number) %>
<%= _x('text to translate', 'context for translators') %>
```
Without it, you may experience errors in some Git clients.
The domain `mailpoet` will be added automatically by the Twig functions.
## 🕹 Commands
**in Javascript code**
The `./do` script define aliases for most of the commands you will need while working on plugins:
First add the string to the translations block in the Twig view:
```shell
./do setup Setup the environment.
./do start Start the docker containers.
./do stop Stop the docker containers.
./do ssh [--test] Run an interactive bash shell inside the plugin directory.
./do run [--test] <command> Run a custom bash command in the wordpress container.
./do acceptance [--premium] Run acceptance tests.
./do build [--premium] Builds a .zip for the plugin.
./do templates Generates templates classes and assets.
./do [--test] [--premium] <command> Run './do <command>' inside the plugin directory.
Options:
--test Run the command using the 'test_wordpress' service.
--premium Run the command inside the premium plugin.
```html
<% block translations %>
<%= localize({
'key': __('string to translate'),
...
}) %>
<% endblock %>
```
You can access this help in your command line running `./do` without parameters.
Then use `MailPoet.I18n.t('key')` to get the translated string on your Javascript code.
## ✉️ Adding new templates to the plugin
## Acceptance testing
[Read the article.](https://mailpoet.atlassian.net/wiki/spaces/MAILPOET/pages/629374977/Adding+new+templates+to+the+plugin)
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.
## 🚥 Testing with PHP 7.4 or PHP 8.0
If there are some unexpected errors you can delete all the runtime and start again.
To delete all the docker runtime for acceptance tests use the command `./do d:d`.
To switch the environment to PHP 7.4/8.0:
When debugging you can add `$i->pause();` in to your test which pauses the execution.
1. Configure the `wordpress` service in `docker-compose.override.yml` to build from the php74 Dockerfile:
We are using Gravity Flow plugin's setup as an example for our acceptance test suite: https://www.stevenhenty.com/learn-acceptance-testing-deeply/
```yaml
wordpress:
build:
context: .
dockerfile: dev/php74/Dockerfile # OR dev/php80/Dockerfile
```
From the article above:
2. Run `docker-compose build wordpress`.
3. Start the stack with `./do start`.
_Windows users only: enable hard drive sharing in the Docker settings._
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,
and start the stack using `./do start`.
## ✅ TODO
- install woo commerce, members and other useful plugins by default
The browser runs in a docker container. You can use a VNC client to watch the test run, follow instructions in official
repo: https://github.com/SeleniumHQ/docker-selenium
If youre on a Mac, you can open vnc://localhost:5900 in Safari to watch the tests running in Chrome. If youre on Windows, youll need a VNC client. Password: secret.

1067
RoboFile.php Normal file

File diff suppressed because it is too large Load Diff

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

@ -0,0 +1,18 @@
@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;
}

View File

@ -0,0 +1,170 @@
input.mailpoet_color {
width: 5em;
}
select.mailpoet_font-family {
width: 8em;
}
select.mailpoet_font-size {
width: 5em;
}
.mailpoet_input,
.mailpoet_select {
$form-control-padding: 3px;
appearance: none;
border-radius: 1px;
box-shadow: none !important;
line-height: 28px - $form-control-padding * 2;
padding: $form-control-padding;
}
.mailpoet_input {
border: 1px solid $color-editor-border-content;
width: 283px;
}
.mailpoet_input_small {
width: 58px;
}
.mailpoet_input_medium {
width: 150px;
}
.mailpoet_input_full {
box-sizing: border-box;
margin: 0;
width: 100%;
}
.mailpoet_range {
-webkit-appearance: none;
padding: 0;
vertical-align: middle;
width: 283px;
&:focus {
outline: none;
}
&::-webkit-slider-runnable-track {
background: $range-track-background-color;
border: 1px solid $range-track-border-color;
border-radius: $range-border-radius;
cursor: pointer;
height: $range-track-height;
width: 100%;
}
&::-webkit-slider-thumb {
-webkit-appearance: none;
background: $range-thumb-background-color;
border: 1px solid $range-thumb-border-color;
border-radius: $range-border-radius;
cursor: pointer;
height: $range-thumb-height;
margin-top: -1 * $range-thumb-height / 3;
width: $range-thumb-width;
}
&:hover::-webkit-slider-thumb {
background: $range-thumb-hover-background-color;
}
&::-moz-range-track {
background: $range-track-background-color;
border: 1px solid $range-track-border-color;
border-radius: $range-border-radius;
cursor: pointer;
height: $range-track-height;
width: 100%;
}
&::-moz-range-thumb {
background: $range-thumb-background-color;
border: 1px solid $range-thumb-border-color;
border-radius: $range-border-radius;
cursor: pointer;
height: $range-thumb-height;
width: $range-thumb-width;
}
&:hover::-moz-range-thumb {
background: $range-thumb-hover-background-color;
}
&::-ms-fill-lower {
background: $range-track-background-color;
border: 1px solid $range-track-border-color;
}
&::-ms-fill-upper {
background: $range-track-background-color;
border: 1px solid $range-track-border-color;
}
&::-ms-track {
background: transparent;
border-color: transparent;
border-width: $range-track-height * 2 0;
color: transparent;
cursor: pointer;
height: $range-track-height;
width: 100%;
}
&::-ms-thumb {
background: $range-thumb-background-color;
border: 1px solid $range-thumb-border-color;
border-radius: $range-border-radius;
cursor: pointer;
height: $range-thumb-height;
width: $range-thumb-width;
}
&:hover::-ms-thumb {
background: $range-thumb-hover-background-color;
}
&:focus::-ms-fill-lower {
background: $range-track-background-color;
border: 1px solid $range-track-border-color;
}
&:focus::-ms-fill-upper {
background: $range-track-background-color;
border: 1px solid $range-track-border-color;
}
}
.mailpoet_range_small {
width: 100px;
}
.mailpoet_range_medium {
width: 180px;
}
.mailpoet_select {
border-color: $color-editor-border-content;
color: $color-primary-text;
margin: 0;
}
.mailpoet_select_large {
width: 139px;
}
.mailpoet_select_medium {
width: 103px;
}
.mailpoet_select_small {
width: 68px;
}
.mailpoet_select_half_width {
width: 50%;
}

View File

@ -1,5 +1,3 @@
@use 'sass:math';
.mailpoet_drop_marker {
background-color: $color-primary;
box-shadow: 0 0 1px 0 $color-primary;
@ -30,7 +28,7 @@
.mailpoet_drop_marker.mailpoet_drop_marker_middle,
.mailpoet_drop_marker.mailpoet_drop_marker_first.mailpoet_drop_marker_after,
.mailpoet_drop_marker.mailpoet_drop_marker_last.mailpoet_drop_marker_before {
margin-top: -1 * math.div($editor-dnd-drop-size, 2);
margin-top: -1 * ($editor-dnd-drop-size / 2);
}
.mailpoet_drop_marker.mailpoet_drop_marker_last.mailpoet_drop_marker_after {

View File

@ -12,18 +12,37 @@
}
}
.edit-post-layout .interface-interface-skeleton__content {
background-color: $color-white;
}
// Fix for fixed bar forms
// This will prevent editor width to grow and push sidebar out of the screen
.interface-interface-skeleton__editor {
max-width: 100%;
}
// 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
// We want to display it in center
.block-editor .block-editor-inserter .block-editor-button-block-appender.block-list-appender__toggle {
margin: 0 auto;
.block-editor-button-block-appender.block-list-appender__toggle {
width: 100%;
svg {
height: 24px;
}
}
// Html blocks contains iframe which captures clicks and in some cases prevents selecting block.
@ -48,14 +67,8 @@ 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 {
// Fix for form padding rendering
.mailpoet-form-background > div > .block-editor-block-list__layout > .block-editor-block-list__block:first-child {
margin-top: 0;
}
@ -83,14 +96,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
@ -110,7 +122,6 @@ h2 {
}
.edit-post-visual-editor {
background-color: $color-white;
padding: 10px;
}

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;
}
}
@ -112,6 +99,7 @@
// Styles for labels and headings for style setting components
// We override some styles from @wordpress/components to have unified labels appearance
.mailpoet-styles-settings .mailpoet-styles-settings-heading,
.mailpoet-styles-settings .components-base-control__label,
.mailpoet-styles-settings .components-input-control__label,
.mailpoet-styles-settings .components-custom-select-control__label,

View File

@ -120,7 +120,3 @@
padding-left: 16px;
}
}
// This style hides the horizontal scrollbar in Firefox browser
.interface-interface-skeleton__sidebar {
overflow-x: hidden;
}

View File

@ -1,5 +1,3 @@
@use 'sass:math';
$mailpoet-form-template-thumbnail-width: 480px;
$mailpoet-form-template-thumbnail-height: 316px;
@ -12,7 +10,7 @@ $mailpoet-form-template-thumbnail-height: 316px;
.mailpoet-templates {
@include formTemplatesGrid;
padding-bottom: math.div($mailpoet-form-template-thumbnail-height, 3);
padding-bottom: $mailpoet-form-template-thumbnail-height / 3;
padding-top: $grid-gap-large;
.mailpoet-categories {
@ -23,12 +21,12 @@ $mailpoet-form-template-thumbnail-height: 316px;
.mailpoet-form-template {
height: $mailpoet-form-template-thumbnail-height + (2 * $grid-gap-large);
padding-bottom: math.div($grid-gap-half, 2);
padding-bottom: ($grid-gap-half / 2);
width: $mailpoet-form-template-thumbnail-width + $grid-gap-half;
.mailpoet-template-thumbnail {
height: $mailpoet-form-template-thumbnail-height;
padding: math.div($grid-gap-half, 2) math.div($grid-gap-half, 2) 0;
padding: ($grid-gap-half / 2) ($grid-gap-half / 2) 0;
}
}

View File

@ -1,9 +1,7 @@
@use 'sass:math';
.mailpoet_browser_preview_toggle {
flex: 0 1 auto;
height: 34px;
padding-bottom: math.div($grid-gap, 2);
padding-bottom: $grid-gap / 2;
text-align: center;
width: 100%;
}

View File

@ -0,0 +1,84 @@
.clearfix {
@include clearfix();
}
.relative-holder {
position: relative;
}
a:focus {
outline: 0 none !important;
}
.nav-tab:focus {
box-shadow: none;
}
.mailpoet_success {
color: #090;
}
.mailpoet_error {
color: #900;
}
.mailpoet_hidden {
display: none;
}
.mailpoet_spaced_block {
margin: 1em 0;
}
.mailpoet_centered {
text-align: center;
}
/* double class is intentional here, we need to be very specific here to
something wrapping our warning message could override its style */
p.sender_email_address_warning.sender_email_address_warning,
p.sender_email_address_warning.sender_email_address_warning a {
align-self: flex-start;
color: #900;
text-align: left;
}
p.sender_email_address_warning:first-child {
margin-top: 1em;
}
.button.mailpoet-button-bigger {
font-size: 1.5em;
height: 46px;
padding: 10px 18px;
}
// Fix for select 2 placeholder padding rendering issue in Chrome
.select2-container .select2-search--inline,
.select2-container .select2-search--inline .select2-search__field {
max-width: 100%;
}
.widefat {
margin-bottom: $grid-gap;
}
.mailpoet-subscribers-in-plan {
font-size: 18px;
margin-bottom: 20px;
.mailpoet-subscribers-in-plan-spacer {
display: inline-block;
width: 20px;
}
.tooltip {
position: relative;
top: -1px;
vertical-align: middle;
}
@include respond-to(small-screen) {
margin-top: 0;
}
}

View File

@ -0,0 +1,221 @@
.mailpoet_form {
margin: 0 0 20px;
}
.mailpoet_form td {
vertical-align: top !important;
}
.select2-container {
max-width: 100%;
width: 25em !important;
}
input.select2-search__field::-webkit-input-placeholder {
color: $color-placeholder-select2;
}
input.select2-search__field:-moz-placeholder {
color: $color-placeholder-select2;
}
input.select2-search__field::-moz-placeholder {
color: $color-placeholder-select2;
}
input.select2-search__field:-ms-input-placeholder {
color: $color-placeholder-select2;
}
.select2-container--default.select2-container--focus .select2-selection--multiple {
border: 1px solid #aaa; /* default Select2 border for single dropdown */
}
textarea.regular-text {
width: 25em !important;
}
@include respond-to(small-screen) {
.select2-container {
width: 100% !important;
}
}
progress {
background-color: $progress-background;
border: 0;
height: 2em;
width: 100%;
}
progress::-webkit-progress-bar {
background-color: $progress-background;
}
progress::-webkit-progress-value {
background-color: $progress-foreground;
border-radius: $progress-border-radius;
}
progress::-moz-progress-bar {
background-color: $progress-foreground;
border-radius: $progress-border-radius;
}
.mailpoet-form-content-around {
margin: 0 auto;
max-width: 976px;
}
.mailpoet-form-grid {
align-items: flex-start;
display: grid;
grid-gap: $grid-gap;
grid-template-columns: $grid-column $grid-column;
justify-content: space-between;
margin: $grid-gap auto;
max-width: 976px;
@include respond-to(small-screen) {
grid-template-columns: 1fr;
}
}
.mailpoet-form-actions {
grid-column: span 2;
p {
color: $color-text;
font-size: $font-size;
margin: $grid-gap 0;
}
.mailpoet-form-send-email & {
grid-column: 2 / -1;
padding-top: $grid-gap + ($heading-font-size-h4 * $heading-line-height) + ($font-size * $line-height * 2);
text-align: right;
}
@include respond-to(small-screen) {
grid-column: 1 !important;
}
}
.mailpoet-form-description {
color: $color-text;
font-size: $font-size;
margin-top: 0;
.mailpoet-h4 + & {
margin-top: -$grid-gap;
}
}
.mailpoet-form-field + .mailpoet-form-field {
margin-top: $grid-gap;
}
.mailpoet-form-field-description {
grid-row: span 2;
}
.mailpoet-form-field-email-header {
border-bottom: 1px solid $color-tertiary-light;
grid-column: 1 / -1;
margin-bottom: $grid-gap-medium;
padding: $grid-gap-large 0 $grid-gap-xl;
}
.mailpoet-form-field-subject,
.mailpoet-form-field-preheader {
background: transparent;
border: 0;
height: auto;
width: 100%;
.mailpoet-form-input-label {
background: #fff;
bottom: 100%;
color: $color-text-light;
display: none;
font-size: 12px;
font-weight: bold;
height: 16px;
left: 4px;
position: absolute;
text-transform: uppercase;
width: 100%;
}
.parsley-errors-list {
left: 4px;
}
input,
textarea {
font-family: $font-family;
padding: 4px;
&:hover,
&:focus,
&:active {
background: rgba($color-tertiary-light, .6);
~ .mailpoet-form-input-label {
display: block;
}
}
}
.mailpoet-form-tooltip-holder {
opacity: 0;
}
&:hover,
&:focus {
.mailpoet-form-tooltip-holder {
opacity: 1;
}
}
}
.mailpoet-form-field-subject {
input {
font-size: $heading-font-size-h1;
font-weight: bold;
line-height: 40px;
}
.mailpoet-form-tooltip-holder {
margin-top: -($grid-gap + 8px) + 2px;
}
}
.mailpoet-form-field-preheader {
textarea {
font-size: 18px;
height: 56px;
line-height: 24px;
}
.mailpoet-form-tooltip-holder {
margin-top: -($grid-gap + 8px) - 9px;
}
}
.mailpoet-form-schedule-time {
color: $color-text;
margin-left: $grid-gap;
vertical-align: middle;
}
.mailpoet-form-field {
.mailpoet-form-error-message {
color: $color-input-error;
font-style: italic;
}
.mailpoet-form-notice-message {
font-style: italic;
}
}

View File

@ -83,7 +83,7 @@ tr {
margin-left: 40px;
}
.mailpoet-clean-list-step-container {
.mailpoet-offer-clearout-step-container {
margin: -$grid-gap 0 !important;
max-width: 42em;

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 {
@ -235,7 +216,7 @@ h1.title.mailpoet-newsletter-listing-heading {
bottom: 10px;
display: flex;
justify-content: center;
margin: 0 !important;
margin: 0;
min-height: 32px;
position: absolute;
right: 10px;
@ -307,7 +288,3 @@ h1.title.mailpoet-newsletter-listing-heading {
margin-top: 5px;
max-width: 150px;
}
.mailpoet-listing-stats-percentages-opens {
font-weight: normal;
}

View File

@ -0,0 +1,474 @@
// Fix for notice being above "Screen options" button
.notice,
.error {
clear: both;
}
.mailpoet-listing {
background: $color-white;
border: 1px solid $color-tertiary-light;
border-radius: 0 4px 4px;
font-family: $font-family;
padding: $grid-gap;
.mailpoet-tab-content & {
background: none;
border: 0;
border-radius: 0;
padding: 0;
}
.mailpoet-categories {
padding-left: $grid-gap-half;
padding-right: $grid-gap-half;
}
a {
color: $color-text;
}
}
.mailpoet-listing-search {
display: inline-block;
}
.mailpoet-listing-filters {
display: inline-block;
margin-left: $grid-gap;
.mailpoet-form-select {
margin-right: $grid-gap;
min-height: 30px;
}
}
.mailpoet-listing-pages {
color: $color-text-light;
float: right;
font-size: $font-size-extra-small;
font-weight: 600;
margin: 0 0 9px;
}
.mailpoet-listing-pages-num {
margin-right: 21px;
}
.mailpoet-listing-pages-links > span,
.mailpoet-listing-pages-links > a {
padding: 0 3px;
}
.mailpoet-listing-pages-first,
.mailpoet-listing-pages-previous,
.mailpoet-listing-pages-next,
.mailpoet-listing-pages-last {
vertical-align: middle;
}
input.mailpoet-listing-current-page {
border: 1px solid $color-tertiary-light;
color: $color-text-light;
font-size: $font-size-extra-small;
margin-right: 8px;
text-align: center;
width: 37px;
}
.mailpoet-listing-loading tbody tr,
.mailpoet_form_loading div.mailpoet-form-grid {
opacity: .2;
}
tr.mailpoet-listing-actions-and-select-all-row td {
background-color: $color-white;
box-shadow: 0 4px 4px -2px rgba($color-tertiary-light, .5) !important;
padding: 0 !important;
}
div.mailpoet-listing-bulk-actions-container {
padding: 0;
}
.mailpoet-listing-bulk-actions {
padding: ($grid-gap / 2) $grid-gap;
a {
color: red;
font-size: $font-size;
font-weight: bold;
line-height: 1.5;
margin-right: 1em;
text-decoration: underline;
white-space: nowrap;
}
}
.mailpoet-listing-select-all {
color: $color-tertiary;
font-size: $font-size-small;
padding: ($grid-gap / 2) $grid-gap;
text-align: right;
a {
color: $color-secondary;
font-weight: 600;
text-decoration: underline;
}
}
.mailpoet-listing-table {
border-spacing: 0;
.mailpoet-listing & {
background: #fff;
border: 0;
border-top: 1px solid $color-tertiary-light;
margin: $grid-gap 0 - $grid-gap;
width: calc(100% + 2 * #{$grid-gap});
}
.mailpoet-listing-no-space & {
border-top: 0;
margin: -$grid-gap;
tbody tr:last-child td {
border-bottom: 0;
}
}
a {
text-decoration: none;
}
th {
font-size: 14px;
line-height: 1.3em;
span {
white-space: nowrap;
}
}
td,
p {
color: $color-text;
font-size: 13px;
line-height: 1.5em;
}
thead th,
thead th a {
color: $color-text-light !important;
font-size: $font-size-extra-small;
font-weight: 600;
letter-spacing: 1px;
line-height: 1.4em;
padding: 12px 10px;
text-transform: uppercase;
}
thead th {
border-bottom: 1px solid $color-tertiary-light;
box-shadow: 0 4px 4px -2px rgba($color-tertiary-light, .5);
text-align: left;
white-space: nowrap;
a {
align-items: center;
display: flex;
}
&.sortable {
padding: 0;
}
&:last-child a {
justify-content: flex-end;
}
&.mailpoet-listing-column-narrow {
@media screen and (max-width: 1400px) {
padding-left: 4px;
padding-right: 4px;
}
}
}
tbody th,
tbody td {
border-bottom: 1px solid $color-tertiary-light;
box-shadow: none;
max-width: 30vw;
padding: $grid-gap-medium $grid-gap-half;
vertical-align: middle;
@include respond-to(small-screen) {
max-width: none;
}
}
thead th.column-primary,
tfoot th.column-primary {
min-width: 25em;
}
th:last-child:not(:only-child),
td:last-child:not(:only-child) {
text-align: right;
}
.column-date {
white-space: nowrap;
}
@include respond-to(small-screen) {
thead th.column-primary,
tfoot th.column-primary {
width: 100% !important;
}
tbody th,
tbody td {
border-bottom: 0;
display: block !important;
padding: 5px 10px !important;
&:before {
display: none !important;
}
&.mailpoet-hide-on-mobile {
display: none !important;
}
}
.column-primary {
float: left !important;
padding: 5px 30px 5px 0 !important;
position: static !important;
}
tr {
border-bottom: 1px solid $color-tertiary-light;
display: block;
padding: 5px 10px 47px;
position: relative;
&:after {
clear: both;
content: '';
display: table;
}
.mailpoet-listing-no-actions-on-mobile & {
padding-bottom: 0;
}
}
}
}
.mailpoet-listing-sorting-arrow {
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%239CA6CC' d='M2 0h8c.552 0 1 .448 1 1 0 .216-.07.427-.2.6l-4 5.333c-.331.442-.958.532-1.4.2-.076-.057-.143-.124-.2-.2L1.2 1.6C.869 1.158.958.531 1.4.2c.173-.13.384-.2.6-.2z'/%3E%3C/svg%3E") no-repeat center;
content: '';
display: none;
height: 8px;
margin-left: 5px;
width: 12px;
.sorted & {
display: block;
}
.asc & {
transform: rotate(180deg);
}
}
.mailpoet-listing-title {
color: $color-text;
font-size: $font-size;
font-weight: 600;
}
a.mailpoet-listing-title {
&:hover,
&:focus {
color: $color-secondary;
}
}
.mailpoet-listing-subtitle {
color: $color-text;
font-size: $font-size-small;
font-weight: normal;
}
.mailpoet-listing-actions-holder {
position: relative;
@include respond-to(small-screen) {
position: static;
}
}
.mailpoet-listing-actions {
align-items: center;
display: none;
flex-wrap: wrap;
left: 0;
line-height: 15px;
position: absolute;
top: 0;
width: 100%;
a {
color: $color-text-light;
text-decoration: none;
&:hover,
&:focus {
color: $color-secondary;
}
}
> span {
align-items: center;
color: $color-text-light;
display: flex;
+ span:before {
content: '';
margin: 0 4px;
}
}
tr:hover & {
display: flex;
}
@include respond-to(small-screen) {
bottom: 10px;
display: flex;
left: 2px;
right: 10px;
top: auto;
width: auto;
a {
align-items: center;
background: $color-secondary-light;
border-radius: 4px;
box-sizing: border-box;
color: $color-secondary;
display: inline-flex;
font-size: $font-size-small;
font-weight: bold;
justify-content: center;
line-height: 20px;
max-width: 100%;
min-height: 32px;
padding: 6px 12px;
position: relative;
text-align: center;
text-decoration: none;
vertical-align: top;
width: 100%;
}
> span {
flex-grow: 1;
max-width: 50%;
&:before {
content: '' !important;
margin: 0 4px;
}
}
}
}
.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 &,
input:checked + {
.mailpoet-form-checkbox-control {
opacity: 1;
}
}
}
.mailpoet-listing-row-inactive {
background: rgba($color-tertiary-light, .2);
}
.mailpoet-listing-row-selected {
background: rgba($color-secondary-light, .6);
.mailpoet-listing-check-column { border-left-color: $color-secondary; }
}
.mailpoet-listing-footer {
background-color: $color-white;
}
.mailpoet-listing-error {
color: #f00;
}
a.mailpoet-listing-error {
color: #f00;
text-decoration: underline;
&:hover,
&:focus {
color: #f00;
text-decoration: none;
}
}
@include respond-to(small-screen) {
.mailpoet-listing {
padding: 0;
}
.mailpoet-listing-header {
display: none;
}
.mailpoet-listing-pages {
float: none;
text-align: center;
}
tr.mailpoet-listing-actions-and-select-all-row {
display: none;
}
.mailpoet-listing-table {
.mailpoet-listing & {
border-top: 0;
margin-bottom: 0;
margin-top: 0;
}
thead,
.mailpoet-listing-check-column {
display: none;
}
}
.mailpoet-listing-footer {
margin: 0 0 - $grid-gap;
padding-top: $grid-gap;
}
}

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

@ -53,8 +53,3 @@
}
}
}
.mailpoet-template-import {
grid-column: 1/-1;
margin: 0 auto;
}

View File

@ -0,0 +1,12 @@
.mailpoet-template-iframe {
left: 0;
max-width: $grid-editor-width;
position: absolute;
top: 0;
width: $grid-editor-width;
z-index: -9999;
}
.mailpoet-schedule-email {
margin-top: 120px;
}

View File

@ -27,6 +27,7 @@
p,
ul {
font-family: $font-family;
font-size: $font-size;
line-height: $line-height;
@ -93,6 +94,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 +199,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 +231,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%;

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