diff --git a/.cursor/rules/cloudinary.mdc b/.cursor/rules/cloudinary.mdc new file mode 100644 index 00000000..ca3f195b --- /dev/null +++ b/.cursor/rules/cloudinary.mdc @@ -0,0 +1,14 @@ +--- +description: Cloudinary WordPress plugin — canonical agent conventions +alwaysApply: true +--- + +Follow [`AGENTS.md`](../../AGENTS.md) at the repo root for all build/test/lint, distribution, hooks, and conventions. + +This is the official Cloudinary plugin for WordPress/WooCommerce — a site plugin installed from the WordPress.org directory, not a code SDK. It does not wrap or require `cloudinary_php`. + +Non-negotiables: +- Edit `src/`; never hand-edit the compiled `js/` and `css/` (webpack builds them via `npm run build`). +- Build toolchain is Node >=22 / npm >=10 (per `.nvmrc` and `engines`) — ignore any "Node 16" reference. +- `STABLETAG` in `cloudinary.php`/`readme.txt` is a build-time version placeholder — do not hardcode a version. +- PHP must pass `composer lint` (WordPress + VIP standards) and target PHP 7.4+. License GPL-2.0. Branch/PR against `master`. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..39e4c6cd --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,10 @@ +# Copilot instructions — cloudinary_wordpress + +This is the official Cloudinary plugin for WordPress/WooCommerce (a site plugin installed from the WordPress.org directory, not a code SDK). + +**See [`AGENTS.md`](../AGENTS.md) at the repo root for the canonical instructions** — distribution/versions, contributor setup (Node >=22, `npm install`, `npm run build`, wp-env for e2e), build/test/lint commands, developer hooks, and conventions. + +Key reminders: +- Edit `src/` — never the compiled `js/` and `css/` (built by webpack via `npm run build`). +- `STABLETAG` in `cloudinary.php`/`readme.txt` is a build-time version placeholder — don't hardcode a version. +- PHP must pass `composer lint` (WordPress + VIP standards) and run on PHP 7.4+. License is GPL-2.0. PR against `master`. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..fe153727 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,88 @@ +# AGENTS.md — cloudinary_wordpress + +## What this is (one line) +The official Cloudinary plugin for WordPress/WooCommerce: it syncs the WordPress media library to Cloudinary and rewrites front-end image/video URLs to be optimized and CDN-delivered. It is a **site plugin**, configured in `wp-admin`, not a code SDK. + +## When to use / when NOT to use +- **Use this when:** the target is a **WordPress or WooCommerce site** that should optimize and deliver media through Cloudinary. Installed by end users from the **WordPress.org plugin directory**; connected with a `cloudinary://:@` string in the admin UI. No application code needed for basic use. +- **Do NOT use this when:** you're building a **custom PHP application** and want to call Cloudinary in code — use [`cloudinary_php`](https://github.com/cloudinary/cloudinary_php). This plugin does **not** wrap or require the PHP SDK; it builds delivery URLs and calls the Cloudinary API itself (only runtime PHP dep is `ext-json`). +- **Siblings:** other platform integrations are `cloudinary_magento2`, `cloudinary_sap_commerce`, `cloudinary_sfcc_site_cartridge`, `cloudinary_commercetools`. For an agent/no-code path see [Cloudinary MCP servers](https://github.com/cloudinary/mcp-servers). + +## Distribution & versions +- **Distribution channel:** WordPress.org plugin directory. Slug: `cloudinary-image-management-and-manipulation-in-the-cloud-cdn`. **Not** published to Composer/Packagist for site use. +- **Current version:** 3.3.4 (source of truth: `.version` and `package.json`). In `cloudinary.php` and `readme.txt` the version reads `STABLETAG` — that's a **build-time placeholder** replaced at release. Do not hand-set it. +- **Runtime requirements:** WordPress 5.6+ (tested to 7.0), PHP 7.4+. `cloudinary.php` guards on `version_compare(phpversion(),'7.4','>=')` before loading. + +## Setup for contributors +This is a WordPress plugin built with `@wordpress/scripts` (webpack). **Build toolchain needs Node >=22 and npm >=10** (`.nvmrc` = 22, `engines.node` = ">=22", CI uses Node 22 — the old README's "Node v16" is stale). + +```bash +nvm use # Node 22 (per .nvmrc) +npm install # installs JS deps; postinstall runs `composer install` for PHP tooling +npm run build # compile src/ -> js/ and css/ via wp-scripts (webpack) +npm run dev # wp-scripts start (watch mode) +``` + +For end-to-end tests, the repo uses `@wordpress/env` (Docker): +```bash +npm run env:start # boots WordPress at http://localhost:8888 (wp-env, needs Docker) +npm run env:stop +``` + +## Minimal developer hook example +Extension is via WordPress filters/actions from a theme/plugin, not by editing this repo. Verified hook: +```php +// Add a global transformation to every delivered image (php/class-media.php:994). +add_filter( 'cloudinary_transformations', function ( $transformations, $attachment_id ) { + $transformations[] = array( 'effect' => 'sharpen:80' ); + return $transformations; +}, 10, 2 ); +``` +Other verified hooks: `cloudinary_is_media` (`php/class-media.php:331`), `cloudinary_can_sync_asset` (`php/class-sync.php:339`), `cloudinary_is_deliverable` (`php/class-delivery.php:419`), action `cloudinary_register_sync_types` (`php/class-sync.php:679`), action `cloudinary_init_delivery` (`php/class-delivery.php:850`). Full list: . + +WP-CLI (registered in `instance.php` as the `cloudinary` namespace): `wp cloudinary sync` (`php/traits/trait-cli.php:144`), `wp cloudinary analyze` (`php/traits/trait-cli.php:202`). + +## Build / test / lint (from CI: .github/workflows/ci.yml) +```bash +npm ci # clean install (CI) +npm run lint # runs lint:php (phpcs), lint:js (wp-scripts), lint:style +npm run build # webpack production build + +# End-to-end (Playwright on wp-env, Docker required): +npx playwright install --with-deps chromium +npm run build +npm run env:start +npm run test:e2e # playwright test --config tests/e2e/playwright.config.js +npm run env:stop + +# Single e2e test file: +npx playwright test tests/e2e/.spec.js --config tests/e2e/playwright.config.js + +# PHP-only lint / auto-fix (Composer scripts): +composer lint # phpcs (WordPress/VIP coding standards) +composer fix # phpcbf +``` +CI matrix: PHP **7.4 and 8.3**, Node **22**. The `build` job runs `npm ci` → `npm run lint` → `npm run build`; the `e2e` job builds, boots wp-env, and runs Playwright (needs the `CLOUDINARY_E2E_URL` secret for live-cloud e2e). + +## Conventions & gotchas +- **Edit `src/`, not the compiled output.** JS/CSS in `js/` and `css/` are built from `src/` by webpack — never hand-edit the compiled files; run `npm run build`. +- **`STABLETAG` is a build-time placeholder** for the version in `cloudinary.php` and `readme.txt` (replaced by grunt-text-replace / release-it at release). Don't hardcode a version there. +- PHP lives in namespaced `Cloudinary\` classes under `php/`; bootstrap is `cloudinary.php` → `instance.php` → `new Cloudinary\Plugin()`. +- PHP must pass **WordPress + VIP coding standards** (phpcs via `composer lint`) and stay compatible with **PHP 7.4**. +- Release tooling (Grunt `grunt-wp-deploy` to the WP.org SVN, `release-it`) is maintainer-only — don't run `npm run deploy`. +- **License: GPL-2.0** — keep new files GPL-compatible. +- **`npm run readme` is currently broken** (aliases a `composer readme` script that isn't defined). Don't rely on it. + +## Canonical docs +- WordPress integration guide: https://cloudinary.com/documentation/wordpress_integration +- Developer hooks (actions & filters): https://cloudinary.com/documentation/wordpress_developers#actions_and_filters +- Plugin listing: https://wordpress.org/plugins/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/ +- Transformation & API references: https://cloudinary.com/documentation/cloudinary_references + +## Agent / MCP note +For autonomous Cloudinary operations outside WordPress, prefer the [Cloudinary MCP servers](https://github.com/cloudinary/mcp-servers). Use this repo for changes to the WordPress plugin itself. + +## Commit / PR conventions +- Branch off and PR against `master`. Keep the CI matrix green (PHP 7.4 & 8.3, Node 22). +- Run `npm run lint` and `npm run build` before pushing; add/adjust Playwright e2e coverage for behavior changes. +- Edit `src/`; never commit hand-edited `js/`/`css/` build output or a hardcoded version in place of `STABLETAG`. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..14c5a466 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,50 @@ +@AGENTS.md + +# CLAUDE.md — cloudinary_wordpress + +## Claude Code-specific notes + +**Primary reference:** `AGENTS.md` (imported above) covers distribution, setup, build/test/lint, hooks, and gotchas. Read it before touching any file. + +## What this repo is + +`cloudinary_wordpress` is the **WordPress/WooCommerce site plugin** for Cloudinary: it syncs the media library to Cloudinary and rewrites front-end image/video URLs to be optimized and CDN-delivered. Users install it from the **WordPress.org plugin directory** (not Composer) and connect it with a `cloudinary://:@` string in `wp-admin`. It is **not** a code SDK. It does **not** wrap or require `cloudinary_php` — point custom-PHP-app builders to `cloudinary_php` instead. + +## Key constraints + +- **Build needs Node >=22 and npm >=10** (`.nvmrc` = 22, `engines.node` = ">=22", CI Node 22). Ignore any "Node 16" reference — it's stale. +- **Edit `src/`, never the compiled `js/` and `css/`.** They're built by webpack (`npm run build`). +- **`STABLETAG`** in `cloudinary.php` and `readme.txt` is a **build-time placeholder** for the version — do not replace it with a hardcoded version. Current version is 3.3.4 (`.version`, `package.json`). +- **PHP 7.4 floor.** Code must pass WordPress + VIP coding standards (`composer lint` → phpcs) and run on the CI matrix (PHP 7.4 & 8.3). +- **Branch target:** `master`. License is **GPL-2.0** — keep new files GPL-compatible. +- **`npm run readme` is broken** (missing `composer readme` script) — don't rely on it. + +## Verified build/test commands + +```bash +npm install # postinstall runs composer install (PHP tooling) +npm run lint # lint:php (phpcs) + lint:js + lint:style +npm run build # webpack production build (src/ -> js/, css/) +npm run dev # wp-scripts watch mode + +# End-to-end (Docker + wp-env): +npx playwright install --with-deps chromium +npm run build +npm run env:start # WordPress at http://localhost:8888 +npm run test:e2e # playwright test --config tests/e2e/playwright.config.js +npm run env:stop + +# Single e2e file: +npx playwright test tests/e2e/.spec.js --config tests/e2e/playwright.config.js + +# PHP lint / auto-fix: +composer lint # phpcs +composer fix # phpcbf +``` + +## Verified developer extension points + +- Filters: `cloudinary_transformations` (`php/class-media.php:994`), `cloudinary_is_media` (`php/class-media.php:331`), `cloudinary_can_sync_asset` (`php/class-sync.php:339`), `cloudinary_is_deliverable` (`php/class-delivery.php:419`). +- Actions: `cloudinary_register_sync_types` (`php/class-sync.php:679`), `cloudinary_init_delivery` (`php/class-delivery.php:850`). +- WP-CLI: `wp cloudinary sync` (`php/traits/trait-cli.php:144`), `wp cloudinary analyze` (`php/traits/trait-cli.php:202`). +- Full hook reference: . diff --git a/README.md b/README.md index 90aa11ee..4b238f26 100644 --- a/README.md +++ b/README.md @@ -1,182 +1,111 @@ -# Cloudinary's WordPress Plugin +# Cloudinary plugin for WordPress -Cloudinary is a cloud service that offers a solution to a web application's entire image and video management pipeline. -With Cloudinary, all your images are automatically uploaded, normalized, optimized and backed-up in the cloud instead of being hosted on your servers. +[![WordPress Plugin Version](https://img.shields.io/wordpress/plugin/v/cloudinary-image-management-and-manipulation-in-the-cloud-cdn.svg)](https://wordpress.org/plugins/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/) +[![License: GPL v2](https://img.shields.io/badge/license-GPL--2.0-blue.svg)](./LICENSE) +[![CI](https://github.com/cloudinary/cloudinary_wordpress/actions/workflows/ci.yml/badge.svg)](https://github.com/cloudinary/cloudinary_wordpress/actions/workflows/ci.yml) -With Cloudinary, you can stop messing around with image editors. Cloudinary can manipulate and transform your images online, on-the-fly, directly from your WordPress console. Enhance your images using every possible filter and effect you can think of. All manipulations are done in the cloud using super-powerful hardware, and all resulting images are cached, optimized (smushed and more) and delivered via a lightning fast content delivery network (CDN). +The Cloudinary plugin for WordPress syncs the WordPress media library to Cloudinary and rewrites the front-end image and video URLs a theme outputs so they deliver optimized, responsively sized, and CDN-served — no template edits. It's a site plugin configured in `wp-admin`, not a code SDK; it installs from the WordPress.org plugin directory (slug `cloudinary-image-management-and-manipulation-in-the-cloud-cdn`) and runs on WordPress 5.6+ (tested to 7.0) and PHP 7.4+. -## WordPress Plugin +## Installation -The plugin is available for installation via WordPress plugins directory. -The plugin is publicly available at: [https://wordpress.org/plugins/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/](https://wordpress.org/plugins/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/) +Install it from the WordPress.org plugin directory, not Composer: -This Git repository is the development repository, while there's a mirror public SVN repository of the actual released WordPress plugin version: [https://plugins.svn.wordpress.org/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/](https://plugins.svn.wordpress.org/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/) +1. In `wp-admin`, go to **Plugins > Add New**. +2. Search for **Cloudinary**. +3. On *Cloudinary - Deliver Images and Videos at Scale*, click **Install Now**, then **Activate**. -> **Deprecation Note** -> The legacy WordPress Plugin version (v1.x) will be deprecated as of **February 1st, 2021**, after which support, updates and bug fixes for the legacy plugin will continue in limited fashion. -> The legacy plugin will be made obsolete on **August 1st, 2021** (end-of-life date), meaning, Version 1.x of the plugin will no longer function after that date. -> We ask that you update to our latest WordPress Plugin v2.x before the August 1st deadline. +Or upload the ZIP from the [plugin page](https://wordpress.org/plugins/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/) via **Plugins > Add New > Upload Plugin**. The `composer.json` in this repo is for local development tooling only — don't `composer require` the plugin into a site. -## Additional resources +## Configuration -Additional resources are available at: +The plugin holds the API secret server-side (in the WordPress database), so there's no client-side config and no env var to export. Connect it with a single connection string in the admin UI: -- [Website](https://cloudinary.com) -- [Documentation](https://cloudinary.com/documentation) -- [Knowledge Base](https://support.cloudinary.com/hc/en-us) +1. In the [Cloudinary Console](https://console.cloudinary.com/console), copy the **API environment variable** for your product environment. Its format is: -## Support + ``` + cloudinary://:@ + ``` -You can [open an issue through GitHub](https://github.com/cloudinary/cloudinary_wordpress/issues). +2. In `wp-admin`, open the **Cloudinary** menu (the setup wizard opens on first activation). +3. Paste the connection string into the connection field and save. -Contact us [https://cloudinary.com/contact](https://cloudinary.com/contact) +Cloudinary verifies the credentials, then the Image, Video, Lazy Loading, and Sync settings pages become available. The API secret stays in the WordPress database on the server — it's never exposed on the front end. Keep it out of client-side code and version control. -Stay tuned for updates, tips and tutorials: [Blog](https://cloudinary.com/blog), [Twitter](https://twitter.com/cloudinary), [Facebook](https://www.facebook.com/Cloudinary). +## Quick examples -## Development +The plugin is configured through the admin UI; its behavior is extended from a theme or plugin through WordPress filters and WP-CLI. Add the PHP snippets to your theme's `functions.php`. Each hook name and line reference below is verified against the plugin source. -### Prerequisites +### Add a global transformation to every delivered image -- [Node.js](https://nodejs.org/) v16+ (see `.nvmrc`) -- [npm](https://www.npmjs.com/) v6.9+ -- [Composer](https://getcomposer.org/) -- [Docker](https://www.docker.com/) (required for the WordPress local environment via `wp-env`) +The `cloudinary_transformations` filter (`php/class-media.php:994`) receives the transformation array Cloudinary applies to an asset and the WordPress attachment ID. Append a step to change how every image is delivered: -### Local Development Setup - -1. **Clone the repository:** - - ```bash - git clone https://github.com/cloudinary/cloudinary_wordpress.git - cd cloudinary_wordpress - ``` - -2. **Set the correct Node version** (if using [nvm](https://github.com/nvm-sh/nvm)): - - ```bash - nvm install - nvm use - ``` - -3. **Install dependencies:** - - ```bash - npm install - ``` - - This will also run `composer install` automatically via the `postinstall` script, setting up PHP dependencies and linting tools. - -4. **Start the local WordPress environment:** - - Make sure Docker is running, then: - - ```bash - npm run env:start - ``` - - This spins up a WordPress instance at [http://localhost:8888](http://localhost:8888) with the plugin activated and `WP_DEBUG` enabled. A loopback fix is applied automatically so REST API self-requests work inside the container. - -5. **Build front-end assets:** - - ```bash - npm run build # One-time production build - npm run dev # Watch mode for development - ``` - -### Useful Commands - -| Command | Description | -| ---------------------- | ---------------------------------------- | -| `npm run env:start` | Start the local WordPress environment | -| `npm run env:stop` | Stop the local WordPress environment | -| `npm run env:destroy` | Remove the local environment completely | -| `npm run env:logs` | View container logs | -| `npm run env:cli` | Run WP-CLI commands inside the container | -| `npm run env:clean` | Reset the environment (removes all data) | -| `npm run build` | Build front-end assets for production | -| `npm run dev` | Build front-end assets in watch mode | -| `npm run lint` | Run all linters (PHP, JS, CSS) | -| `npm run lint:php` | Run PHP CodeSniffer | -| `npm run lint:php:fix` | Auto-fix PHP linting issues | -| `npm run lint:js` | Run ESLint on JavaScript files | -| `npm run lint:js:fix` | Auto-fix JS linting issues | -| `npm run lint:style` | Run stylelint on SCSS files | -| `npm run i18n` | Generate translation files | - -### Create a Plugin Release Package - -Run `npm run package` to create the plugin release in the `/build` directory and package it as `cloudinary-image-management-and-manipulation-in-the-cloud-cdn.zip` in the root directory. - -Files included in the release package are defined in the `gruntfile.js` under the `copy` task. Be sure to update this list of files and directories when you add new files to the project. - -### Deployment to WordPress.org - -Deployment is automated via the `Deploy to WordPress.org Repository` GitHub Actions workflow (`.github/workflows/deploy-to-wp-org.yml`): - -1. Bump the version in `.version` on `master` (this is what gets checked against the release tag, and what `readme.txt`/`cloudinary.php` are stamped with during the build). - -2. Create and publish a GitHub Release from `master`, with a tag matching that version (e.g. `3.3.4` or `v3.3.4`). Publishing the release triggers the workflow, which builds the plugin, deploys it to the WP.org SVN repository, and attaches the built zip to the release. - - - Marking the release as a **pre-release** runs the same workflow in dry-run mode: it builds and verifies everything but skips the actual SVN commit, which is the safe way to test a release without shipping it to WP.org. - - The workflow can also be run manually from the Actions tab (`workflow_dispatch`) against any branch/tag, defaulting to a dry-run, to exercise the pipeline without publishing a GitHub release at all. - -3. If you need to deploy from a local machine instead (e.g. as a fallback), run `npm run deploy`, which builds and runs `grunt deploy` using SVN credentials configured locally. - -4. Run `npm run deploy-assets` to deploy just the WP.org plugin assets such as screenshots, icons and banners. - -## End-to-end testing - -E2E tests run against a wp-env site using Playwright. - -### One-time setup - -```bash -npm install -npx playwright install --with-deps chromium -npm run env:start +```php + 'sharpen:80' ); + return $transformations; + }, + 10, + 2 +); ``` -### Running the tests - -```bash -npm run test:e2e +### Keep specific assets out of Cloudinary + +The `cloudinary_can_sync_asset` filter (`php/class-sync.php:339`) receives whether an asset may sync, its attachment ID, and its sync type. Return `false` to keep an asset on the WordPress host: + +```php +:@` string in `wp-admin`, and needs no application code for basic use. It does not wrap or require `cloudinary_php`. For other platforms and tasks, route to a different package: -> **Note:** Do **not** set `CLOUDINARY_URL` or `CLOUDINARY_CONNECTION_STRING` as PHP constants via `.wp-env.override.json` while running this spec. The plugin treats a constant-defined connection string as already-configured and hides the wizard's connection input, which makes the test impossible. - -CI will provide `CLOUDINARY_E2E_URL` via a GitHub Actions secret (wired separately under WPP-1195's CI subtask). - -### Debugging a failing e2e test - -```bash -npm run test:e2e:debug -- wizard-setup -``` +| Task | Use instead | +|---|---| +| Call Cloudinary from a custom PHP application | [`cloudinary_php`](https://github.com/cloudinary/cloudinary_php) | +| A Magento 2 / Adobe Commerce store | [`cloudinary_magento2`](https://github.com/cloudinary/cloudinary_magento2) | +| SAP Commerce Cloud | [`cloudinary_sap_commerce`](https://github.com/cloudinary/cloudinary_sap_commerce) | +| Salesforce Commerce Cloud | [`cloudinary_sfcc_site_cartridge`](https://github.com/cloudinary/cloudinary_sfcc_site_cartridge) | +| commercetools | [`cloudinary_commercetools`](https://github.com/cloudinary/cloudinary_commercetools) | +| Run Cloudinary operations as agent tools | [Cloudinary MCP servers](https://github.com/cloudinary/mcp-servers) | -This opens Playwright's UI runner where you can step through actions, inspect the DOM, and view the network panel. +## Links -## License +- [WordPress integration guide](https://cloudinary.com/documentation/wordpress_integration) +- [Developer hooks (actions and filters)](https://cloudinary.com/documentation/wordpress_developers#actions_and_filters) +- [Transformation and API references](https://cloudinary.com/documentation/cloudinary_references) +- [Documentation llms.txt index](https://cloudinary.com/documentation/llms.txt) +- [Plugin on WordPress.org](https://wordpress.org/plugins/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/) -Released under the GPL license. +Released under the GPL-2.0 license.