Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
7188f68
Raise PHPStan to level 1 and fix all findings
PatelUtkarsh Jun 24, 2026
955fb01
Fix: don't force non-crop size slugs to exact dimensions
airbuzz Jun 26, 2026
fdd3129
Avoid re-running full plugin init during activation
PatelUtkarsh Jul 3, 2026
423ac1b
Merge branch 'develop' into phpstan-level1
PatelUtkarsh Jul 8, 2026
72ef050
Bump PHPStan to level 2 and fix type/annotation issues
PatelUtkarsh Jul 8, 2026
1a2fbe9
Fix broken references to removed settings API
PatelUtkarsh Jul 8, 2026
302a540
Bump PHPStan to level 3 and fix type/annotation issues
PatelUtkarsh Jul 14, 2026
7f7cf79
Suppress content filters on internal asset bookkeeping queries
PatelUtkarsh Jul 14, 2026
3d0b290
Bump PHPStan to level 4 and fix type/annotation issues
PatelUtkarsh Jul 14, 2026
9e09d5a
Use version_compare for 2.4 to 2.5 settings migration guard
PatelUtkarsh Jul 14, 2026
e6e9051
chore(docs): add hookdoc build workflow
PatelUtkarsh Jul 14, 2026
48286c1
Merge pull request #1206 from cloudinary/uat
gabrielcld2 Jul 20, 2026
018fcc1
Pass version explicitly to the release GH action
gabriel-detassigny Jul 21, 2026
6563ad5
Merge branch 'master' into feature/release-automation
gabriel-detassigny Jul 21, 2026
b7661db
New version to test release process
gabriel-detassigny Jul 21, 2026
e9a5ed4
Make zip downloadable from artifacts panel
gabriel-detassigny Jul 21, 2026
e8fe824
Merge pull request #1188 from cloudinary/phpstan-level1
utkarshcloudinary Jul 24, 2026
219a6d7
Merge pull request #1196 from cloudinary/phpstan-level2
utkarshcloudinary Jul 24, 2026
0601302
Merge pull request #1198 from cloudinary/phpstan-level3
utkarshcloudinary Jul 24, 2026
3e52b58
Merge pull request #1200 from cloudinary/phpstan-level4
utkarshcloudinary Jul 24, 2026
05fc20c
Merge branch 'develop' into chore/docs-workflow
gabriel-detassigny Jul 24, 2026
a932d43
Merge branch 'develop' into chore/docs-workflow
gabriel-detassigny Jul 24, 2026
bb5751b
Bump PHPStan to level 5 and fix type/annotation issues
PatelUtkarsh Jul 24, 2026
81f8f0c
Merge pull request #1201 from cloudinary/chore/docs-workflow
utkarshcloudinary Jul 24, 2026
f8c6b64
Merge pull request #1213 from cloudinary/phpstan-level5
gabrielcld2 Jul 24, 2026
f3eafa8
Ensure Gallery block compatibility with WordPress 7.1
PatelUtkarsh Jul 24, 2026
02432c8
Fix core image/video block editor integration for WordPress 7.1
PatelUtkarsh Jul 27, 2026
444501e
Fix duplicate gallery settings app script enqueue
PatelUtkarsh Jul 27, 2026
b2ca7f2
Use generated asset dependencies for the block editor script
PatelUtkarsh Jul 27, 2026
be00b29
Upgrade node dependencies to fix security vulnerabilities
gabriel-detassigny Jul 27, 2026
36b997b
Auto-fix ESLint/Prettier formatting issues
gabriel-detassigny Jul 27, 2026
21e52c5
Fix remaining lint issues in the six files left out of the formatting…
gabriel-detassigny Jul 27, 2026
a776120
Override webpack-dev-server to patched v5.2.6
gabriel-detassigny Jul 27, 2026
d59c930
Merge pull request #1199 from cloudinary/fix/suppress-filters-interna…
gabrielcld2 Jul 31, 2026
603fe2f
Instrument connection, sync, settings, media, cache, features, and de…
gabriel-detassigny Jul 31, 2026
9593d81
Rebuild JS bundles for the new analytics call sites
gabriel-detassigny Aug 3, 2026
385d11b
Merge remote-tracking branch 'origin/develop' into feature/custom-eve…
gabriel-detassigny Aug 3, 2026
330e67b
Add Analytics to get_component()'s return type for phpstan level 5
gabriel-detassigny Aug 3, 2026
154e5c5
Merge pull request #1190 from airbuzz/fix/size-slug-non-crop-stretch
gabrielcld2 Aug 4, 2026
0a787d2
Fix Image_Preview's placeholder src causing a self-fetch on every pag…
gabriel-detassigny Aug 4, 2026
e7d1fd0
Bump brace-expansion override to ^5.0.9
gabriel-detassigny Aug 4, 2026
b5fb4e7
Merge pull request #1223 from cloudinary/chore/upgrade-packages
gabrielcld2 Aug 4, 2026
ba269c6
Merge remote-tracking branch 'origin/develop' into feature/custom-eve…
gabriel-detassigny Aug 4, 2026
55fb9f3
Rebuild JS bundles for the new analytics call sites
gabriel-detassigny Aug 4, 2026
1531459
Continue analytics implementation
gabriel-detassigny Aug 6, 2026
cc8d844
Merge branch 'develop' into fix/wp-7-1-compatibility
gabriel-detassigny Aug 6, 2026
0335980
Add @wordpress/hooks as dev dependency
gabriel-detassigny Aug 6, 2026
6a54914
Merge pull request #1222 from cloudinary/fix/wp-7-1-compatibility
gabrielcld2 Aug 6, 2026
37eed2f
Merge branch 'develop' into feature/release-automation
gabriel-detassigny Aug 6, 2026
0831eb0
Revert "New version to test release process"
gabriel-detassigny Aug 6, 2026
05140bc
Merge pull request #1229 from cloudinary/feature/release-automation
gabrielcld2 Aug 6, 2026
c98e6d7
Automate sync category e2e coverage
gabriel-detassigny Aug 6, 2026
da72772
Automate media category e2e coverage
gabriel-detassigny Aug 6, 2026
1e1dd5a
Automate cache category e2e coverage
gabriel-detassigny Aug 6, 2026
72fd7ec
Automate features category e2e coverage
gabriel-detassigny Aug 6, 2026
f2db431
Add e2e coverage for connection_disconnected, deactivation_submitted,…
gabriel-detassigny Aug 6, 2026
5d0f0ac
Preempt real analytics/deactivation-feedback traffic from test runs; …
gabriel-detassigny Aug 10, 2026
cac149e
Make asset_cache_purged test deterministic instead of relying on page…
gabriel-detassigny Aug 10, 2026
c6215cf
Fix JSON object/array shape corruption in REST API string replacement
gabriel-detassigny Aug 10, 2026
98d0854
Merge pull request #1232 from cloudinary/chore/upgrade-packages
gabrielcld2 Aug 10, 2026
27f1ee9
Add taffydb dev dependency required for docs generation
gabriel-detassigny Aug 10, 2026
4d38d47
Merge pull request #1233 from cloudinary/bugfix/docs-action
gabrielcld2 Aug 10, 2026
fd8eaad
Merge pull request #1231 from cloudinary/bugfix/novamira
gabrielcld2 Aug 11, 2026
89dcda9
Merge branch 'develop' into feature/custom-events-tracking
gabriel-detassigny Aug 11, 2026
6d30260
Address PR review: fix event-scope/race bugs, sanitize input, harden …
gabriel-detassigny Aug 11, 2026
9eb38fa
Address follow-up PR review: fix notoptions cache poisoning and notic…
gabriel-detassigny Aug 11, 2026
4c7ea71
Merge pull request #1226 from cloudinary/feature/custom-events-tracking
gabrielcld2 Aug 12, 2026
70a9dd9
Merge pull request #1193 from cloudinary/fix/activation-avoid-early-f…
gabrielcld2 Aug 12, 2026
86ae524
Add Dependabot config for Composer targeting develop
PatelUtkarsh Aug 12, 2026
25e2ad4
Add npm ecosystem to Dependabot config
PatelUtkarsh Aug 12, 2026
eddd37d
Add npm ecosystem to Dependabot with @wordpress/* group
PatelUtkarsh Aug 12, 2026
e8c6025
Merge pull request #1235 from cloudinary/chore/add-dependabot-config
gabrielcld2 Aug 12, 2026
862879e
Fix dependencies for i18n command
gabriel-detassigny Aug 12, 2026
ec0934f
Generate pot file
gabriel-detassigny Aug 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .eslintignore

This file was deleted.

30 changes: 0 additions & 30 deletions .eslintrc.json

This file was deleted.

16 changes: 16 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
version: 2
updates:
- package-ecosystem: composer
directory: /
schedule:
interval: weekly
target-branch: develop
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
target-branch: develop
groups:
wordpress:
patterns:
- "@wordpress/*"
37 changes: 37 additions & 0 deletions .github/workflows/build-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Build Docs

on:
push:
branches:
- master
release:
types: [published]
workflow_dispatch:

permissions:
contents: write

jobs:
hookdocs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build docs
run: npm run build:docs

- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
22 changes: 19 additions & 3 deletions .github/workflows/deploy-to-wp-org.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,21 @@ jobs:
- name: Prepare build directory
run: npx grunt prepare

# Read once so both the tag check and the deploy step use the exact same value, rather
# than letting the deploy action derive its own version from GITHUB_REF - that only works
# when triggered from a tag push, and yields a bogus value like "refs/heads/master" (which
# SVN then can't use as a tag path) on a workflow_dispatch run against a branch.
- name: Read plugin version
run: echo "PLUGIN_VERSION=$(cat .version | tr -d '[:space:]')" >> "$GITHUB_ENV"

# Ensure the version in the .version file matches the tag of the release.
# Skipped for manual runs, which may not be run against a release tag.
- name: Verify version matches tag
if: github.event_name == 'release'
run: |
TAG="${GITHUB_REF_NAME#v}"
FILE_VERSION=$(cat .version | tr -d '[:space:]')
if [ "$TAG" != "$FILE_VERSION" ]; then
echo "::error::Tag $TAG does not match .version $FILE_VERSION"
if [ "$TAG" != "$PLUGIN_VERSION" ]; then
echo "::error::Tag $TAG does not match .version $PLUGIN_VERSION"
exit 1
fi

Expand All @@ -102,10 +108,20 @@ jobs:
env:
BUILD_DIR: 'build'
SLUG: 'cloudinary-image-management-and-manipulation-in-the-cloud-cdn'
VERSION: ${{ env.PLUGIN_VERSION }}
# Use secrets to authenticate with WP.org.
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}

# Makes the zip downloadable from the run's Artifacts panel regardless of trigger, so
# manual/dry-run dispatches can be inspected without publishing a release.
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.PLUGIN_VERSION }}.zip
path: ${{ steps.deploy.outputs.zip-path }}
retention-days: 7

- name: Upload release asset
if: github.event_name == 'release'
uses: softprops/action-gh-release@v2
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,6 @@ package/dist

# PHPStan result cache
/.phpstan-cache/

# Generated docs (published to gh-pages by workflow)
/docs/
46 changes: 46 additions & 0 deletions .hookdoc/layout.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title><?js= title ?> - Cloudinary Docs</title>

<script src="scripts/prettify/prettify.js"></script>
<script src="scripts/prettify/lang-css.js"></script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">

<link
href="https://fonts.googleapis.com/css?family=IBM+Plex+Mono|IBM+Plex+Sans:300,400|Playfair+Display:900&display=swap"
rel="stylesheet">
</head>

<body>

<div id="main">

<?js if (title !== 'Home') { ?>
<h1 class="page-title"><?js= title ?></h1>
<?js } ?>

<?js= content ?>
</div>

<nav>
<?js= this.nav ?>
</nav>

<br class="clear">

<footer>
<a href="https://cloudinary.com/" target="_blank" rel="noopener noreferrer">Cloudinary</a> |
<a href="https://github.com/cloudinary/cloudinary_wordpress/" target="_blank" rel="noopener noreferrer">Cloudinary
on GitHub</a>
</footer>

<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"></script>
</body>
</html>
94 changes: 94 additions & 0 deletions .wp-env/mu-plugins/analytics-capture.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php
/**
* Analytics egress capture — local/e2e dev helper mu-plugin.
*
* Intercepts outgoing requests to any Cloudinary analytics-api.cloudinary.com
* endpoint — the custom-events collector AND the older deactivation-reason
* collector, both on the same host — and appends each payload as a JSONL
* entry to a log file, so e2e tests and manual QA can assert on emitted
* events. The request is fully preempted with a synthetic response: earlier
* versions of this mu-plugin only logged the payload and let the request
* proceed, which meant every local/CI test run was quietly leaking synthetic
* events (and deactivation "feedback") into the real production collector.
*
* @package Cloudinary
*/

