We use DateTime component on the send page.
The DateTime component uses DateText for picking date.
We add site's offset before we pass the date to the DateTime.
The date-text component is nested in the DateTime and was also applying
offset on the date.
The second issue was we needed to convert the value to JS Date.
The MailPoet.Date.toDate expects the value to be in UTC, and we provided an already converted date.
So for offset -07:00
MailPoet.Date.toDate('2023-09-01');
ends up
Thu Aug 31 2023 17:00:00 GMT-0700 (Pacific Daylight Time) and calendar display's incorrect value.
This commit fixes it so that we don't touch offset in the DateText component.
[MAILPOET-6197]
In the renderer we only display the border if both
colour and size are set. Before this commit in the
editor we showed the border even if the colour
was transparent. This make it consistent and display
the border in the editor same way as in the renderer
[MAILPOET-6193]
pnpm dedupe upated Typescript.
The update of Typescript is more complex. We also need to update the eslint
because there is a warning that TS version is not supported and
eslint-config-airbnb-typescript was abandoned so we need to remove it and
do some changes in eslint config for TS
[MAILPOET-6191]
The package is a subdependency of @wordpress/scripts
I tried pnpm update axios but it didn't work.
I removed @wordpress/scripts and installed the same version again
and it updated the axios.
[MAILPOET-6191]
I update pnpm because the required version is quite old and
some devs are using newer version anyways and mixing versions
causes strange changelogs in package-lock.yml
I ran corepack up but I removed the sha from the version
because the previous version didn't have it as well.
[MAILPOET-6191]
There is no use case for the methods without the translation to site's timezone.
When the input doesn't specify the timezone we treat it as utc.
When the input provides timezone (e.g. '2024-08-13 10:00+02:00' or new Date('2024-08-13 10:00+02:00'))
We respect the timezone of the input and print the result in the site's timezone.
When the site's timezone is set +01:00
'2024-08-13 10:00' prints as 2024-08-13 11:00
'2024-08-13 10:00:+02:00' prints as 2024-08-13 09:00
new Date('2024-08-13 10:00:+02:00') prints as 2024-08-13 09:00
new Date('2024-08-13 10:00:+00:00') prints as 2024-08-13 11:00
[MAILPOET-6142]
I looked into using DBAL events for this but found that DBAL events
are deprecated so I went with middleware as they are recommended
as a replacement for the DBAL events.
[MAILPOET-6142]
This is no longer used. It was used in just a couple of places
and was fixing a difference between PHP time zone and browser time.
We rely on WordPress to set PHP timezone to UTC and we use the site's
timezone on the client so the fix is no longer useful.
[MAILPOET-6142]
The user picks time in a select box, and we expect they pick a time
in the site's timezone so the saved cron expression is in the site's timezone.
When we calculate the next run date, we do it in the site's timezone and
to get UTC time, we convert it.
[MAILPOET-6142]
The time adjustments are not necessary because we rely on WP setting
timezone to UTC.
Manipulation in adjustTimezone difference was causing us to display GMT time.
[MAILPOET-6142]
$this->wp->currentTime('timestamp') adds 'gmt_offset' value.
This was needed with PDO connection because the connection
used @session.time_zone set to the same offset value.
[MAILPOET-6142]
Theoretically, we may end up running the delete query with a condition like
WHERE wp_user_id IN (null, null);
This is a tiny optimization to skip null IDs to avoid running such a query.
[MAILPOET-6142]
The test was using an empty entity which was not presisted. This may
potentially cause issues as in some places, an entity with a proper type might be expected.
It was already causing that an SQL query ran with WHERE type = null condition which is always false.
[MAILPOET-6142]
The conversion is done by MailPoetVendor\Doctrine\DBAL\Driver\API\MySQL\ExceptionConverter
that is returned from MailPoetVendor\Doctrine\DBAL\Driver\AbstractMySQLDriver.
[MAILPOET-6142]
We had the fix in the renderer, but we do use pQuery also in further processing of the rendered email
e.g. in code where we add GA tracking params to links.
In this commit, I moved the fix directly to the pQuery library so that it is safe to use
later in email code processing.
[MAILPOET-6190]
DB may crash when deleting too many rows in one query.
The scheduled_task_subscribers has the potential to contain many records.
This commit adds limit when cleaning up inconsistent data from scheduled task subscribers.
[MAILPOET-6155]
Using now "cached" on the TimestampListener instance was causing us to set createdAt and updatedAt slightly in the past.
It was potentially problematic in tests where the TimestampListener lives a long time or in long requests, such as a cron request.
[MAILPOET-6155]
This is a performance optimization to avoid fetching too many scheduled task rows.
Run is always created before the scheduled task which is created in send action step.
[MAILPOET-6155]
It is possible that one email (e.g., purchase in category) is sent multiple times
to the same subscriber.
AutomationEmailScheduler::getScheduledTaskSubscriber was selecting the task based on subscriber and newsletter.
In the case of multiple emails sent to one subscriber, the method failed to pick ScheduledTaskSubsrciberEntity because
the query was fetching multiple results, but getOneOrNullResult expects only one result.
This commit fixes it by adding additional filtering by $runId to get the ScheduledTaskSubsriberEntity associated
with the correct run.
I did the filtering in PHP because an alternative would be using LIKE %% in the query. The meta column is text.
[MAILPOET-6155]
This reduces the size of the files combined from 224KB to 64KB.
The command used was:
for f in originals/*.mp3; do ffmpeg -i "$f" -c:a libmp3lame -af "highpass=f=200, lowpass=f=15000, afftdn=nf=-30, anlmdn=s=1, rubberband=pitch=1.05, volume=1.5" -b:a 8k -ac 1 -ar 8000 "${f##*/}"; done
[MAILPOET-6038]
Previously, a new CAPTCHA phrase was generated when the CAPTCHA image
or audio was requested "again". For that, a counter needed to be stored in the
session, and since image and audio were fetched in parallel, any of them could
initialize the new CAPTCHA phrase. The problem appeared when they both
generated a new phrase at the same time. This resulted in a race condition,
where the image and audio had different CAPTCHA phrases and some users
weren't able to pass the CAPTCHA at all. This was occuring especially in Safari,
(maybe somehow due the type dectection range "preflight" request).
Now, the phrase is initialized on the CAPTCHA page load (and reloaded via AJAX),
so we don't need to store any additional metadata, apart from the phrase itself.
[MAILPOET-6038]x
Some styles newly applied for the Woo Content blocks might
make the blocks look broken (e.g., too big font applied on the order items table).
This commit adds a check for existing emails, and for sites with existing customized the Woo email template
they are not applied unless a user saves the email in the editor.
[MAILPOET-4180]
In the Woo email customizer, we have only one font family.
The newsletter data carry different default font families for headings.
In this commit, we enforce that the renderer uses the same font family
for text and headings.
This only applies to the part of the email that is handled by the MailPoet renderer.
The part that comes from the Woo itself is handled differently.
See previous commits.
I used clone to make sure we don't accidentally save the settings.
It wouldn't probably cause any damage because we don't expose these settings to users, but to be safe.
[MAILPOET-4180]
Woo has a stylesheet that is later inlined into the email content by Emogrifier.
In this commit I replace all font family declarations by the font family set
in the Woo customizer.
[MAILPOET-4180]
The font size was not applied at all, but Woo content comes with inlined font-family
styles so we need to use !important to override it.
[MAILPOET-4180]
The previous assumption was, that a Delay action is not in mailpoet_automation_run_log database, and had to be calculated. But this was a wrong assumption, and since the action is there, we don't have to calculate it.
[PREMIUM-280]
I found that we already have a logic for determining whether to show
Woo segment. It also covers case when there are Woo customers in the DB
but Woo plugin is not active.
This logic is used in segments listing API. I reused it also for fetching
lists on the newsletters page.
[MAILPOET-5224]
In new interact.js versions, you can no longer assign a clone to the element (it's read only). This is a workaround without doing a major refactor.
[MAILPOET-6109]
We complete the actions in the database. However, we don't delete
the batch processes. Woo thinks those crashed. It tries to log an
error, but it doens't have suficient rights for that.
Previously we used useHistory which wasn't throwing errors in case
it was used outside of router. It just returned undefined.
The undefined was causing errors being logged in console on admin pages
where we don't define onClick explicitly and where we don't use router.
useNavigate throws an error if it is not inside the router. In this commit, I added
handling of the error and default fallback that redirects to the homepage in cases where there is no router.
[MAILPOET-3911]
This component seems to be a leftover after we removed automatic email.
It uses this.prop.history.push which is no longer available.
I was not able to find any usage of this component in the free or premium
plugin.
[MAILPOET-3911]
st.deletedAt line was ignored, because the "->where" on the next line replaced it. Resulting query was also wrongy built because of mixing of OR and AND conditions.
[MAILPOET-5755]
The abandoned cart automation allows for transactional abandoned carts. Therefore we should not check for the subscriber status when initalizing the abandoned cart mechanism
[MAILPOET-6115]
Using inject-loader requires first transpiling modules to CommonJS. Previously,
we were doing this via parametrized imports, but these are no longer supported.
Instead, we can fix this by using CommonJS preset in Webpack config.
[MAILPOET-5491]
This fixes an error with the following:
1. CurrencyFactory patch
```js
import { CurrencyFactory } from '@woocommerce/currency';
```
instead of
```js
import CurrencyFactory from '@woocommerce/currency';
```
2. Error with TextComponent from `@wordpress/components`
Fixed with pnpm patch
MAILPOET-5121
By providing this option value 'gpl' we declare our intention
to use TinyMCE under GPLv2+ license.
Our plugin uses the GPL so we are fine.
[MAILOPET-5988]
We previously were looking for search term on the Newsletter table subject column. Unfortunately, post-notification and its history items sometimes contain both static text and dynamic text i.e., MailPoet shortcodes. This prevented the search from returning any useful results.
The RenderedSubject on the Sending queues table includes both the static text and dynamic text, so we can look for the search term on it
MAILPOET-6072
Previously this module was mocked as an empty module, but
after updating @woocommerce/currency we need to provide at
least getSetting function.
The function is called only once with the parameter 'currency'.
I tried installing the full @woocommerce/settings, but it requires
complex initialization (e.g. passing some data from PHP). I find it
better to provide this simple mock and throw an error if it is used more than expected.
[MAILPOET-6008]
I couldn't make it work with the Babel loader. There is a possible
solution using ts-node as a loader. I didn't want to install another
package, so I chose a different workaround.
mocha-env.mjs is processed as a module thanks to the suffix, and it
sets chai. expect globally, and then I updated tests to use the global expect.
Please see https://github.com/chaijs/chai/issues/1568
[MAILPOET-6008]
After 3.0.0 the date-fn's package.json contains 'exports' propperty
which prevents us from including the buildLocalizeFn function via direct import form it's file.
Because everything that is not listed in 'exports' throws ModuleNotFound error.
[MAILPOET-6008]
Without this configuration, the block editor uses a fallback value
which is always a new array and causes a shallow check to mark it as a new value
and was causing
"The 'useSelect' hook returns different values when called with the same state and parameters"
warning and rerenders of the blocks panel.
[MAILPOET-6054]
The ref is needed to prevent an error triggered when inserting a block
from the inserter sidebar.
The error was not causing a visible issues but was logged in console and causing acceptance
test to fail.
[MAILPOET-6054]
This commit addresses two issues:
1) Newly added paragraph and heading blocks have instance RichTextData
instead of a plain string as a content attribute. To address that I added .toString().
2) I experienced that blocks passed via onChange or onInput callbacks might not contain
the latest RichTextData for headings and paragraphs (for example last couple of letters was missing).
This was causing an issue when the user saved immediately after finishing editing (was caught by a test).
I fixed that by using the blocks directly from the block editor store for saving.
At the same time, I removed the onInput callback. The reasoning here is that currently, we use the blocks in our store
as a backup state, which is used to restore accidentally deleted required blocks.
So triggering the reducer and validation for both callbacks was a bit overkill.
[MAILPOET-6054]
We can't update to latest @wordpress/dependency-extraction-webpack-plugin
and latest @wordpress/scripts (at the time of committing 28.0.0) because
a BC issue is causing it doesn't work for WP lower than 6.6.
See https://github.com/WordPress/gutenberg/issues/62202#issuecomment-2149165189
[MAILPOET-6054]
The code was commented because it was breaking the build after dependencies update.
The functionality is now directly included in the block editor
so we can safely remove the code.
See https://github.com/WordPress/gutenberg/pull/62086
[MAILPOET-6054]
The MoreMenuDropDown was removed from @wordpress/interface.
This commit replaces it with a generic DropdownMenu to make the build passing.
It will need further adjustments.
[MAILPOET-6054]
We prefixed iconType with URL protocol, which caused the changing iconType to stop working. I added a new function that helps make the difference between iconType and URLs.
[MAILPOET-6106]
This is because we call `getItems()` in a few places already and this `notices.apiError` causes a render which causes `getItems()` to re-render, and so on.
MAILPOET-6022
For non-campaign emails, we use scheduled tasks to display processed stats.
The invalid tasks are no longer processed, and they don't block the queue
and are not counted in the stats.
For campaign emails (bulk emails), we just mark them as sent to zero recipients.
[MAILPOET-5881]
The batch will be continued anyway because of the next condition
if (!$queue->getCountToProcess()) {
continue;
}
The newsletter entity will be marked as sent (plus other stuff related to finished sending)
after the loop in $this->endSending.
In all other cases when we pause sending, we immediately end
the processSending method. In this case, we would unnecessarily
start processing one more batch.
[MAILPOET-5881]
wordpress_image_version:6.1.1-php7.4 # We use image with PHP 7.4 and install required WordPress version via CLI# We use image with PHP 7.4 and install required WordPress version via CLI
There is a `./do` command that helps with the development process. See README.md for more details.
There is a `./do` command that helps with the development process. See [README](README.md) for more details.
## PHP Code
- Two spaces indentation.
- Space between keyword (if, for, switch...) and left bracket
- CamelCase for classes.
- camelCase for methods.
- snake_case for variables and class properties.
- Space between keyword and left bracket (`if ()`, `for ()`, `switch ()`...).
-`CamelCase` for classes.
-`camelCase` for methods.
-`snake_case` for variables and class properties.
- Composition over Inheritance.
- Comments are a code smell. If you need to use a comment - see if same idea can be achieved by more clearly expressing code.
- Require other classes with 'use' at the beginning of the class file.
- Do not specify 'public' if method is public, it's implicit.
- Require other classes with `use` at the beginning of the class file.
- Always use guard clauses.
- Ensure compatibility with PHP 7.1 and newer versions.
- Ensure compatibility with PHP 7.4 and newer versions.
- 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.
-`kebab-case` for file names.
- Components files are prefixed with underscore, to indicate, that they aren't compiled separately (`_new-component.scss`).
## 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
- Default to TypeScript for new 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:
-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 doesn’t require an explanation
-For PHP we do the same with the exception `// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps` which for now doesn’t require an explanation
## Git flow
- Do not commit to trunk.
- Open a short-living feature branch.
-Open a pull request.
- Add Jira issue reference in the title of the Pull Request.
- Work on the pull request.
-Use good commit messages as explained here https://chris.beams.io/posts/git-commit. Include Jira ticket in the commit message.
- Use the `./do qa` command to check your code style before pushing.
-Use good commit messages as explained here https://chris.beams.io/posts/git-commit
-Create a pull request when finished. Include Jira ticket in the title of the pull request.
- 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).
## Feature flags
We use feature flags to control the visibility of new features. This allows us to work on new features in smaller chunks before they are released to all customers.
- Feature flags can be enabled on the experimental page: wp-admin/admin.php?page=mailpoet-experimental
- New feature flags can be added in the class `FeaturesController`
- Feature flags can be enabled on the experimental page: `/admin.php?page=mailpoet-experimental`.
- New feature flags can be added in the class `FeaturesController`.
@ -7,16 +26,16 @@ If you have **any questions or need help or support**, please see the [Support](
To use our Docker-based development environment (recommended), continue with the steps below.
If you'd like to use the plugin code directly, see details in [the plugin's readme](mailpoet/README.md).
## 🔌 Initial setup
## Initial setup
1. Run `./do setup` to pull everything and install necessary dependencies.
2. Add secrets to `.env` files in `mailpoet` and `mailpoet-premium` directories. Go to the Secret Store and look for "MailPoet: plugin .env"
3. Run `./do start` to start the stack.
4. Go to http://localhost:8888 to see the dashboard of the dev environment.
## ✅ Additional dependencies
### Additional dependencies
Even though it possible to run everything using Docker, in the development workflow,
Even though it's 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:
@ -24,7 +43,9 @@ the following tools are recommended:
2.**Node.js**, as specified by `.nvmrc`. For automatic management use [nvm](https://github.com/nvm-sh/nvm), [FNM](https://github.com/Schniz/fnm), or [Volta](https://github.com/volta-cli/volta).
3.**pnpm**, as specified in `package.json`. For automatic setup enable [Corepack](https://nodejs.org/docs/latest-v17.x/api/corepack.html) using `corepack enable`.
## 🔍 PHPStorm setup for XDebug
## Xdebug
### PhpStorm setup
In `Languages & Preferences > PHP > Servers` set path mappings:
@ -41,7 +62,7 @@ To use XDebug inside the **cron**, you need to pass a URL argument `&XDEBUG_TRIG
[in the cron request](https://github.com/mailpoet/mailpoet/blob/bf7bd6d2d9090ed6ec7b8b575bb7d6b08e663a52/lib/Cron/CronHelper.php#L155-L166).
Alternatively, you can add `XDEBUG_TRIGGER: yes` to the `wordpress` service in `docker-compose.yml` and restart it (which will run XDebug also for all other requests).
## Xdebug develop mode
### Xdebug develop mode
[Xdebug develop mode](https://xdebug.org/docs/develop) is disabled by default because it causes performance issues due to conflicts with the DI container.
@ -52,7 +73,7 @@ environment:
XDEBUG_MODE: debug, develop
```
## Xdebug for integration tests
### Xdebug for integration tests
- In Languages & Preferences > PHP > Servers create a new sever named `MailPoetTest`, set the host to `localhost` and port to `80` and set following path mappings:
- Add `XDEBUG_TRIGGER: 1` environment to `mailpoet/tests/docker/docker-compose.yml` -> codeception service to start triggering Xdebug
- Add `XDEBUG_TRIGGER: 1` environment to `tests_env/docker/docker-compose.yml` -> codeception service to start triggering Xdebug
- Make PHPStorm listen to connections by clicking on the phone icon
## 💾 NFS volume sharing for Mac
## Local development
### NFS volume sharing for Mac
NFS volumes can bring more stability and performance on Docker for Mac. To setup NFS volume sharing run:
@ -87,7 +110,7 @@ docker-compose up -d
**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/).
# 🐶 Husky
### Husky hooks
We use [Husky](https://github.com/typicode/husky) to run automated checks in pre-commit hooks.
@ -102,7 +125,9 @@ export NVM_DIR="$HOME/.nvm"
Without it, you may experience errors in some Git clients.
## 🕹 Commands
## Docker
### Commands
The `./do` script define aliases for most of the commands you will need while working on plugins:
@ -124,11 +149,7 @@ Options:
You can access this help in your command line running `./do` without parameters.
## ✉️ Adding new templates to the plugin
[Read the article.](https://mailpoet.atlassian.net/wiki/spaces/MAILPOET/pages/629374977/Adding+new+templates+to+the+plugin)
## 🚥 Testing with different PHP versions
### Available PHP versions
To switch the environment to a different PHP version:
@ -148,7 +169,7 @@ To switch the environment to a different PHP version:
To switch back to the default PHP version remove what was added in 2) 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`.
## Disabling the Tracy panel
### Disabling the Tracy panel
To disable the Tracy panel, add the following to `docker-compose.override.yml`:
@ -159,6 +180,39 @@ services:
MAILPOET_DISABLE_TRACY_PANEL: 1
```
## ✅ TODO
### Running individual tests
- install woo commerce, members and other useful plugins by default
It's recommended to run tests in Docker. Free plugin tests can be run using --test flag (`./do --test`). However, to run a premium test, you need to ssh into test container (`./do ssh --test`) and run tests there.
The argument `$subscriber` is similar to [Add Subscriber](AddSubscriber.md) method, but the subscriber is updated instead of created.
It returns the updated subscriber. See [Get Subscriber](GetSubscriber.md) for a subscriber data structure.
If the subscriber is a WordPress user, the method does not allow updating `email`, `first_name` and `last_name`. It needs to be updated in the `wp_users` and MailPoet will synchronise the new values.
3. [Frameworks and libraries](#frameworks-and-libraries)
3. [Workflow Commands](#workflow-commands)
4. [Coding and Testing](#coding-and-testing)
1. [DI](#di)
2. [PHP-Scoper](#php-scoper)
3. [i18n](#i18n)
4. [Acceptance testing](#acceptance-testing)
If you have **any questions or need help or support**, please see the [Support](../SUPPORT.md) document.
## MailPoet
To use the official Docker-based development environment, see details
in [the readme file](../README.md) in the root of this repository. If
you'd like to use the plugin code directly, you can follow the instructions
below.
## Contents
- [Setup](#setup)
- [Frameworks and libraries](#frameworks-and-libraries)
- [Workflow Commands](#workflow-commands)
- [Coding and Testing](#coding-and-testing)
- For help with product, visit [SUPPORT](../SUPPORT.md).
- To use the Docker-based development environment, see [monorepo README](../README.md).
- To use plugin code directly, follow instructions below.
## Setup
### Requirements
- PHP >= 7.3 (only for the development environment, to run the plugin PHP >= 7.2 is required)
- PHP >= 7.4
- NodeJS
- WordPress
@ -48,9 +50,8 @@ cp .env.sample .env
./do compile:all
```
## Frameworks and libraries
### Frameworks and libraries
- [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.
$ ./do generate:data [<generatorName>][<threads>]# Generates random usage data (Note: requires WooCommerce active) e.g. ./do generate:data past_revenues 4
```
## Storybook
We use [Storybook.js](https://storybook.js.org/) to showcase our React components, which can be used throughout the plugin.
### 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
```
To build the static version, which can be accessed via browser, run
```bash
./do storybook:build
```
which will create a `storybook-static` folder with all necessary files. Don't forget to rebuild it when new components are added.
### Building new components
- 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
@ -169,9 +142,23 @@ Dependencies handled by PHP-Scoper are configured in extra configuration files `
### i18n
We use functions `__()`, `_n()`, `_x()`, and `_nx()` with domain `mailpoet` to translate strings.
We use functions `__()`, `_n()`, `_x()`, and `_nx()` with domain `mailpoet` to translate strings. Please follow [best practices](https://codex.wordpress.org/I18n_for_WordPress_Developers).
**in PHP code**
#### Comments for translators
When the translation string can be ambiguous, add [a translators comment](https://codex.wordpress.org/I18n_for_WordPress_Developers#Descriptions) for clarification. Don't use `_x()` or `_xn()` for clarification.
```php
// translators:
$customErrorMessage=sprintf(
// translators: %1$s is the link, %2$s is the error message.
__('Please see %1$s for more information. %2$s.','mailpoet'),
'https://kb.mailpoet.com',
$errorMessage
);
```
#### In PHP code
```php
__('text to translate','mailpoet');
@ -180,7 +167,7 @@ _x('text to translate', 'context', 'mailpoet');
@import'../../../node_modules/@wordpress/block-editor/build-style/style';// for inserter styles
@import'settings/colors';
// automation components
@import'./components-automation/badges';
@import'./components-automation/statistics';
// automation editor
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.