elementor/AGENTS.md
eavichay-elementor 4f52f4f2d7
Internal: CSS to style schema conversion infra [ED-24441] (#36133)
Part of [ED-24401]


[ED-24401]:
https://elementor.atlassian.net/browse/ED-24401?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!--start_gitstream_placeholder-->
###  PR Description
## 1. Problem & Context

Implements CSS-to-atomic conversion infrastructure (ED-24441) to bridge
LLM-generated raw CSS with Elementor's style schema. Replaces style
PropValue system with a server-side CSS parser that converts
declarations to native styles, storing unconvertible rules as
`custom_css`. Defers real telemetry to Phase 4.

## 2. What Changed (Where)

| Component | Purpose |
|-----------|---------|
| **PHP Backend** | `css-converter/` module: parser, registry factory,
REST API endpoint at `POST /elementor/v1/css-to-atomic` |
| **TypeScript Frontend** | `convert-css-to-atomic.ts`: client calling
REST API; integrated into `build-composition` and `configure-element`
tools |
| **Removed** | `STYLE_SCHEMA_URI` and style PropValue schema resources;
`styles-schema` MCP resource; `stylePropertiesToChange` parameter |
| **Updated Prompts** | Docs now describe styling as raw CSS `property:
value` maps instead of PropValue objects |

## 3. How It Works

1. **Ingestion**: LLM provides raw CSS (`color: red; gap: 4px`) via
`style` parameter (build-composition, configure-element)
2. **Conversion**: `convertCssToAtomic()` calls REST endpoint; PHP
parses, blocks malicious patterns (behavior, javascript:, expression()),
routes to registry
3. **Registry Pattern**: `Converter_Registry` iterates converters in
order; first to claim property wins (try-until-success); Phase 1 uses
no-ops, fallback to `customCss`
4. **Result**: Returns split `{ props: {...}, customCss: "..." }`;
unconvertible declarations preserved; exceptions caught and reported to
`Conversion_Failure_Reporter`

## 4. Risks

- **Naive CSS parsing**: splits on `;` and first `:` only—breaks on
values with colons/semicolons (mitigated: acceptable for LLM input per
comments)
- **Security**: blocks hardcoded patterns (behavior, -moz-binding,
javascript:, expression()) but may miss edge cases in untrusted input
- **Phase 1 limitation**: all converters are no-ops; nothing actually
converts until real converters added (intentional per coverage test
design)
- **No telemetry yet**: null reporter swallows failures; real
channel/payload undefined for Phase 4

_Generated by LinearB AI and added by gitStream._
<sub>AI-generated content may contain inaccuracies. Please verify before
using.
💡 **Tip:** You can customize your AI Description using **Guidelines**
[Learn
how](https://docs.gitstream.cm/automation-actions/#describe-changes)</sub>
<!--end_gitstream_placeholder-->

---------

Co-authored-by: Netanel Baba <50736016+Ntnelbaba@users.noreply.github.com>
2026-06-11 13:54:12 +03:00

6.5 KiB
Vendored

Agent and cloud environment guide

Short reference for Cursor Cloud and other non-interactive agents. For full human onboarding use CONTRIBUTING.md and tests/test-environment-setup.md.

Choosing a WordPress environment

Runtime When to use Ports / URL
wp-lite-env (Docker) Same stack as Playwright in CI (.github/workflows/playwright.yml). Full PHP/MySQL containers, two WP instances. http://localhost:8888 and http://localhost:8889
WP Playground CLI (npm run wp-playground) No Docker. WordPress in WASM; quick editor and blueprint-driven setup. Default listen address matches local Playwright dev base URL. http://127.0.0.1:9400
wp-env (npm run wp-env, .wp-env.json) Alternative Docker-based @wordpress/env setup used in other workflows and docs. See @wordpress/env defaults after wp-env start

Use wp-lite-env when you need Docker parity with CI (full Playwright against 8888/8889, setup.sh, theme on disk). Use WP Playground when Docker is missing or broken; it is sufficient for many editor checks and aligns with tests/playwright/playwright.config.ts local localDevServer / localTestServer (both http://127.0.0.1:9400 when not in CI). WP Playground still uses a blueprint (tests/playwright/blueprints/local.json) so PHP/WordPress versions may differ from tests/playwright/.playwright-wp-lite-env.json.

Cursor Cloud specifics

System requirements (typical VM image)

  • Node.js version from .nvmrc (via nvm; PATH in ~/.bashrc)
  • PHP >= 7.4 with extensions: mbstring, xml, zip, curl, dom, bcmath (see composer.json)
  • Composer 2.x
  • Docker only if you use wp-lite-env or wp-env (often needs fuse-overlayfs and iptables-legacy in nested setups)

PATH

The image may ship a system Node under /exec-daemon/node that does not match .nvmrc. If installs or engines fail, confirm which node points at the nvm-managed binary.

Common commands

Action Command
Install deps npm ci --ignore-scripts && composer install
Build packages npm run build:packages
Build styles npx grunt styles
Build scripts npx grunt scripts
Full dev watch npm run watch
Lint JS/TS (root) npx eslint .
Lint JS/TS (packages) cd packages && npx eslint . --report-unused-disable-directives-severity error
Lint PHP vendor/bin/phpcs --extensions=php --standard=./ruleset.xml .
Jest (main) npm run test:jest
Jest (packages) npm run test:packages
All Jest npm run test
Fast DB-less PHPUnit (single/few files) tests/phpunit/run-unit.sh <test-file.php> [<test-file.php> ...] [--filter <pattern>]

Fast DB-less PHPUnit for local dev

tests/phpunit/run-unit.sh runs a small set of PHPUnit files without WordPress or MySQL for a quick inner loop. It uses tests/phpunit/unit-bootstrap.php, which only defines ABSPATH and registers an Elementor\ autoloader (same name->path transform as includes/autoloader.php), and ignores the project phpunit.xml. Pass any number of test-*.php files (added to a generated testsuite, which sidesteps PHPUnit's test-*.phpTest_* filename/classname assumption) plus optional pass-through args like --filter.

tests/phpunit/run-unit.sh tests/phpunit/elementor/modules/atomic-widgets/css-converter/test-css-converter.php
tests/phpunit/run-unit.sh tests/phpunit/.../test-css-converter.php --filter test_convert

Only works for tests whose subjects don't touch WordPress at load/run time. Tests needing WordPress/MySQL (e.g. REST endpoints with act_as_admin/WP_REST_Server, or anything pulling Style_Schema) must use the full suite (npm run test:setup:playwright env, or the wp-lite-env setup below).

wp-lite-env (Docker): full setup

Non-interactive one-shot (skips container cleanup prompt):

SKIP_CONFIRMATION=true npm run env:setup

That script installs deps, builds, downloads Hello Elementor, runs npm run start-local-server (8888 and 8889), then npm run test:setup:playwright. Do not start only 8888 and then run npm run test:setup:playwright alone; package.json expects both ports.

Manual equivalent: see tests/test-environment-setup.md (steps: npm run start-local-server then npm run test:setup:playwright).

If Docker is not running on the VM yet, a typical pattern is sudo dockerd &>/tmp/dockerd.log & in the background, then ensure the Docker socket is usable for the agent user (for example sudo chmod 666 /var/run/docker.sock in disposable environments only). For a manual plugin tree under ./build/ without the setup script, flows often use composer install --no-scripts --no-dev && composer dump-autoload && npx grunt copy, then npm run setup-templates, then start both wp-lite-env instances (see npm run start-local-server in package.json).

Admin: http://localhost:8888/wp-admin/ — user admin, password password (see test environment doc).

WP Playground CLI (no Docker)

After npm ci (or full install per repo):

npm run wp-playground

Wait until the CLI prints that WordPress is running, then open http://127.0.0.1:9400 . This flow was smoke-tested with the same CLI flags as package.json wp-playground in a clean agent-style environment without Docker.

For CI-style mounted build output use npm run wp-playground:ci (expects ./build).

Gotchas

  • npm run lint runs ESLint at the repo root and in the elementor-packages workspace (npm run lint -w elementor-packages); both must pass.
  • PHPCS may report warnings without errors on the current tree; treat policy from maintainers, not only the exit summary.
  • composer install post-install can run php-scoper (Twig prefixing); dev dependency humbug/php-scoper must be present for a full dev install.
  • For a production-like plugin tree under ./build, many flows use composer install --no-scripts --no-dev first, then npx grunt copy. Dev dependencies must be restored afterward with composer install.
  • package.json engines and .nvmrc define the Node version; keep them aligned when troubleshooting.
  • Husky pre-commit runs lint-staged with NODE_OPTIONS=--max-old-space-size=8192 (see .husky/pre-commit).