defined( 'ABSPATH' ) || exit;

/**
* Returns the path to the capture log file.
*
* @return string
*/
function cld_analytics_capture_log_path() {
$upload = wp_upload_dir();

return $upload['basedir'] . '/analytics-capture.log';
}

add_filter( 'pre_http_request', 'cld_analytics_capture_intercept', 10, 3 );

/**
* Logs outgoing analytics/deactivation-reason requests and preempts them
* with a synthetic success response, so nothing actually reaches the real
* collector during local dev or CI runs.
*
* @param false|array|WP_Error $preempt Whether to preempt the request.
* @param array $parsed_args Parsed request arguments.
* @param string $url The request URL.
*
* @return false|array|WP_Error
*/
function cld_analytics_capture_intercept( $preempt, $parsed_args, $url ) {
if ( false === strpos( $url, 'analytics-api.cloudinary.com' ) ) {
return $preempt;
}

$body = isset( $parsed_args['body'] ) ? $parsed_args['body'] : '';
$decoded = json_decode( $body, true );

file_put_contents( // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents, WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_file_put_contents
cld_analytics_capture_log_path(),
wp_json_encode( null !== $decoded ? $decoded : $body ) . "\n",
FILE_APPEND | LOCK_EX
);

return array(
'headers' => array(),
'body' => '',
'response' => array(
'code' => 200,
'message' => 'OK',
),
'cookies' => array(),
'filename' => null,
);
}

/**
* Prints the captured analytics events, one JSON object per line.
*
* ## OPTIONS
*
* [--clear]
* : Empty the log after printing it.
*
* @param array $args Positional arguments.
* @param array $assoc_args Associative arguments.
*/
function cld_analytics_capture_wpcli_command( $args, $assoc_args ) {
$log_file = cld_analytics_capture_log_path();

if ( file_exists( $log_file ) ) {
WP_CLI::line( file_get_contents( $log_file ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents, WordPressVIPMinimum.Performance.FetchingRemoteData.FileGetContentsUnknown
}

if ( isset( $assoc_args['clear'] ) ) {
file_put_contents( $log_file, '' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents, WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_file_put_contents
}
}

if ( defined( 'WP_CLI' ) && WP_CLI ) {
WP_CLI::add_command( 'cloudinary analytics-events', 'cld_analytics_capture_wpcli_command' );
}
2 changes: 1 addition & 1 deletion css/cloudinary.css

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions css/gallery-ui.css

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
const globals = require( 'globals' );
const wpPlugin = require( '@wordpress/eslint-plugin' );

// eslint-import-resolver-typescript v4+ is incompatible with eslint-plugin-import
// (throws "invalid interface loaded as resolver"), and this project has no TypeScript
// anyway, so strip the typescript resolver that @wordpress/eslint-plugin configures.
const recommended = wpPlugin.configs.recommended.map( ( config ) => {
if ( ! config.settings || ! config.settings[ 'import/resolver' ] ) {
return config;
}
const { typescript, ...resolver } = config.settings[ 'import/resolver' ];
return {
...config,
settings: {
...config.settings,
'import/resolver': resolver,
},
};
} );

module.exports = [
{
ignores: [
'**/build/**',
'**/built/**',
'**/node_modules/**',
'**/vendor/**',
'js/**',
'**/*.min.js',
// Vendored third-party library (https://github.com/kallookoo/wp-color-picker-alpha).
'src/js/wp-color-picker-alpha.js',
],
},
...recommended,
{
settings: {
'import/resolver': {
node: true,
},
},
languageOptions: {
globals: {
...globals.browser,
cloudinary: 'readonly',
jQuery: 'readonly',
$: 'readonly',
CLDN: 'readonly',
CLDLB: 'readonly',
CLD_GLOBAL_TRANSFORMATIONS: 'readonly',
samplePlayer: 'readonly',
CLDCACHE: 'readonly',
cldData: 'readonly',
CLD_METADATA: 'readonly',
CLDASSETS: 'readonly',
},
},
rules: {
'no-alert': 'off',
'no-console': 'off',
'no-unused-vars': 'off',
'no-nested-ternary': 'off',
'jsx-a11y/click-events-have-key-events': 'off',
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'@wordpress/no-global-event-listener': 'off',
// CLD_Deactivate is a wp_localize_script object name (php/class-deactivation.php);
// renaming it would require a matching PHP-side change.
camelcase: [
'error',
{ properties: 'never', allow: [ '^CLD_Deactivate$' ] },
],
},
},
];
19 changes: 19 additions & 0 deletions hookdoc-conf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"opts": {
"destination": "docs",
"template": "node_modules/wp-hookdoc/template",
"recurse": true,
"readme": "./README.md"
},
"source": {
"includePattern": ".+\\.(php|inc)?$"
},
"plugins": [
"node_modules/wp-hookdoc/plugin"
],
"templates": {
"default": {
"layoutFile": ".hookdoc/layout.tmpl"
}
}
}
2 changes: 1 addition & 1 deletion js/asset-edit.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/asset-manager.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/block-editor.asset.php
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?php return array('dependencies' => array('wp-api-fetch', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => 'aab7b2e0606348e43cc2');
<?php return array('dependencies' => array('wp-api-fetch', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-hooks', 'wp-i18n'), 'version' => '58afb0a9ee7fa6faecd7');
Loading
Loading