From 3ac86eb10e1ae723794f180f6dcb8eef7426079e Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Thu, 2 Apr 2026 14:24:16 -0400 Subject: [PATCH 01/19] feature: scaffold initial harbor integration --- composer.json | 5 +- composer.lock | 558 +++++++++++++----- includes/resources/App.php | 2 + includes/resources/Harbor/Harbor_Provider.php | 58 ++ 4 files changed, 459 insertions(+), 164 deletions(-) create mode 100644 includes/resources/Harbor/Harbor_Provider.php diff --git a/composer.json b/composer.json index fc01e7401..db7abc9c3 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,7 @@ "psr/container": "^1.0", "stellarwp/container-contract": "^1.1", "stellarwp/db": "^1.1", + "stellarwp/harbor": "dev-main", "stellarwp/prophecy-image-downloader": "^3.0", "stellarwp/prophecy-storage": "^3.0", "stellarwp/schema": "^2.0", @@ -83,16 +84,18 @@ "vendor/bin/stellar-uplink domain=kadence-blocks" ], "strauss-install": [ - "test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/download/0.19.1/strauss.phar" + "test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/download/0.27.0/strauss.phar" ], "strauss": [ "@strauss-install", "@php bin/strauss.phar", + "@php vendor/stellarwp/harbor/bin/stellar-harbor domain=kadence-blocks", "@composer dump-autoload" ], "strauss-release": [ "@strauss-install", "@php bin/strauss.phar --deleteVendorPackages=true", + "@php vendor/stellarwp/harbor/bin/stellar-harbor domain=kadence-blocks", "@composer dump-autoload" ], "strauss-clean": [ diff --git a/composer.lock b/composer.lock index 77382173e..6e65a13ac 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7a823630fd7197034de879f12f7ac260", + "content-hash": "9bfeef8e7638329a40d2da9f24b9d639", "packages": [ { "name": "adbario/php-dot-notation", @@ -460,6 +460,84 @@ ], "time": "2026-01-01T13:05:00+00:00" }, + { + "name": "nyholm/psr7", + "version": "1.8.2", + "source": { + "type": "git", + "url": "https://github.com/Nyholm/psr7.git", + "reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nyholm/psr7/zipball/a71f2b11690f4b24d099d6b16690a90ae14fc6f3", + "reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0" + }, + "provide": { + "php-http/message-factory-implementation": "1.0", + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "http-interop/http-factory-tests": "^0.9", + "php-http/message-factory": "^1.0", + "php-http/psr7-integration-tests": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.4", + "symfony/error-handler": "^4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.8-dev" + } + }, + "autoload": { + "psr-4": { + "Nyholm\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com" + }, + { + "name": "Martijn van der Ven", + "email": "martijn@vanderven.se" + } + ], + "description": "A fast PHP7 implementation of PSR-7", + "homepage": "https://tnyholm.se", + "keywords": [ + "psr-17", + "psr-7" + ], + "support": { + "issues": "https://github.com/Nyholm/psr7/issues", + "source": "https://github.com/Nyholm/psr7/tree/1.8.2" + }, + "funding": [ + { + "url": "https://github.com/Zegnat", + "type": "github" + }, + { + "url": "https://github.com/nyholm", + "type": "github" + } + ], + "time": "2024-09-09T07:06:30+00:00" + }, { "name": "phpoption/phpoption", "version": "1.9.5", @@ -583,6 +661,166 @@ }, "time": "2021-11-05T16:50:12+00:00" }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/1.1" + }, + "time": "2023-04-04T09:50:52+00:00" + }, { "name": "psr/log", "version": "1.1.4", @@ -784,6 +1022,159 @@ }, "time": "2025-11-10T10:55:50+00:00" }, + { + "name": "stellarwp/harbor", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/stellarwp/harbor.git", + "reference": "f59c6d9c46f304383bf2cadb29fe3e0b5d1ac96e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stellarwp/harbor/zipball/f59c6d9c46f304383bf2cadb29fe3e0b5d1ac96e", + "reference": "f59c6d9c46f304383bf2cadb29fe3e0b5d1ac96e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nyholm/psr7": "^1.0", + "php": ">=7.4", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1", + "stellarwp/container-contract": "^1.0", + "stellarwp/licensing-api-client-wordpress": "^0.9" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1", + "dpanta94/phpstan-containers": "^0", + "exussum12/coverage-checker": "^1.1", + "lucatume/codeception-snapshot-assertions": "*", + "lucatume/di52": "^3", + "lucatume/wp-browser": "*", + "php-stubs/wp-cli-stubs": "^2", + "phpcompatibility/phpcompatibility-wp": "^2", + "phpspec/prophecy": "*", + "phpspec/prophecy-phpunit": "*", + "phpstan/phpstan": "^2", + "phpunit/phpunit": "*", + "stellarwp/coding-standards": "^2", + "szepeviktor/phpstan-wordpress": ">=1.0", + "wp-cli/wp-cli": "^2" + }, + "default-branch": true, + "bin": [ + "bin/stellar-harbor" + ], + "type": "library", + "autoload": { + "psr-4": { + "LiquidWeb\\Harbor\\": "src/Harbor/", + "LiquidWeb\\Harbor\\Views\\": "src/views/", + "LiquidWeb\\Harbor\\Build_Dir\\": "build/", + "LiquidWeb\\Harbor\\Build_Dev_Dir\\": "build-dev/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Liquid Web", + "homepage": "https://liquidweb.com" + } + ], + "description": "A library that integrates a WordPress product with the Liquid Web licensing system.", + "support": { + "issues": "https://github.com/stellarwp/harbor/issues", + "source": "https://github.com/stellarwp/harbor/tree/main" + }, + "time": "2026-04-02T16:22:47+00:00" + }, + { + "name": "stellarwp/licensing-api-client", + "version": "0.9.3", + "source": { + "type": "git", + "url": "https://github.com/stellarwp/licensing-api-client.git", + "reference": "0ed1a9caf57889f864fcb8636dad6ecfbdb86f6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stellarwp/licensing-api-client/zipball/0ed1a9caf57889f864fcb8636dad6ecfbdb86f6e", + "reference": "0ed1a9caf57889f864fcb8636dad6ecfbdb86f6e", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=7.4", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.10.x-dev" + } + }, + "autoload": { + "psr-4": { + "LiquidWeb\\LicensingApiClient\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "description": "A PHP client for the Liquid Web Licensing API.", + "support": { + "source": "https://github.com/stellarwp/licensing-api-client/tree/0.9.3" + }, + "time": "2026-04-02T17:34:33+00:00" + }, + { + "name": "stellarwp/licensing-api-client-wordpress", + "version": "0.9.3", + "source": { + "type": "git", + "url": "https://github.com/stellarwp/licensing-api-client-wordpress.git", + "reference": "9b2b181ff25887363b4a372ea54a67b2ffeb6245" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stellarwp/licensing-api-client-wordpress/zipball/9b2b181ff25887363b4a372ea54a67b2ffeb6245", + "reference": "9b2b181ff25887363b4a372ea54a67b2ffeb6245", + "shasum": "" + }, + "require": { + "nyholm/psr7": "^1.8", + "php": ">=7.4", + "stellarwp/licensing-api-client": "^0.9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.10.x-dev" + } + }, + "autoload": { + "psr-4": { + "LiquidWeb\\LicensingApiClientWordPress\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "description": "WordPress transport and factory integration for the Liquid Web Licensing API client.", + "support": { + "source": "https://github.com/stellarwp/licensing-api-client-wordpress/tree/0.9.3" + }, + "time": "2026-04-02T17:37:04+00:00" + }, { "name": "stellarwp/prophecy-container", "version": "3.0.0.74", @@ -7229,166 +7620,6 @@ }, "time": "2019-01-08T18:20:26+00:00" }, - { - "name": "psr/http-client", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-client.git", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", - "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", - "shasum": "" - }, - "require": { - "php": "^7.0 || ^8.0", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Client\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP clients", - "homepage": "https://github.com/php-fig/http-client", - "keywords": [ - "http", - "http-client", - "psr", - "psr-18" - ], - "support": { - "source": "https://github.com/php-fig/http-client" - }, - "time": "2023-09-23T14:17:50+00:00" - }, - { - "name": "psr/http-factory", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-factory.git", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", - "shasum": "" - }, - "require": { - "php": ">=7.1", - "psr/http-message": "^1.0 || ^2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", - "keywords": [ - "factory", - "http", - "message", - "psr", - "psr-17", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-factory" - }, - "time": "2024-04-15T12:06:14+00:00" - }, - { - "name": "psr/http-message", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "time": "2023-04-04T09:54:51+00:00" - }, { "name": "psr/simple-cache", "version": "1.0.1", @@ -12490,6 +12721,7 @@ "aliases": [], "minimum-stability": "stable", "stability-flags": { + "stellarwp/harbor": 20, "stellarwp/uplink": 20 }, "prefer-stable": false, @@ -12497,9 +12729,9 @@ "platform": { "ext-json": "*" }, - "platform-dev": {}, + "platform-dev": [], "platform-overrides": { "php": "7.4" }, - "plugin-api-version": "2.9.0" + "plugin-api-version": "2.6.0" } diff --git a/includes/resources/App.php b/includes/resources/App.php index 08dec39aa..91cc30cfe 100644 --- a/includes/resources/App.php +++ b/includes/resources/App.php @@ -16,6 +16,7 @@ use KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface; use KadenceWP\KadenceBlocks\StellarWP\ProphecyMonorepo\Container\Contracts\Container; use KadenceWP\KadenceBlocks\StellarWP\ProphecyMonorepo\Container\Contracts\Providable; +use KadenceWP\KadenceBlocks\Harbor\Harbor_Provider; use KadenceWP\KadenceBlocks\Uplink\Uplink_Provider; use RuntimeException; @@ -43,6 +44,7 @@ final class App { Database_Provider::class, Asset_Provider::class, Uplink_Provider::class, + Harbor_Provider::class, Health_Provider::class, Admin_Provider::class, Image_Downloader_Provider::class, diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php new file mode 100644 index 000000000..167de0aa8 --- /dev/null +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -0,0 +1,58 @@ +container ); + Harbor::init(); + + lw_harbor_register_submenu( 'kadence-blocks' ); + add_filter( 'lw-harbor/legacy_licenses', [ $this, 'report_legacy_licenses' ] ); + } + + /** + * Reports legacy Uplink-managed Kadence licenses to Harbor so they appear + * in the unified license UI. + * + * @param array $licenses Existing legacy licenses from other plugins. + * + * @return array + */ + public function report_legacy_licenses( array $licenses ): array { + $data = kadence_blocks_get_current_license_data(); + + if ( empty( $data['key'] ) ) { + return $licenses; + } + + $product_names = [ + 'kadence-blocks' => 'Kadence Blocks', + 'kadence-blocks-pro' => 'Kadence Blocks Pro', + 'kadence-creative-kit' => 'Kadence Creative Kit', + ]; + + $slug = $data['product'] ?? 'kadence-blocks'; + $name = $product_names[ $slug ] ?? 'Kadence Blocks'; + + $licenses[] = [ + 'key' => $data['key'], + 'slug' => $slug, + 'name' => $name, + 'product' => 'kadence', + 'is_active' => true, + 'page_url' => admin_url( 'admin.php?page=kadence-blocks-home' ), + ]; + + return $licenses; + } + +} From e8cb1887b11fa5ad9e364e5213e351959ad32d80 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Thu, 2 Apr 2026 14:47:30 -0400 Subject: [PATCH 02/19] feature: add harbor check and update existing conditional --- includes/class-kadence-blocks-ai-events.php | 11 +-------- .../class-kadence-blocks-editor-assets.php | 9 ++----- includes/helper-functions.php | 24 +++++++++++++++++++ includes/resources/Harbor/Harbor_Provider.php | 21 +++++++++------- .../class-kadence-blocks-settings.php | 8 +------ 5 files changed, 41 insertions(+), 32 deletions(-) diff --git a/includes/class-kadence-blocks-ai-events.php b/includes/class-kadence-blocks-ai-events.php index 6ad570284..5101df20f 100644 --- a/includes/class-kadence-blocks-ai-events.php +++ b/includes/class-kadence-blocks-ai-events.php @@ -7,10 +7,7 @@ exit; } -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_authorization_token; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_domain; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_original_domain; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\is_authorized; /** * Class responsible for sending events AI Events to Stellar Prophecy WP AI. @@ -99,13 +96,7 @@ public function verify_user_can_edit(): bool { */ public function handle_event( string $name, array $context ): void { // Only pass tracking events if AI has been activated through Opt in. - $token = get_authorization_token( 'kadence-blocks' ); - $license_key = kadence_blocks_get_current_license_key(); - $is_authorized = false; - if ( ! empty( $license_key ) ) { - $is_authorized = is_authorized( $license_key, 'kadence-blocks', ( ! empty( $token ) ? $token : '' ), get_license_domain() ); - } - if ( ! $is_authorized ) { + if ( ! kadence_blocks_is_license_authorized() ) { return; } diff --git a/includes/class-kadence-blocks-editor-assets.php b/includes/class-kadence-blocks-editor-assets.php index a774b162d..1eb6be5ee 100644 --- a/includes/class-kadence-blocks-editor-assets.php +++ b/includes/class-kadence-blocks-editor-assets.php @@ -8,9 +8,8 @@ namespace KadenceWP\KadenceBlocks; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_domain; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_authorization_token; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\is_authorized; use function kadence_blocks_get_asset_file; +use function kadence_blocks_is_license_authorized; use function kadence_blocks_get_current_license_data; use function kadence_blocks_get_post_types; use function kadence_blocks_is_ai_disabled; @@ -293,11 +292,7 @@ public function editor_assets_variables() { if ( ! empty( $pro_data['email'] ) ) { $pro_data['api_email'] = $pro_data['email']; } - $token = ! kadence_blocks_is_ai_disabled() ? get_authorization_token( 'kadence-blocks' ) : ''; - $is_authorized = false; - if ( ! empty( $pro_data['key'] ) && ! kadence_blocks_is_ai_disabled() ) { - $is_authorized = is_authorized( $pro_data['key'], 'kadence-blocks', ( ! empty( $token ) ? $token : '' ), get_license_domain() ); - } + $is_authorized = ! kadence_blocks_is_ai_disabled() && kadence_blocks_is_license_authorized(); if ( empty( $pro_data['domain'] ) ) { $pro_data['domain'] = get_license_domain(); } diff --git a/includes/helper-functions.php b/includes/helper-functions.php index cecc0ecbd..4a9aefb7f 100644 --- a/includes/helper-functions.php +++ b/includes/helper-functions.php @@ -11,7 +11,10 @@ exit; } +use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_authorization_token; +use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_domain; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_key; +use function KadenceWP\KadenceBlocks\StellarWP\Uplink\is_authorized; /** * Check if we are in AMP Mode. @@ -232,6 +235,27 @@ function kadence_blocks_get_current_license_data(): array { return $cache = $license_data; } +/** + * Whether the current site has an authorized Kadence license. + * + * Checks the legacy StellarWP Uplink license first, then falls back to + * Harbor's unified license as the final check. + * + * @return bool + */ +function kadence_blocks_is_license_authorized(): bool { + $license_key = kadence_blocks_get_current_license_key(); + + if ( ! empty( $license_key ) ) { + $token = get_authorization_token( 'kadence-blocks' ); + if ( is_authorized( $license_key, 'kadence-blocks', $token ?? '', get_license_domain() ) ) { + return true; + } + } + + return lw_harbor_is_product_license_active( 'kadence' ); +} + /** * Check if ai is enabled. */ diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php index 167de0aa8..94adfbb0b 100644 --- a/includes/resources/Harbor/Harbor_Provider.php +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -5,6 +5,9 @@ use KadenceWP\KadenceBlocks\LiquidWeb\Harbor\Config as HarborConfig; use KadenceWP\KadenceBlocks\LiquidWeb\Harbor\Harbor; use KadenceWP\KadenceBlocks\StellarWP\ProphecyMonorepo\Container\Contracts\Provider; +use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_authorization_token; +use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_domain; +use function KadenceWP\KadenceBlocks\StellarWP\Uplink\is_authorized; final class Harbor_Provider extends Provider { @@ -40,16 +43,18 @@ public function report_legacy_licenses( array $licenses ): array { 'kadence-creative-kit' => 'Kadence Creative Kit', ]; - $slug = $data['product'] ?? 'kadence-blocks'; - $name = $product_names[ $slug ] ?? 'Kadence Blocks'; + $slug = $data['product'] ?? 'kadence-blocks'; + $name = $product_names[ $slug ] ?? 'Kadence Blocks'; + $token = get_authorization_token( 'kadence-blocks' ); + $is_active = is_authorized( $data['key'], 'kadence-blocks', $token ?? '', get_license_domain() ); $licenses[] = [ - 'key' => $data['key'], - 'slug' => $slug, - 'name' => $name, - 'product' => 'kadence', - 'is_active' => true, - 'page_url' => admin_url( 'admin.php?page=kadence-blocks-home' ), + 'key' => $data['key'], + 'slug' => $slug, + 'name' => $name, + 'product' => 'kadence', + 'is_active' => $is_active, + 'page_url' => admin_url( 'admin.php?page=kadence-blocks-home' ), ]; return $licenses; diff --git a/includes/settings/class-kadence-blocks-settings.php b/includes/settings/class-kadence-blocks-settings.php index a0cff5889..c50147209 100644 --- a/includes/settings/class-kadence-blocks-settings.php +++ b/includes/settings/class-kadence-blocks-settings.php @@ -9,10 +9,8 @@ exit; } -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_authorization_token; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_disconnect_url; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_domain; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\is_authorized; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\build_auth_url; /** @@ -804,14 +802,10 @@ public function home_scripts() { if ( $network_enabled && function_exists( 'is_plugin_active_for_network' ) && is_plugin_active_for_network( 'kadence-blocks/kadence-blocks.php' ) ) { $using_network_enabled = true; } - $token = get_authorization_token( 'kadence-blocks' ); $auth_url = build_auth_url( apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), get_license_domain() ); $license_key = kadence_blocks_get_current_license_key(); $disconnect_url = ''; - $is_authorized = false; - if ( ! empty( $license_key ) && ! kadence_blocks_is_ai_disabled() ) { - $is_authorized = is_authorized( $license_key, 'kadence-blocks', ( ! empty( $token ) ? $token : '' ), get_license_domain() ); - } + $is_authorized = ! kadence_blocks_is_ai_disabled() && kadence_blocks_is_license_authorized(); if ( $is_authorized ) { $disconnect_url = get_disconnect_url( 'kadence-blocks' ); From 286babd8169e9fa1735465fbc83ea86ef9cc2e03 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Thu, 2 Apr 2026 17:42:31 -0400 Subject: [PATCH 03/19] feature: add uplink filter based notices --- includes/resources/Harbor/Harbor_Provider.php | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php index 94adfbb0b..b00bc4e29 100644 --- a/includes/resources/Harbor/Harbor_Provider.php +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -20,6 +20,51 @@ public function register(): void { lw_harbor_register_submenu( 'kadence-blocks' ); add_filter( 'lw-harbor/legacy_licenses', [ $this, 'report_legacy_licenses' ] ); + + $extensions = [ + 'kadence-blocks' => __( 'Kadence Blocks', 'kadence-blocks' ), + 'kadence-insights' => __( 'Kadence Insights', 'kadence-blocks' ), + ]; + + foreach ( $extensions as $hook_prefix => $product_name ) { + add_action( + "stellarwp/uplink/{$hook_prefix}/license_field_after_form", + function() use ( $product_name ) { + $this->render_harbor_license_notice( $product_name ); + } + ); + } + + if ( class_exists( 'KadenceWP\KadenceBlocksPro\Uplink\Connect' ) ) { + remove_action( 'admin_notices', [ \KadenceWP\KadenceBlocksPro\Uplink\Connect::get_instance(), 'inactive_notice' ] ); + } + } + + /** + * Renders a Harbor notice below the save button on a Kadence Uplink license field. + * + * @param string $product_name The human-readable product name. + * + * @return void + */ + public function render_harbor_license_notice( string $product_name ): void { + $url = lw_harbor_get_license_page_url(); + if ( empty( $url ) ) { + return; + } + ?> +
+

+

Liquid Web Software Manager.', 'kadence-blocks' ), + esc_html( $product_name ), + esc_url( $url ) + ), + [ 'a' => [ 'href' => [] ] ] + ); ?>

+ Date: Thu, 2 Apr 2026 17:51:29 -0400 Subject: [PATCH 04/19] feature: add known kadence plugins using uplink --- includes/resources/Harbor/Harbor_Provider.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php index b00bc4e29..b23e1ed25 100644 --- a/includes/resources/Harbor/Harbor_Provider.php +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -24,6 +24,14 @@ public function register(): void { $extensions = [ 'kadence-blocks' => __( 'Kadence Blocks', 'kadence-blocks' ), 'kadence-insights' => __( 'Kadence Insights', 'kadence-blocks' ), + 'kadence-shop-kit' => __( 'Kadence Shop Kit', 'kadence-blocks' ), + 'kadence-galleries' => __( 'Kadence Galleries', 'kadence-blocks' ), + 'kadence-creative-kit' => __( 'Kadence Creative Kit', 'kadence-blocks' ), + 'kadence-conversions' => __( 'Kadence Conversions', 'kadence-blocks' ), + 'kadence-captcha' => __( 'Kadence Captcha', 'kadence-blocks' ), + 'kadence-theme-pro' => __( 'Kadence Theme Pro', 'kadence-blocks' ), + 'kadence-pattern-hub' => __( 'Kadence Pattern Hub', 'kadence-blocks' ), + 'kadence-white-label' => __( 'Kadence White Label', 'kadence-blocks' ), ]; foreach ( $extensions as $hook_prefix => $product_name ) { From 893cc10bea57c16da07682567901a0a94cf55577 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Fri, 3 Apr 2026 15:14:13 -0400 Subject: [PATCH 05/19] feature: make disabled message dynamic --- includes/assets/js/kb-header-block.min.js | 2 +- includes/class-kadence-blocks-ai-events.php | 2 +- .../class-kadence-blocks-editor-assets.php | 5 ++- includes/helper-functions.php | 42 +++++++++++++++++-- .../class-kadence-blocks-settings.php | 3 +- .../large-banner/disabled-banner.js | 3 +- src/plugins/prebuilt-library/page-list.js | 3 +- src/plugins/prebuilt-library/pattern-list.js | 3 +- 8 files changed, 53 insertions(+), 10 deletions(-) diff --git a/includes/assets/js/kb-header-block.min.js b/includes/assets/js/kb-header-block.min.js index 5a1174340..14410e410 100644 --- a/includes/assets/js/kb-header-block.min.js +++ b/includes/assets/js/kb-header-block.min.js @@ -1 +1 @@ -class KBHeader{components={};_state;root;rootID;autoTransparentSpacing;sticky;stickyTablet;stickyMobile;transparent;transparentTablet;transparentMobile;stickySection;stickySectionTablet;stickySectionMobile;activeSize="mobile";lastScrollTop=0;activeOffsetTop=0;shrinkMain=!1;shrinkMainHeight=0;shrinkMainHeightTablet=0;shrinkMainHeightMobile=0;shrinkStartHeight=0;mobileBreakpoint=0;currentTopPosition=0;anchorOffset=0;placeholderWrapper;stickyWrapper;isSticking=!1;isTransparent=!1;activeHeaderContainer;constructor(a,b={}){this.root="string"==typeof a?document.querySelector(a):a,this.activeHeaderContainer=this.root.querySelector(".wp-block-kadence-header-desktop"),this.rootID="aaa",this.autoTransparentSpacing="1"===this.root.dataset?.autoTransparentSpacing,this.sticky="1"==this.root.dataset?.sticky,this.stickyTablet="1"==this.root.dataset?.stickyTablet,this.stickyMobile="1"==this.root.dataset?.stickyMobile,this.transparent="1"==this.root.dataset?.transparent,this.transparentTablet="1"==this.root.dataset?.transparentTablet,this.transparentMobile="1"==this.root.dataset?.transparentMobile,this.stickySection=this.root.dataset?.stickySection,this.stickySectionTablet=this.root.dataset?.stickySectionTablet,this.stickySectionMobile=this.root.dataset?.stickySectionMobile,this.shrinkMain="1"===this.root.dataset?.shrinkMain,this.shrinkMainHeight=this.root.dataset?.shrinkMainHeight,this.shrinkMainHeightTablet=this.root.dataset?.shrinkMainHeightTablet,this.shrinkMainHeightMobile=this.root.dataset?.shrinkMainHeightMobile,this.revealScrollUp="1"===this.root.dataset?.revealScrollUp,this.mobileBreakpoint=this.root.dataset?.mobileBreakpoint,this._state="CREATED",(this.sticky||this.stickyTablet||this.stickyMobile)&&this.initStickyHeader(),this.mobileBreakpoint&&0!==this.mobileBreakpoint&&this.initMobileBreakpoint();var c=new Event("MOUNTED",{bubbles:!0});c.ID=this.rootID,this.root.dispatchEvent(c),this._state="IDLE"}initMobileBreakpoint(){this.mobileBreakpoint&&0!==this.mobileBreakpoint&&(window.addEventListener("resize",this.updateMobileBreakpoint.bind(this),!1),window.addEventListener("hashchange",this.updateMobileBreakpoint.bind(this),!1),window.addEventListener("scroll",this.updateMobileBreakpoint.bind(this),!1),window.addEventListener("load",this.updateMobileBreakpoint.bind(this),!1),window.addEventListener("orientationchange",this.updateMobileBreakpoint.bind(this)))}updateMobileBreakpoint(){this.setActiveSize(),"desktop"==this.activeSize?(this.root.querySelector(".wp-block-kadence-header-tablet").style.display="none",this.root.querySelector(".wp-block-kadence-header-desktop").style.display="block"):(this.root.querySelector(".wp-block-kadence-header-desktop").style.display="none",this.root.querySelector(".wp-block-kadence-header-tablet").style.display="block")}initStickyHeader(){this.sticky&&this.createAndSetPlaceholderAndStickyWrappers("desktop"),(this.stickyTablet||this.stickyMobile)&&this.createAndSetPlaceholderAndStickyWrappers("tablet"),this.placeholderWrapper&&this.stickyWrapper&&(this.setActiveSize(),this.updatePlaceholderAndStickyWrappers(),"desktop"==this.activeSize?this.sticky&&(this.activeOffsetTop=this.getOffset(this.placeholderWrapper).top):"tablet"==this.activeSize?this.stickyTablet&&(this.activeOffsetTop=this.getOffset(this.placeholderWrapper).top):this.stickyMobile&&(this.activeOffsetTop=this.getOffset(this.placeholderWrapper).top),window.addEventListener("resize",this.updateSticky.bind(this),!1),window.addEventListener("hashchange",this.updateSticky.bind(this),!1),window.addEventListener("scroll",this.updateSticky.bind(this),!1),window.addEventListener("load",this.updateSticky.bind(this),!1),window.addEventListener("orientationchange",this.updateSticky.bind(this)),"complete"===document.readyState&&this.updateSticky("updateActive"),document.body.classList.contains("woocommerce-demo-store")&&document.body.classList.contains("kadence-store-notice-placement-above")&&this.respondToVisibility(document.querySelector(".woocommerce-store-notice"),()=>{this.updateSticky("updateActive").bind(this)}))}setActiveSize(){const a=this.mobileBreakpoint&&0!==this.mobileBreakpoint?this.mobileBreakpoint:kadenceHeaderConfig.breakPoints.desktop;this.activeSize=parseInt(a){b.appendChild(a)})),b}respondToVisibility(a,b){var c={root:document.documentElement},d=new IntersectionObserver(a=>{a.forEach(a=>{b(0 .kb-nav-sub-menu");if(p.length){var q=this.getOffset(p[0]).top;this.stickyWrapper.style.setProperty("--kb-sticky-mega-overflow-header-offset",q-d+"px")}const r=c,s=c-e,t=this.currentTopPosition+e;var u=this.stickyWrapper.parentNode;if(this.shrinkMain){const b="mobile"===this.activeSize?this.shrinkMainHeightMobile:"tablet"===this.activeSize?this.shrinkMainHeightTablet:this.shrinkMainHeight;if(b){const c=this.activeHeaderContainer.querySelectorAll(".kb-img, .wp-block-kadence-identity img, .wp-block-image img"),d=this.activeHeaderContainer.querySelector(".wp-block-kadence-header-row-center .kadence-header-row-inner");(!this.shrinkStartHeight||a&&void 0!==a.type&&"orientationchange"===a.type)&&(this.shrinkStartHeight=d.offsetHeight);const e=Math.max(b,this.shrinkStartHeight-window.scrollY);if(d.style.height=e+"px",d.style.minHeight=e+"px",d.style.maxHeight=e+"px",0==window.scrollY){if(c)for(let a=0;athis.lastScrollTop,w=Math.floor(this.anchorOffset+e);d<=this.anchorOffset-c?(this.currentTopPosition=0,this.setStickyChanged(!1)):d<=w?v?(this.currentTopPosition=0,this.setStickyChanged(!1)):(this.stickyWrapper.classList.remove("item-hidden-above"),this.currentTopPosition=r,this.setStickyChanged(!0)):d>=this.currentTopPosition&&d<=t?this.setStickyChanged(!1):(v?(this.stickyWrapper.classList.add("item-hidden-above"),this.stickyWrapper.style.top=s+"px",this.currentTopPosition=s):(this.stickyWrapper.classList.remove("item-hidden-above"),this.currentTopPosition=r),this.setStickyChanged(!0))}else{var w=Math.floor(this.anchorOffset-c);d<=w?(this.currentTopPosition=0,this.setStickyChanged(!1)):(this.currentTopPosition=r,this.setStickyChanged(!0))}this.lastScrollTop=d,window.scrollY==w?(this.stickyWrapper.classList.add("item-is-fixed"),this.stickyWrapper.classList.add("item-at-start"),this.stickyWrapper.classList.remove("item-is-stuck"),u.classList.add("child-is-fixed"),document.body.classList.add("header-is-fixed")):window.scrollY>w?this.revealScrollUp?window.scrollY{window.KBHeaderBlocks=[];var a=document.querySelectorAll(".wp-block-kadence-header");for(let c=0;c{this.updateSticky("updateActive").bind(this)}))}setActiveSize(){const a=this.mobileBreakpoint&&0!==this.mobileBreakpoint?this.mobileBreakpoint:kadenceHeaderConfig.breakPoints.desktop;this.activeSize=parseInt(a){b.appendChild(a)})),b}respondToVisibility(a,b){var c={root:document.documentElement},d=new IntersectionObserver(a=>{a.forEach(a=>{b(0 .kb-nav-sub-menu");if(p.length){var q=this.getOffset(p[0]).top;this.stickyWrapper.style.setProperty("--kb-sticky-mega-overflow-header-offset",q-d+"px")}const r=c,s=c-e,t=this.currentTopPosition+e;var u=this.stickyWrapper.parentNode;if(this.shrinkMain){const b="mobile"===this.activeSize?this.shrinkMainHeightMobile:"tablet"===this.activeSize?this.shrinkMainHeightTablet:this.shrinkMainHeight;if(b){const c=this.activeHeaderContainer.querySelectorAll(".kb-img, .wp-block-kadence-identity img, .wp-block-image img"),d=this.activeHeaderContainer.querySelector(".wp-block-kadence-header-row-center .kadence-header-row-inner");(!this.shrinkStartHeight||a&&void 0!==a.type&&"orientationchange"===a.type)&&(this.shrinkStartHeight=d.offsetHeight);const e=Math.max(b,this.shrinkStartHeight-window.scrollY);if(d.style.height=e+"px",d.style.minHeight=e+"px",d.style.maxHeight=e+"px",0==window.scrollY){if(c)for(let a=0;athis.lastScrollTop,w=Math.floor(this.anchorOffset+e);d<=this.anchorOffset-c?(this.currentTopPosition=0,this.setStickyChanged(!1)):d<=w?v?(this.currentTopPosition=0,this.setStickyChanged(!1)):(this.stickyWrapper.classList.remove("item-hidden-above"),this.currentTopPosition=r,this.setStickyChanged(!0)):d>=this.currentTopPosition&&d<=t?this.setStickyChanged(!1):(v?(this.stickyWrapper.classList.add("item-hidden-above"),this.stickyWrapper.style.top=s+"px",this.currentTopPosition=s):(this.stickyWrapper.classList.remove("item-hidden-above"),this.currentTopPosition=r),this.setStickyChanged(!0))}else{var w=Math.floor(this.anchorOffset-c);d<=w?(this.currentTopPosition=0,this.setStickyChanged(!1)):(this.currentTopPosition=r,this.setStickyChanged(!0))}this.lastScrollTop=d,window.scrollY==w?(this.stickyWrapper.classList.add("item-is-fixed"),this.stickyWrapper.classList.add("item-at-start"),this.stickyWrapper.classList.remove("item-is-stuck"),u.classList.add("child-is-fixed"),document.body.classList.add("header-is-fixed")):window.scrollY>w?this.revealScrollUp?window.scrollY{window.KBHeaderBlocks=[];var a=document.querySelectorAll(".wp-block-kadence-header");for(let c=0;c $pro_data, 'isAuthorized' => $is_authorized, 'isAIDisabled' => kadence_blocks_is_ai_disabled(), + 'aiDisabledMessage' => kadence_blocks_get_ai_disabled_message(), 'homeLink' => admin_url( 'admin.php?page=kadence-blocks-home' ), 'pro' => ( class_exists( 'Kadence_Blocks_Pro' ) ? 'true' : 'false' ), 'creativeKit' => ( class_exists( 'KadenceWP\CreativeKit' ) ? 'true' : 'false' ), diff --git a/includes/helper-functions.php b/includes/helper-functions.php index 4a9aefb7f..b146069f1 100644 --- a/includes/helper-functions.php +++ b/includes/helper-functions.php @@ -207,7 +207,7 @@ function kadence_blocks_get_current_env() { return 'dev'; case 'https://licensing-staging.stellarwp.com': return 'staging'; - + } } return ''; @@ -244,6 +244,23 @@ function kadence_blocks_get_current_license_data(): array { * @return bool */ function kadence_blocks_is_license_authorized(): bool { + if ( kadence_blocks_is_legacy_license_authorized() ) { + return true; + } + + return lw_harbor_is_product_license_active( 'kadence' ); +} + +/** + * Check if a legacy (Uplink) Kadence license is authorized. + * + * AI features are not currently supported under Harbor licensing, so this + * function gates AI-specific UI and functionality. Harbor-only customers and + * customers with no license will return false. + * + * @return bool + */ +function kadence_blocks_is_legacy_license_authorized(): bool { $license_key = kadence_blocks_get_current_license_key(); if ( ! empty( $license_key ) ) { @@ -253,7 +270,7 @@ function kadence_blocks_is_license_authorized(): bool { } } - return lw_harbor_is_product_license_active( 'kadence' ); + return false; } /** @@ -263,7 +280,26 @@ function kadence_blocks_is_ai_disabled() { if ( defined( 'KADENCE_BLOCKS_AI_DISABLED' ) && KADENCE_BLOCKS_AI_DISABLED ) { return true; } - return false; + + return lw_harbor_is_product_license_active( 'kadence' ); +} + +/** + * Get the message shown when Kadence AI is disabled. + * + * Applies the `kadence_blocks_ai_disabled_message` filter so hosting + * environments (e.g. Harbor) can surface a context-specific reason. + * + * @return string + */ +function kadence_blocks_get_ai_disabled_message(): string { + $message = __( 'Kadence AI is disabled by site admin.', 'kadence-blocks' ); + + if ( lw_harbor_is_product_license_active( 'kadence' ) ) { + $message = __( 'Kadence AI is not yet available with your plan.', 'kadence-blocks' ); + } + + return apply_filters( 'kadence_blocks_ai_disabled_message', $message ); } /** diff --git a/includes/settings/class-kadence-blocks-settings.php b/includes/settings/class-kadence-blocks-settings.php index c50147209..49b059e5c 100644 --- a/includes/settings/class-kadence-blocks-settings.php +++ b/includes/settings/class-kadence-blocks-settings.php @@ -805,7 +805,7 @@ public function home_scripts() { $auth_url = build_auth_url( apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), get_license_domain() ); $license_key = kadence_blocks_get_current_license_key(); $disconnect_url = ''; - $is_authorized = ! kadence_blocks_is_ai_disabled() && kadence_blocks_is_license_authorized(); + $is_authorized = ! kadence_blocks_is_ai_disabled() && kadence_blocks_is_legacy_license_authorized(); if ( $is_authorized ) { $disconnect_url = get_disconnect_url( 'kadence-blocks' ); @@ -845,6 +845,7 @@ public function home_scripts() { 'site_name' => sanitize_title( get_bloginfo( 'name' ) ), 'pSlug' => apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), 'isAIDisabled' => kadence_blocks_is_ai_disabled(), + 'aiDisabledMessage' => kadence_blocks_get_ai_disabled_message(), 'pVersion' => KADENCE_BLOCKS_VERSION, 'isAuthorized' => $is_authorized, 'licenseKey' => $license_key, diff --git a/src/dashboard/components/large-banner/disabled-banner.js b/src/dashboard/components/large-banner/disabled-banner.js index a52896d3c..e97b8edd7 100644 --- a/src/dashboard/components/large-banner/disabled-banner.js +++ b/src/dashboard/components/large-banner/disabled-banner.js @@ -47,7 +47,8 @@ export function DisabledBanner() { )}

- {__('Kadence AI is disabled by site admin.', 'kadence-blocks')} + {window?.kadence_blocks_params?.aiDisabledMessage || + __('Kadence AI is disabled by site admin.', 'kadence-blocks')}

diff --git a/src/plugins/prebuilt-library/page-list.js b/src/plugins/prebuilt-library/page-list.js index d7ba23022..95a780994 100644 --- a/src/plugins/prebuilt-library/page-list.js +++ b/src/plugins/prebuilt-library/page-list.js @@ -528,7 +528,8 @@ function PageList({ return (

- {__('Kadence AI is disabled by site admin.', 'kadence-blocks')} + {window?.kadence_blocks_params?.aiDisabledMessage || + __('Kadence AI is disabled by site admin.', 'kadence-blocks')}

); diff --git a/src/plugins/prebuilt-library/pattern-list.js b/src/plugins/prebuilt-library/pattern-list.js index 0d73653ff..8fb95492f 100644 --- a/src/plugins/prebuilt-library/pattern-list.js +++ b/src/plugins/prebuilt-library/pattern-list.js @@ -1273,7 +1273,8 @@ function PatternList({ return (

- {__('Kadence AI is disabled by site admin.', 'kadence-blocks')} + {window?.kadence_blocks_params?.aiDisabledMessage || + __('Kadence AI is disabled by site admin.', 'kadence-blocks')}

); From 6cfe51df50b526427162ce2883b81753a6354f92 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Fri, 3 Apr 2026 15:32:39 -0400 Subject: [PATCH 06/19] refactor: use filters for disabled bool and message --- includes/helper-functions.php | 13 +++----- includes/resources/Harbor/Harbor_Provider.php | 33 +++++++++++++++++++ .../large-banner/disabled-banner.js | 2 +- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/includes/helper-functions.php b/includes/helper-functions.php index b146069f1..49bd8fe9b 100644 --- a/includes/helper-functions.php +++ b/includes/helper-functions.php @@ -281,7 +281,7 @@ function kadence_blocks_is_ai_disabled() { return true; } - return lw_harbor_is_product_license_active( 'kadence' ); + return (bool) apply_filters( 'kadence_blocks_ai_disabled', false ); } /** @@ -293,13 +293,10 @@ function kadence_blocks_is_ai_disabled() { * @return string */ function kadence_blocks_get_ai_disabled_message(): string { - $message = __( 'Kadence AI is disabled by site admin.', 'kadence-blocks' ); - - if ( lw_harbor_is_product_license_active( 'kadence' ) ) { - $message = __( 'Kadence AI is not yet available with your plan.', 'kadence-blocks' ); - } - - return apply_filters( 'kadence_blocks_ai_disabled_message', $message ); + return apply_filters( + 'kadence_blocks_ai_disabled_message', + __( 'Kadence AI is disabled by site admin.', 'kadence-blocks' ) + ); } /** diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php index b23e1ed25..2afa7c239 100644 --- a/includes/resources/Harbor/Harbor_Provider.php +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -20,6 +20,8 @@ public function register(): void { lw_harbor_register_submenu( 'kadence-blocks' ); add_filter( 'lw-harbor/legacy_licenses', [ $this, 'report_legacy_licenses' ] ); + add_filter( 'kadence_blocks_ai_disabled', [ $this, 'is_ai_disabled' ] ); + add_filter( 'kadence_blocks_ai_disabled_message', [ $this, 'ai_disabled_message' ] ); $extensions = [ 'kadence-blocks' => __( 'Kadence Blocks', 'kadence-blocks' ), @@ -48,6 +50,37 @@ function() use ( $product_name ) { } } + /** + * Disables Kadence AI for Harbor-licensed customers. + * AI features are not yet supported under Harbor licensing. + * + * @param bool $disabled Whether AI is disabled. + * + * @return bool + */ + public function is_ai_disabled( bool $disabled ): bool { + if ( $disabled ) { + return true; + } + + return lw_harbor_is_product_license_active( 'kadence' ); + } + + /** + * Overrides the AI disabled message for Harbor-licensed customers. + * + * @param string $message The default disabled message. + * + * @return string + */ + public function ai_disabled_message( string $message ): string { + if ( lw_harbor_is_product_license_active( 'kadence' ) ) { + return __( 'Kadence AI is not yet available with your plan.', 'kadence-blocks' ); + } + + return $message; + } + /** * Renders a Harbor notice below the save button on a Kadence Uplink license field. * diff --git a/src/dashboard/components/large-banner/disabled-banner.js b/src/dashboard/components/large-banner/disabled-banner.js index e97b8edd7..d57497340 100644 --- a/src/dashboard/components/large-banner/disabled-banner.js +++ b/src/dashboard/components/large-banner/disabled-banner.js @@ -47,7 +47,7 @@ export function DisabledBanner() { )}

- {window?.kadence_blocks_params?.aiDisabledMessage || + {window?.kadenceHomeParams?.aiDisabledMessage || __('Kadence AI is disabled by site admin.', 'kadence-blocks')}

From 897fda1980eba15069209be2c7766f2a1fd166db Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Fri, 3 Apr 2026 15:50:01 -0400 Subject: [PATCH 07/19] refactor: add check for legacy license in disabled message --- includes/resources/Harbor/Harbor_Provider.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php index 2afa7c239..fea1be5dd 100644 --- a/includes/resources/Harbor/Harbor_Provider.php +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -63,6 +63,10 @@ public function is_ai_disabled( bool $disabled ): bool { return true; } + if ( kadence_blocks_is_legacy_license_authorized() ) { + return false; + } + return lw_harbor_is_product_license_active( 'kadence' ); } @@ -74,6 +78,10 @@ public function is_ai_disabled( bool $disabled ): bool { * @return string */ public function ai_disabled_message( string $message ): string { + if ( kadence_blocks_is_legacy_license_authorized() ) { + return $message; + } + if ( lw_harbor_is_product_license_active( 'kadence' ) ) { return __( 'Kadence AI is not yet available with your plan.', 'kadence-blocks' ); } From c4a531109d56921bcfca1708059d8e11b7e3c818 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Mon, 6 Apr 2026 09:27:54 -0400 Subject: [PATCH 08/19] chore: remove unused imports --- includes/init.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/includes/init.php b/includes/init.php index bf13790e5..9635780af 100644 --- a/includes/init.php +++ b/includes/init.php @@ -14,10 +14,6 @@ use KadenceWP\KadenceBlocks\App; use KadenceWP\KadenceBlocks\StellarWP\ContainerContract\ContainerInterface; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_domain; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_authorization_token; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\is_authorized; - /** * Setup the post type options for post blocks. From 7719926de1844cf79f106ae42ccd25e3681aa52c Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Mon, 6 Apr 2026 09:58:41 -0400 Subject: [PATCH 09/19] feature: report all known legacy licenses and supress inactive notices in favor of harbor --- includes/resources/Harbor/Harbor_Provider.php | 161 +++++++++++++----- 1 file changed, 119 insertions(+), 42 deletions(-) diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php index fea1be5dd..ef8b6019b 100644 --- a/includes/resources/Harbor/Harbor_Provider.php +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -8,6 +8,7 @@ use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_authorization_token; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_domain; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\is_authorized; +use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_key; final class Harbor_Provider extends Provider { @@ -23,31 +24,16 @@ public function register(): void { add_filter( 'kadence_blocks_ai_disabled', [ $this, 'is_ai_disabled' ] ); add_filter( 'kadence_blocks_ai_disabled_message', [ $this, 'ai_disabled_message' ] ); - $extensions = [ - 'kadence-blocks' => __( 'Kadence Blocks', 'kadence-blocks' ), - 'kadence-insights' => __( 'Kadence Insights', 'kadence-blocks' ), - 'kadence-shop-kit' => __( 'Kadence Shop Kit', 'kadence-blocks' ), - 'kadence-galleries' => __( 'Kadence Galleries', 'kadence-blocks' ), - 'kadence-creative-kit' => __( 'Kadence Creative Kit', 'kadence-blocks' ), - 'kadence-conversions' => __( 'Kadence Conversions', 'kadence-blocks' ), - 'kadence-captcha' => __( 'Kadence Captcha', 'kadence-blocks' ), - 'kadence-theme-pro' => __( 'Kadence Theme Pro', 'kadence-blocks' ), - 'kadence-pattern-hub' => __( 'Kadence Pattern Hub', 'kadence-blocks' ), - 'kadence-white-label' => __( 'Kadence White Label', 'kadence-blocks' ), - ]; - - foreach ( $extensions as $hook_prefix => $product_name ) { + foreach ( $this->get_known_plugins() as $slug => $plugin ) { add_action( - "stellarwp/uplink/{$hook_prefix}/license_field_after_form", - function() use ( $product_name ) { - $this->render_harbor_license_notice( $product_name ); + "stellarwp/uplink/{$slug}/license_field_after_form", + function() use ( $plugin ) { + $this->render_harbor_license_notice( $plugin['name'] ); } ); } - if ( class_exists( 'KadenceWP\KadenceBlocksPro\Uplink\Connect' ) ) { - remove_action( 'admin_notices', [ \KadenceWP\KadenceBlocksPro\Uplink\Connect::get_instance(), 'inactive_notice' ] ); - } + add_action( 'admin_init', [ $this, 'suppress_legacy_inactive_notices' ] ); } /** @@ -125,33 +111,124 @@ public function render_harbor_license_notice( string $product_name ): void { * @return array */ public function report_legacy_licenses( array $licenses ): array { - $data = kadence_blocks_get_current_license_data(); + $reported_keys = []; + $domain = get_license_domain(); + + foreach ( $this->get_known_plugins() as $slug => $plugin ) { + $key = get_license_key( $slug ); + + if ( empty( $key ) || isset( $reported_keys[ $key ] ) ) { + continue; + } + + $reported_keys[ $key ] = true; + $token = get_authorization_token( $slug ); + $is_active = is_authorized( $key, $slug, $token ?? '', $domain ); + + $licenses[] = [ + 'key' => $key, + 'slug' => $slug, + 'name' => $plugin['name'], + 'product' => 'kadence', + 'is_active' => $is_active, + 'page_url' => esc_url( $plugin['page_url'] ), + ]; + } + + return $licenses; + } - if ( empty( $data['key'] ) ) { - return $licenses; + /** + * Removes legacy "not activated" admin notices from all Kadence add-ons. + * + * Each add-on registers its inactive_notice callback during plugins_loaded, + * which runs after Harbor_Provider::register(). Hooking to admin_init ensures + * all add-on callbacks are already registered before we remove them. + * + * @return void + */ + public function suppress_legacy_inactive_notices(): void { + global $wp_filter; + + if ( empty( $wp_filter['admin_notices'] ) ) { + return; } - $product_names = [ - 'kadence-blocks' => 'Kadence Blocks', - 'kadence-blocks-pro' => 'Kadence Blocks Pro', - 'kadence-creative-kit' => 'Kadence Creative Kit', - ]; + foreach ( $wp_filter['admin_notices']->callbacks as $priority => $callbacks ) { + foreach ( $callbacks as $key => $callback ) { + $function = $callback['function']; - $slug = $data['product'] ?? 'kadence-blocks'; - $name = $product_names[ $slug ] ?? 'Kadence Blocks'; - $token = get_authorization_token( 'kadence-blocks' ); - $is_active = is_authorized( $data['key'], 'kadence-blocks', $token ?? '', get_license_domain() ); - - $licenses[] = [ - 'key' => $data['key'], - 'slug' => $slug, - 'name' => $name, - 'product' => 'kadence', - 'is_active' => $is_active, - 'page_url' => admin_url( 'admin.php?page=kadence-blocks-home' ), - ]; + if ( ! is_array( $function ) + || ! is_object( $function[0] ) + || $function[1] !== 'inactive_notice' + ) { + continue; + } - return $licenses; + if ( strpos( get_class( $function[0] ), 'KadenceWP\\' ) === 0 ) { + unset( $wp_filter['admin_notices']->callbacks[ $priority ][ $key ] ); + } + } + } + } + + /** + * Returns a map of all known Kadence plugin slugs to their metadata. + * + * page_url should be a full URL and should point to the plugin's + * license settings page. + * + * @return array + */ + private function get_known_plugins(): array { + $default_page = admin_url('admin.php?page=kadence-blocks-home'); + + return [ + 'kadence-blocks' => [ + 'name' => __( 'Kadence Blocks', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-blocks-pro' => [ + 'name' => __( 'Kadence Blocks Pro', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-creative-kit' => [ + 'name' => __( 'Kadence Creative Kit', 'kadence-blocks' ), + 'page_url' => admin_url('admin.php?page=kadence-blocks-home&license=show'), + ], + 'kadence-insights' => [ + 'name' => __( 'Kadence Insights', 'kadence-blocks' ), + 'page_url' => admin_url('admin.php?page=kadence-insights-settings&license=show'), + ], + 'kadence-shop-kit' => [ + 'name' => __( 'Kadence Shop Kit', 'kadence-blocks' ), + 'page_url' => admin_url('admin.php?page=kadence-shop-kit-settings&license=show'), + ], + 'kadence-galleries' => [ + 'name' => __( 'Kadence Galleries', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-conversions' => [ + 'name' => __( 'Kadence Conversions', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-captcha' => [ + 'name' => __( 'Kadence Captcha', 'kadence-blocks' ), + 'page_url' => admin_url('admin.php?page=kadence-recaptcha-settings&license=show'), + ], + 'kadence-theme-pro' => [ + 'name' => __( 'Kadence Theme Pro', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-pattern-hub' => [ + 'name' => __( 'Kadence Pattern Hub', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-white-label' => [ + 'name' => __( 'Kadence White Label', 'kadence-blocks' ), + 'page_url' => admin_url('admin.php?page=kadence-white-label-settings') + ], + ]; } } From a6c5614d9fb8b571cdb490b5035ae558e91dcc57 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Mon, 6 Apr 2026 10:05:33 -0400 Subject: [PATCH 10/19] fix: update legacy license auth check to be dynamic based on slug --- includes/helper-functions.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/includes/helper-functions.php b/includes/helper-functions.php index 49bd8fe9b..737611766 100644 --- a/includes/helper-functions.php +++ b/includes/helper-functions.php @@ -264,8 +264,9 @@ function kadence_blocks_is_legacy_license_authorized(): bool { $license_key = kadence_blocks_get_current_license_key(); if ( ! empty( $license_key ) ) { - $token = get_authorization_token( 'kadence-blocks' ); - if ( is_authorized( $license_key, 'kadence-blocks', $token ?? '', get_license_domain() ) ) { + $slug = kadence_blocks_get_current_product_slug(); + $token = get_authorization_token( $slug ); + if ( is_authorized( $license_key, $slug, $token ?? '', get_license_domain() ) ) { return true; } } From f12eb8bf7d7dd369001e09aec28506e59248b267 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Mon, 6 Apr 2026 10:11:05 -0400 Subject: [PATCH 11/19] refactor: update default legacy admin page --- includes/resources/Harbor/Harbor_Provider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php index ef8b6019b..f8bce6fc5 100644 --- a/includes/resources/Harbor/Harbor_Provider.php +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -181,7 +181,7 @@ public function suppress_legacy_inactive_notices(): void { * @return array */ private function get_known_plugins(): array { - $default_page = admin_url('admin.php?page=kadence-blocks-home'); + $default_page = admin_url('admin.php?page=kadence-blocks'); return [ 'kadence-blocks' => [ From ff26aecb7e9a4d1792c9492a9fabd7dabae9017f Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Mon, 6 Apr 2026 11:24:37 -0400 Subject: [PATCH 12/19] refactor: move logic into dedicated actions --- .../Harbor/Actions/Get_Known_Plugins.php | 66 +++++++ .../Actions/Render_Harbor_License_Notice.php | 44 +++++ .../Harbor/Actions/Report_Legacy_Licenses.php | 48 +++++ .../Suppress_Legacy_Inactive_Notices.php | 41 ++++ includes/resources/Harbor/Harbor_Provider.php | 175 +----------------- 5 files changed, 208 insertions(+), 166 deletions(-) create mode 100644 includes/resources/Harbor/Actions/Get_Known_Plugins.php create mode 100644 includes/resources/Harbor/Actions/Render_Harbor_License_Notice.php create mode 100644 includes/resources/Harbor/Actions/Report_Legacy_Licenses.php create mode 100644 includes/resources/Harbor/Actions/Suppress_Legacy_Inactive_Notices.php diff --git a/includes/resources/Harbor/Actions/Get_Known_Plugins.php b/includes/resources/Harbor/Actions/Get_Known_Plugins.php new file mode 100644 index 000000000..a6dc0f1f1 --- /dev/null +++ b/includes/resources/Harbor/Actions/Get_Known_Plugins.php @@ -0,0 +1,66 @@ + + */ + public function __invoke(): array { + $default_page = admin_url( 'admin.php?page=kadence-blocks' ); + + return [ + 'kadence-blocks' => [ + 'name' => __( 'Kadence Blocks', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-blocks-pro' => [ + 'name' => __( 'Kadence Blocks Pro', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-creative-kit' => [ + 'name' => __( 'Kadence Creative Kit', 'kadence-blocks' ), + 'page_url' => admin_url( 'admin.php?page=kadence-blocks-home&license=show' ), + ], + 'kadence-insights' => [ + 'name' => __( 'Kadence Insights', 'kadence-blocks' ), + 'page_url' => admin_url( 'admin.php?page=kadence-insights-settings&license=show' ), + ], + 'kadence-shop-kit' => [ + 'name' => __( 'Kadence Shop Kit', 'kadence-blocks' ), + 'page_url' => admin_url( 'admin.php?page=kadence-shop-kit-settings&license=show' ), + ], + 'kadence-galleries' => [ + 'name' => __( 'Kadence Galleries', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-conversions' => [ + 'name' => __( 'Kadence Conversions', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-captcha' => [ + 'name' => __( 'Kadence Captcha', 'kadence-blocks' ), + 'page_url' => admin_url( 'admin.php?page=kadence-recaptcha-settings&license=show' ), + ], + 'kadence-theme-pro' => [ + 'name' => __( 'Kadence Theme Pro', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-pattern-hub' => [ + 'name' => __( 'Kadence Pattern Hub', 'kadence-blocks' ), + 'page_url' => $default_page, + ], + 'kadence-white-label' => [ + 'name' => __( 'Kadence White Label', 'kadence-blocks' ), + 'page_url' => admin_url( 'admin.php?page=kadence-white-label-settings' ), + ], + ]; + } + +} diff --git a/includes/resources/Harbor/Actions/Render_Harbor_License_Notice.php b/includes/resources/Harbor/Actions/Render_Harbor_License_Notice.php new file mode 100644 index 000000000..e4495ad56 --- /dev/null +++ b/includes/resources/Harbor/Actions/Render_Harbor_License_Notice.php @@ -0,0 +1,44 @@ +product_name = $product_name; + } + + /** + * Renders a Harbor notice below the save button on a Kadence Uplink license field. + * + * @return void + */ + public function __invoke(): void { + $url = lw_harbor_get_license_page_url(); + if ( empty( $url ) ) { + return; + } + ?> +
+

+

Liquid Web Software Manager.', 'kadence-blocks' ), + esc_html( $this->product_name ), + esc_url( $url ) + ), + [ 'a' => [ 'href' => [] ] ] + ); ?>

+ $plugin ) { + $key = get_license_key( $slug ); + + if ( empty( $key ) || isset( $reported_keys[ $key ] ) ) { + continue; + } + + $reported_keys[ $key ] = true; + $token = get_authorization_token( $slug ); + $is_active = is_authorized( $key, $slug, $token ?? '', $domain ); + + $licenses[] = [ + 'key' => $key, + 'slug' => $slug, + 'name' => $plugin['name'], + 'product' => 'kadence', + 'is_active' => $is_active, + 'page_url' => esc_url( $plugin['page_url'] ), + ]; + } + + return $licenses; + } + +} diff --git a/includes/resources/Harbor/Actions/Suppress_Legacy_Inactive_Notices.php b/includes/resources/Harbor/Actions/Suppress_Legacy_Inactive_Notices.php new file mode 100644 index 000000000..95208803e --- /dev/null +++ b/includes/resources/Harbor/Actions/Suppress_Legacy_Inactive_Notices.php @@ -0,0 +1,41 @@ +callbacks as $priority => $callbacks ) { + foreach ( $callbacks as $key => $callback ) { + $function = $callback['function']; + + if ( ! is_array( $function ) + || ! is_object( $function[0] ) + || $function[1] !== 'inactive_notice' + ) { + continue; + } + + if ( strpos( get_class( $function[0] ), 'KadenceWP\\' ) === 0 ) { + unset( $wp_filter['admin_notices']->callbacks[ $priority ][ $key ] ); + } + } + } + } + +} diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php index f8bce6fc5..89158fa05 100644 --- a/includes/resources/Harbor/Harbor_Provider.php +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -2,13 +2,13 @@ namespace KadenceWP\KadenceBlocks\Harbor; +use KadenceWP\KadenceBlocks\Harbor\Actions\Get_Known_Plugins; +use KadenceWP\KadenceBlocks\Harbor\Actions\Render_Harbor_License_Notice; +use KadenceWP\KadenceBlocks\Harbor\Actions\Report_Legacy_Licenses; +use KadenceWP\KadenceBlocks\Harbor\Actions\Suppress_Legacy_Inactive_Notices; use KadenceWP\KadenceBlocks\LiquidWeb\Harbor\Config as HarborConfig; use KadenceWP\KadenceBlocks\LiquidWeb\Harbor\Harbor; use KadenceWP\KadenceBlocks\StellarWP\ProphecyMonorepo\Container\Contracts\Provider; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_authorization_token; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_domain; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\is_authorized; -use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_key; final class Harbor_Provider extends Provider { @@ -20,20 +20,19 @@ public function register(): void { Harbor::init(); lw_harbor_register_submenu( 'kadence-blocks' ); - add_filter( 'lw-harbor/legacy_licenses', [ $this, 'report_legacy_licenses' ] ); + + add_filter( 'lw-harbor/legacy_licenses', new Report_Legacy_Licenses() ); add_filter( 'kadence_blocks_ai_disabled', [ $this, 'is_ai_disabled' ] ); add_filter( 'kadence_blocks_ai_disabled_message', [ $this, 'ai_disabled_message' ] ); - foreach ( $this->get_known_plugins() as $slug => $plugin ) { + foreach ( ( new Get_Known_Plugins() )() as $slug => $plugin ) { add_action( "stellarwp/uplink/{$slug}/license_field_after_form", - function() use ( $plugin ) { - $this->render_harbor_license_notice( $plugin['name'] ); - } + new Render_Harbor_License_Notice( $plugin['name'] ) ); } - add_action( 'admin_init', [ $this, 'suppress_legacy_inactive_notices' ] ); + add_action( 'admin_init', new Suppress_Legacy_Inactive_Notices() ); } /** @@ -75,160 +74,4 @@ public function ai_disabled_message( string $message ): string { return $message; } - /** - * Renders a Harbor notice below the save button on a Kadence Uplink license field. - * - * @param string $product_name The human-readable product name. - * - * @return void - */ - public function render_harbor_license_notice( string $product_name ): void { - $url = lw_harbor_get_license_page_url(); - if ( empty( $url ) ) { - return; - } - ?> -
-

-

Liquid Web Software Manager.', 'kadence-blocks' ), - esc_html( $product_name ), - esc_url( $url ) - ), - [ 'a' => [ 'href' => [] ] ] - ); ?>

- get_known_plugins() as $slug => $plugin ) { - $key = get_license_key( $slug ); - - if ( empty( $key ) || isset( $reported_keys[ $key ] ) ) { - continue; - } - - $reported_keys[ $key ] = true; - $token = get_authorization_token( $slug ); - $is_active = is_authorized( $key, $slug, $token ?? '', $domain ); - - $licenses[] = [ - 'key' => $key, - 'slug' => $slug, - 'name' => $plugin['name'], - 'product' => 'kadence', - 'is_active' => $is_active, - 'page_url' => esc_url( $plugin['page_url'] ), - ]; - } - - return $licenses; - } - - /** - * Removes legacy "not activated" admin notices from all Kadence add-ons. - * - * Each add-on registers its inactive_notice callback during plugins_loaded, - * which runs after Harbor_Provider::register(). Hooking to admin_init ensures - * all add-on callbacks are already registered before we remove them. - * - * @return void - */ - public function suppress_legacy_inactive_notices(): void { - global $wp_filter; - - if ( empty( $wp_filter['admin_notices'] ) ) { - return; - } - - foreach ( $wp_filter['admin_notices']->callbacks as $priority => $callbacks ) { - foreach ( $callbacks as $key => $callback ) { - $function = $callback['function']; - - if ( ! is_array( $function ) - || ! is_object( $function[0] ) - || $function[1] !== 'inactive_notice' - ) { - continue; - } - - if ( strpos( get_class( $function[0] ), 'KadenceWP\\' ) === 0 ) { - unset( $wp_filter['admin_notices']->callbacks[ $priority ][ $key ] ); - } - } - } - } - - /** - * Returns a map of all known Kadence plugin slugs to their metadata. - * - * page_url should be a full URL and should point to the plugin's - * license settings page. - * - * @return array - */ - private function get_known_plugins(): array { - $default_page = admin_url('admin.php?page=kadence-blocks'); - - return [ - 'kadence-blocks' => [ - 'name' => __( 'Kadence Blocks', 'kadence-blocks' ), - 'page_url' => $default_page, - ], - 'kadence-blocks-pro' => [ - 'name' => __( 'Kadence Blocks Pro', 'kadence-blocks' ), - 'page_url' => $default_page, - ], - 'kadence-creative-kit' => [ - 'name' => __( 'Kadence Creative Kit', 'kadence-blocks' ), - 'page_url' => admin_url('admin.php?page=kadence-blocks-home&license=show'), - ], - 'kadence-insights' => [ - 'name' => __( 'Kadence Insights', 'kadence-blocks' ), - 'page_url' => admin_url('admin.php?page=kadence-insights-settings&license=show'), - ], - 'kadence-shop-kit' => [ - 'name' => __( 'Kadence Shop Kit', 'kadence-blocks' ), - 'page_url' => admin_url('admin.php?page=kadence-shop-kit-settings&license=show'), - ], - 'kadence-galleries' => [ - 'name' => __( 'Kadence Galleries', 'kadence-blocks' ), - 'page_url' => $default_page, - ], - 'kadence-conversions' => [ - 'name' => __( 'Kadence Conversions', 'kadence-blocks' ), - 'page_url' => $default_page, - ], - 'kadence-captcha' => [ - 'name' => __( 'Kadence Captcha', 'kadence-blocks' ), - 'page_url' => admin_url('admin.php?page=kadence-recaptcha-settings&license=show'), - ], - 'kadence-theme-pro' => [ - 'name' => __( 'Kadence Theme Pro', 'kadence-blocks' ), - 'page_url' => $default_page, - ], - 'kadence-pattern-hub' => [ - 'name' => __( 'Kadence Pattern Hub', 'kadence-blocks' ), - 'page_url' => $default_page, - ], - 'kadence-white-label' => [ - 'name' => __( 'Kadence White Label', 'kadence-blocks' ), - 'page_url' => admin_url('admin.php?page=kadence-white-label-settings') - ], - ]; - } - } From 3cb8d06f751318b8264a8254ed119d1c8641cf43 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Wed, 8 Apr 2026 08:25:34 -0400 Subject: [PATCH 13/19] feature: add isAIHidden and hide banner --- includes/class-kadence-blocks-editor-assets.php | 2 +- includes/resources/Harbor/Harbor_Provider.php | 17 ++++++++++++++++- .../settings/class-kadence-blocks-settings.php | 7 ++++--- src/dashboard/index.js | 3 ++- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/includes/class-kadence-blocks-editor-assets.php b/includes/class-kadence-blocks-editor-assets.php index 6963f6426..745430724 100644 --- a/includes/class-kadence-blocks-editor-assets.php +++ b/includes/class-kadence-blocks-editor-assets.php @@ -313,7 +313,7 @@ public function editor_assets_variables() { 'numberposts' => 4, 'post_type' => 'product', 'fields' => 'ids', - ] + ] ); $prophecy_data = json_decode( get_option( 'kadence_blocks_prophecy' ), true ); wp_localize_script( diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php index 89158fa05..3fbd08026 100644 --- a/includes/resources/Harbor/Harbor_Provider.php +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -24,6 +24,7 @@ public function register(): void { add_filter( 'lw-harbor/legacy_licenses', new Report_Legacy_Licenses() ); add_filter( 'kadence_blocks_ai_disabled', [ $this, 'is_ai_disabled' ] ); add_filter( 'kadence_blocks_ai_disabled_message', [ $this, 'ai_disabled_message' ] ); + add_filter( 'kadence_blocks_ai_hidden', [ $this, 'is_ai_hidden' ] ); foreach ( ( new Get_Known_Plugins() )() as $slug => $plugin ) { add_action( @@ -52,7 +53,7 @@ public function is_ai_disabled( bool $disabled ): bool { return false; } - return lw_harbor_is_product_license_active( 'kadence' ); + return true; } /** @@ -74,4 +75,18 @@ public function ai_disabled_message( string $message ): string { return $message; } + /** + * Filters the AI hidden state for Harbor-licensed customers. + * + * @param bool $hidden Whether AI is hidden. + * + * @return bool + */ + public function is_ai_hidden( bool $hidden ): bool { + if ( kadence_blocks_is_legacy_license_authorized() ) { + return false; + } + + return true; + } } diff --git a/includes/settings/class-kadence-blocks-settings.php b/includes/settings/class-kadence-blocks-settings.php index 49b059e5c..8a1dce16a 100644 --- a/includes/settings/class-kadence-blocks-settings.php +++ b/includes/settings/class-kadence-blocks-settings.php @@ -586,7 +586,7 @@ public function add_color_palette_css_to_block_editor(array $settings) { private function get_color_palette_css() { $palette = json_decode( get_option( 'kadence_blocks_colors' ) ); - + if ( $palette && is_object( $palette ) && isset( $palette->palette ) && is_array( $palette->palette ) ) { $san_palette = []; foreach ( $palette->palette as $item ) { @@ -845,6 +845,7 @@ public function home_scripts() { 'site_name' => sanitize_title( get_bloginfo( 'name' ) ), 'pSlug' => apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), 'isAIDisabled' => kadence_blocks_is_ai_disabled(), + 'isAIHidden' => (bool) apply_filters( 'kadence_blocks_ai_hidden', false ), 'aiDisabledMessage' => kadence_blocks_get_ai_disabled_message(), 'pVersion' => KADENCE_BLOCKS_VERSION, 'isAuthorized' => $is_authorized, @@ -1218,7 +1219,7 @@ public function load_fonts_local_callback() { echo ''; echo ''; } - + /** * Outputs admin bar settings field */ @@ -1490,7 +1491,7 @@ public function blocks_array() { 'linkText' => __( 'Manage Lottie Animations', 'kadence-blocks' ), ], 'kadence/vector' => [ - 'slug' => 'kadence/vector', + 'slug' => 'kadence/vector', 'name' => __( 'Vector Graphics', 'kadence-blocks' ), 'desc' => __( 'Add custom vector icons and SVGs to enhance your site design.', 'kadence-blocks' ), 'link' => admin_url( 'edit.php?post_type=kadence_vector' ), diff --git a/src/dashboard/index.js b/src/dashboard/index.js index 972bedf1b..d2fd1d1a7 100644 --- a/src/dashboard/index.js +++ b/src/dashboard/index.js @@ -33,6 +33,7 @@ export default function KadenceBlocksHome() { const isNetworkAdmin = kadenceHomeParams.isNetworkAdmin ? true : false; const isNetworkEnabled = kadenceHomeParams.isNetworkEnabled ? true : false; const isAIDisabled = kadenceHomeParams.isAIDisabled ? true : false; + const isAIHidden = kadenceHomeParams.isAIHidden ? true : false; const hasPro = window?.kadenceHomeParams?.pro && kadenceHomeParams.pro === 'true' ? true : false; const showControls = (isNetworkAdmin && isNetworkEnabled) || (!isNetworkAdmin && !isNetworkEnabled) ? true : false; @@ -136,7 +137,7 @@ export default function KadenceBlocksHome() { if (isAIDisabled) { return ( <> - + {!isAIHidden && }
From ebdd82923e9ace25a5dbcb2ba58413bc5292a2f1 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Tue, 14 Apr 2026 11:00:20 -0400 Subject: [PATCH 14/19] feature: add home banner config --- composer.lock | 381 +++++++++--------- includes/resources/Harbor/Harbor_Provider.php | 36 -- .../Home/Banner_Config_View_Model.php | 62 +++ .../class-kadence-blocks-settings.php | 8 +- .../components/large-banner/ai-banner.js | 175 ++++++++ .../components/large-banner/large-banner.scss | 25 ++ src/dashboard/constants.js | 21 - src/dashboard/index.js | 14 +- 8 files changed, 468 insertions(+), 254 deletions(-) create mode 100644 includes/resources/Home/Banner_Config_View_Model.php create mode 100644 src/dashboard/components/large-banner/ai-banner.js diff --git a/composer.lock b/composer.lock index 6e65a13ac..fde95996b 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "adbario/php-dot-notation", - "version": "3.3.0", + "version": "3.5.0", "source": { "type": "git", "url": "https://github.com/adbario/php-dot-notation.git", - "reference": "a94ce4493d19ea430baa8d7d210a2c9bd7129fc2" + "reference": "aa09db5a7a365a8d2d8dd7edfa3cd501d1a8acb0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/a94ce4493d19ea430baa8d7d210a2c9bd7129fc2", - "reference": "a94ce4493d19ea430baa8d7d210a2c9bd7129fc2", + "url": "https://api.github.com/repos/adbario/php-dot-notation/zipball/aa09db5a7a365a8d2d8dd7edfa3cd501d1a8acb0", + "reference": "aa09db5a7a365a8d2d8dd7edfa3cd501d1a8acb0", "shasum": "" }, "require": { @@ -25,7 +25,7 @@ "php": "^7.4 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.8", + "phpstan/phpstan": "^2.1", "phpunit/phpunit": "^9.5", "squizlabs/php_codesniffer": "^3.7" }, @@ -56,9 +56,9 @@ ], "support": { "issues": "https://github.com/adbario/php-dot-notation/issues", - "source": "https://github.com/adbario/php-dot-notation/tree/3.3.0" + "source": "https://github.com/adbario/php-dot-notation/tree/3.5.0" }, - "time": "2023-02-24T20:27:50+00:00" + "time": "2026-04-04T04:29:49+00:00" }, { "name": "composer/installers", @@ -873,16 +873,16 @@ }, { "name": "stellarwp/arrays", - "version": "1.3.1", + "version": "1.3.2", "source": { "type": "git", "url": "https://github.com/stellarwp/arrays.git", - "reference": "315a9b2018ac6f2475a346c89b1d7120ae07c218" + "reference": "e994abcdb5d76fb5fdea7f2e1549d0603c13f91e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stellarwp/arrays/zipball/315a9b2018ac6f2475a346c89b1d7120ae07c218", - "reference": "315a9b2018ac6f2475a346c89b1d7120ae07c218", + "url": "https://api.github.com/repos/stellarwp/arrays/zipball/e994abcdb5d76fb5fdea7f2e1549d0603c13f91e", + "reference": "e994abcdb5d76fb5fdea7f2e1549d0603c13f91e", "shasum": "" }, "require-dev": { @@ -914,10 +914,9 @@ ], "description": "A library for array manipulation.", "support": { - "issues": "https://github.com/stellarwp/arrays/issues", - "source": "https://github.com/stellarwp/arrays/tree/1.3.1" + "source": "https://github.com/stellarwp/arrays/tree/1.3.2" }, - "time": "2025-02-07T18:23:13+00:00" + "time": "2026-02-12T19:58:13+00:00" }, { "name": "stellarwp/container-contract", @@ -968,16 +967,16 @@ }, { "name": "stellarwp/db", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/stellarwp/db.git", - "reference": "f92d6ae0bcd74a3f526b023bb2d6ecd13227ef96" + "reference": "34d6c66adf323f4839c2199d6e1119c79fc87a4f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stellarwp/db/zipball/f92d6ae0bcd74a3f526b023bb2d6ecd13227ef96", - "reference": "f92d6ae0bcd74a3f526b023bb2d6ecd13227ef96", + "url": "https://api.github.com/repos/stellarwp/db/zipball/34d6c66adf323f4839c2199d6e1119c79fc87a4f", + "reference": "34d6c66adf323f4839c2199d6e1119c79fc87a4f", "shasum": "" }, "require-dev": { @@ -1018,9 +1017,9 @@ "description": "A WPDB wrapper and query builder library.", "support": { "issues": "https://github.com/stellarwp/db/issues", - "source": "https://github.com/stellarwp/db/tree/1.2.0" + "source": "https://github.com/stellarwp/db/tree/1.3.0" }, - "time": "2025-11-10T10:55:50+00:00" + "time": "2026-02-25T17:01:46+00:00" }, { "name": "stellarwp/harbor", @@ -1028,12 +1027,12 @@ "source": { "type": "git", "url": "https://github.com/stellarwp/harbor.git", - "reference": "f59c6d9c46f304383bf2cadb29fe3e0b5d1ac96e" + "reference": "4c544035647abf05b0e289e9e420ee1dde918ce5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stellarwp/harbor/zipball/f59c6d9c46f304383bf2cadb29fe3e0b5d1ac96e", - "reference": "f59c6d9c46f304383bf2cadb29fe3e0b5d1ac96e", + "url": "https://api.github.com/repos/stellarwp/harbor/zipball/4c544035647abf05b0e289e9e420ee1dde918ce5", + "reference": "4c544035647abf05b0e289e9e420ee1dde918ce5", "shasum": "" }, "require": { @@ -1044,7 +1043,7 @@ "psr/http-factory": "^1.0", "psr/http-message": "^1.1", "stellarwp/container-contract": "^1.0", - "stellarwp/licensing-api-client-wordpress": "^0.9" + "stellarwp/licensing-api-client-wordpress": "^0.10" }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^1", @@ -1091,20 +1090,20 @@ "issues": "https://github.com/stellarwp/harbor/issues", "source": "https://github.com/stellarwp/harbor/tree/main" }, - "time": "2026-04-02T16:22:47+00:00" + "time": "2026-04-10T19:57:45+00:00" }, { "name": "stellarwp/licensing-api-client", - "version": "0.9.3", + "version": "0.10.0", "source": { "type": "git", "url": "https://github.com/stellarwp/licensing-api-client.git", - "reference": "0ed1a9caf57889f864fcb8636dad6ecfbdb86f6e" + "reference": "ac91bde0f9655cea43ff2f80cba588d05af24928" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stellarwp/licensing-api-client/zipball/0ed1a9caf57889f864fcb8636dad6ecfbdb86f6e", - "reference": "0ed1a9caf57889f864fcb8636dad6ecfbdb86f6e", + "url": "https://api.github.com/repos/stellarwp/licensing-api-client/zipball/ac91bde0f9655cea43ff2f80cba588d05af24928", + "reference": "ac91bde0f9655cea43ff2f80cba588d05af24928", "shasum": "" }, "require": { @@ -1131,28 +1130,28 @@ ], "description": "A PHP client for the Liquid Web Licensing API.", "support": { - "source": "https://github.com/stellarwp/licensing-api-client/tree/0.9.3" + "source": "https://github.com/stellarwp/licensing-api-client/tree/0.10.0" }, - "time": "2026-04-02T17:34:33+00:00" + "time": "2026-04-08T22:33:46+00:00" }, { "name": "stellarwp/licensing-api-client-wordpress", - "version": "0.9.3", + "version": "0.10.0", "source": { "type": "git", "url": "https://github.com/stellarwp/licensing-api-client-wordpress.git", - "reference": "9b2b181ff25887363b4a372ea54a67b2ffeb6245" + "reference": "53aed5017df9458d6cea86c22179c868f940ea34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stellarwp/licensing-api-client-wordpress/zipball/9b2b181ff25887363b4a372ea54a67b2ffeb6245", - "reference": "9b2b181ff25887363b4a372ea54a67b2ffeb6245", + "url": "https://api.github.com/repos/stellarwp/licensing-api-client-wordpress/zipball/53aed5017df9458d6cea86c22179c868f940ea34", + "reference": "53aed5017df9458d6cea86c22179c868f940ea34", "shasum": "" }, "require": { "nyholm/psr7": "^1.8", "php": ">=7.4", - "stellarwp/licensing-api-client": "^0.9.3" + "stellarwp/licensing-api-client": "^0.10" }, "type": "library", "extra": { @@ -1171,9 +1170,9 @@ ], "description": "WordPress transport and factory integration for the Liquid Web Licensing API client.", "support": { - "source": "https://github.com/stellarwp/licensing-api-client-wordpress/tree/0.9.3" + "source": "https://github.com/stellarwp/licensing-api-client-wordpress/tree/0.10.0" }, - "time": "2026-04-02T17:37:04+00:00" + "time": "2026-04-08T22:38:37+00:00" }, { "name": "stellarwp/prophecy-container", @@ -1450,16 +1449,16 @@ }, { "name": "stellarwp/telemetry", - "version": "2.3.4", + "version": "2.4.1", "source": { "type": "git", "url": "https://github.com/stellarwp/telemetry.git", - "reference": "74c7b819d574aa5fc1392f982fb32cedc18d4c6f" + "reference": "c1b3a43359475460a17589dd0442310a81f51b24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/stellarwp/telemetry/zipball/74c7b819d574aa5fc1392f982fb32cedc18d4c6f", - "reference": "74c7b819d574aa5fc1392f982fb32cedc18d4c6f", + "url": "https://api.github.com/repos/stellarwp/telemetry/zipball/c1b3a43359475460a17589dd0442310a81f51b24", + "reference": "c1b3a43359475460a17589dd0442310a81f51b24", "shasum": "" }, "require": { @@ -1493,9 +1492,9 @@ "description": "Telemetry library for StellarWP plugins.", "support": { "issues": "https://github.com/stellarwp/telemetry/issues", - "source": "https://github.com/stellarwp/telemetry/tree/2.3.4" + "source": "https://github.com/stellarwp/telemetry/tree/2.4.1" }, - "time": "2025-04-25T18:58:09+00:00" + "time": "2026-04-10T15:47:09+00:00" }, { "name": "stellarwp/uplink", @@ -3173,27 +3172,27 @@ }, { "name": "brain/monkey", - "version": "2.6.2", + "version": "2.7.0", "source": { "type": "git", "url": "https://github.com/Brain-WP/BrainMonkey.git", - "reference": "d95a9d895352c30f47604ad1b825ab8fa9d1a373" + "reference": "ea3aeb3d559ba3c0930b3f4d210b665a4c044d83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Brain-WP/BrainMonkey/zipball/d95a9d895352c30f47604ad1b825ab8fa9d1a373", - "reference": "d95a9d895352c30f47604ad1b825ab8fa9d1a373", + "url": "https://api.github.com/repos/Brain-WP/BrainMonkey/zipball/ea3aeb3d559ba3c0930b3f4d210b665a4c044d83", + "reference": "ea3aeb3d559ba3c0930b3f4d210b665a4c044d83", "shasum": "" }, "require": { "antecedent/patchwork": "^2.1.17", - "mockery/mockery": "^1.3.5 || ^1.4.4", + "mockery/mockery": "~1.3.6 || ~1.4.4 || ~1.5.1 || ^1.6.10", "php": ">=5.6.0" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7.1", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0.0", "phpcompatibility/php-compatibility": "^9.3.0", - "phpunit/phpunit": "^5.7.26 || ^6.0 || ^7.0 || >=8.0 <8.5.12 || ^8.5.14 || ^9.0" + "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.49 || ^9.6.30" }, "type": "library", "extra": { @@ -3239,7 +3238,7 @@ "issues": "https://github.com/Brain-WP/BrainMonkey/issues", "source": "https://github.com/Brain-WP/BrainMonkey" }, - "time": "2024-08-29T20:15:04+00:00" + "time": "2026-02-05T09:22:14+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -3973,16 +3972,16 @@ }, { "name": "composer/ca-bundle", - "version": "1.5.10", + "version": "1.5.11", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63" + "reference": "68ff39175e8e94a4bb1d259407ce51a6a60f09e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/961a5e4056dd2e4a2eedcac7576075947c28bf63", - "reference": "961a5e4056dd2e4a2eedcac7576075947c28bf63", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/68ff39175e8e94a4bb1d259407ce51a6a60f09e6", + "reference": "68ff39175e8e94a4bb1d259407ce51a6a60f09e6", "shasum": "" }, "require": { @@ -4029,7 +4028,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.10" + "source": "https://github.com/composer/ca-bundle/tree/1.5.11" }, "funding": [ { @@ -4041,20 +4040,20 @@ "type": "github" } ], - "time": "2025-12-08T15:06:51+00:00" + "time": "2026-03-30T09:16:10+00:00" }, { "name": "composer/class-map-generator", - "version": "1.7.1", + "version": "1.7.2", "source": { "type": "git", "url": "https://github.com/composer/class-map-generator.git", - "reference": "8f5fa3cc214230e71f54924bd0197a3bcc705eb1" + "reference": "6a9c2f0970022ab00dc58c07d0685dd712f2231b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/class-map-generator/zipball/8f5fa3cc214230e71f54924bd0197a3bcc705eb1", - "reference": "8f5fa3cc214230e71f54924bd0197a3bcc705eb1", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/6a9c2f0970022ab00dc58c07d0685dd712f2231b", + "reference": "6a9c2f0970022ab00dc58c07d0685dd712f2231b", "shasum": "" }, "require": { @@ -4098,7 +4097,7 @@ ], "support": { "issues": "https://github.com/composer/class-map-generator/issues", - "source": "https://github.com/composer/class-map-generator/tree/1.7.1" + "source": "https://github.com/composer/class-map-generator/tree/1.7.2" }, "funding": [ { @@ -4110,20 +4109,20 @@ "type": "github" } ], - "time": "2025-12-29T13:15:25+00:00" + "time": "2026-03-30T15:36:56+00:00" }, { "name": "composer/composer", - "version": "2.9.3", + "version": "2.9.5", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "fb3bee27676fd852a8a11ebbb1de19b4dada5aba" + "reference": "72a8f8e653710e18d83e5dd531eb5a71fc3223e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/fb3bee27676fd852a8a11ebbb1de19b4dada5aba", - "reference": "fb3bee27676fd852a8a11ebbb1de19b4dada5aba", + "url": "https://api.github.com/repos/composer/composer/zipball/72a8f8e653710e18d83e5dd531eb5a71fc3223e6", + "reference": "72a8f8e653710e18d83e5dd531eb5a71fc3223e6", "shasum": "" }, "require": { @@ -4211,7 +4210,7 @@ "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", "security": "https://github.com/composer/composer/security/policy", - "source": "https://github.com/composer/composer/tree/2.9.3" + "source": "https://github.com/composer/composer/tree/2.9.5" }, "funding": [ { @@ -4223,7 +4222,7 @@ "type": "github" } ], - "time": "2025-12-30T12:40:17+00:00" + "time": "2026-01-29T10:40:53+00:00" }, { "name": "composer/metadata-minifier", @@ -4452,24 +4451,24 @@ }, { "name": "composer/spdx-licenses", - "version": "1.5.9", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f" + "reference": "5ecd0cb4177696f9fd48f1605dda81db3dee7889" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/edf364cefe8c43501e21e88110aac10b284c3c9f", - "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/5ecd0cb4177696f9fd48f1605dda81db3dee7889", + "reference": "5ecd0cb4177696f9fd48f1605dda81db3dee7889", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^7.2 || ^8.0" }, "require-dev": { "phpstan/phpstan": "^1.11", - "symfony/phpunit-bridge": "^3 || ^7" + "symfony/phpunit-bridge": "^6.4.25 || ^7.3.3 || ^8.0" }, "type": "library", "extra": { @@ -4512,7 +4511,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/spdx-licenses/issues", - "source": "https://github.com/composer/spdx-licenses/tree/1.5.9" + "source": "https://github.com/composer/spdx-licenses/tree/1.6.0" }, "funding": [ { @@ -4522,13 +4521,9 @@ { "url": "https://github.com/composer", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" } ], - "time": "2025-05-12T21:07:07+00:00" + "time": "2026-04-08T20:18:39+00:00" }, { "name": "composer/xdebug-handler", @@ -5036,16 +5031,16 @@ }, { "name": "gettext/languages", - "version": "2.12.1", + "version": "2.12.2", "source": { "type": "git", "url": "https://github.com/php-gettext/Languages.git", - "reference": "0b0b0851c55168e1dfb14305735c64019732b5f1" + "reference": "079d6f4842cbcbf5673a70d8e93169a684e7aadd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-gettext/Languages/zipball/0b0b0851c55168e1dfb14305735c64019732b5f1", - "reference": "0b0b0851c55168e1dfb14305735c64019732b5f1", + "url": "https://api.github.com/repos/php-gettext/Languages/zipball/079d6f4842cbcbf5673a70d8e93169a684e7aadd", + "reference": "079d6f4842cbcbf5673a70d8e93169a684e7aadd", "shasum": "" }, "require": { @@ -5095,7 +5090,7 @@ ], "support": { "issues": "https://github.com/php-gettext/Languages/issues", - "source": "https://github.com/php-gettext/Languages/tree/2.12.1" + "source": "https://github.com/php-gettext/Languages/tree/2.12.2" }, "funding": [ { @@ -5107,7 +5102,7 @@ "type": "github" } ], - "time": "2025-03-19T11:14:02+00:00" + "time": "2026-02-23T14:05:50+00:00" }, { "name": "guzzlehttp/guzzle", @@ -5320,16 +5315,16 @@ }, { "name": "guzzlehttp/psr7", - "version": "2.8.0", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "21dc724a0583619cd1652f673303492272778051" + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", - "reference": "21dc724a0583619cd1652f673303492272778051", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/7d0ed42f28e42d61352a7a79de682e5e67fec884", + "reference": "7d0ed42f28e42d61352a7a79de682e5e67fec884", "shasum": "" }, "require": { @@ -5345,6 +5340,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", "http-interop/http-factory-tests": "0.9.0", + "jshttp/mime-db": "1.54.0.1", "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { @@ -5416,7 +5412,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.8.0" + "source": "https://github.com/guzzle/psr7/tree/2.9.0" }, "funding": [ { @@ -5432,7 +5428,7 @@ "type": "tidelift" } ], - "time": "2025-08-23T21:21:41+00:00" + "time": "2026-03-10T16:41:02+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -5703,16 +5699,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "6.6.4", + "version": "6.8.0", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "2eeb75d21cf73211335888e7f5e6fd7440723ec7" + "reference": "89ac92bcfe5d0a8a4433c7b89d394553ae7250cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/2eeb75d21cf73211335888e7f5e6fd7440723ec7", - "reference": "2eeb75d21cf73211335888e7f5e6fd7440723ec7", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/89ac92bcfe5d0a8a4433c7b89d394553ae7250cc", + "reference": "89ac92bcfe5d0a8a4433c7b89d394553ae7250cc", "shasum": "" }, "require": { @@ -5772,9 +5768,9 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.4" + "source": "https://github.com/jsonrainbow/json-schema/tree/6.8.0" }, - "time": "2025-12-19T15:01:32+00:00" + "time": "2026-04-02T12:43:11+00:00" }, { "name": "lucatume/wp-browser", @@ -5962,16 +5958,16 @@ }, { "name": "mck89/peast", - "version": "v1.17.4", + "version": "v1.17.5", "source": { "type": "git", "url": "https://github.com/mck89/peast.git", - "reference": "c6a63f32410d2e4ee2cd20fe94b35af147fb852d" + "reference": "e19a8bd896b7f04941a38fd38a140c9a6531c84f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mck89/peast/zipball/c6a63f32410d2e4ee2cd20fe94b35af147fb852d", - "reference": "c6a63f32410d2e4ee2cd20fe94b35af147fb852d", + "url": "https://api.github.com/repos/mck89/peast/zipball/e19a8bd896b7f04941a38fd38a140c9a6531c84f", + "reference": "e19a8bd896b7f04941a38fd38a140c9a6531c84f", "shasum": "" }, "require": { @@ -5984,7 +5980,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.17.4-dev" + "dev-master": "1.17.5-dev" } }, "autoload": { @@ -6005,9 +6001,9 @@ "description": "Peast is PHP library that generates AST for JavaScript code", "support": { "issues": "https://github.com/mck89/peast/issues", - "source": "https://github.com/mck89/peast/tree/v1.17.4" + "source": "https://github.com/mck89/peast/tree/v1.17.5" }, - "time": "2025-10-10T12:53:17+00:00" + "time": "2026-03-15T10:47:07+00:00" }, { "name": "mikehaertl/php-shellcommand", @@ -7047,16 +7043,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.3.1", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374" + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/16dbf9937da8d4528ceb2145c9c7c0bd29e26374", - "reference": "16dbf9937da8d4528ceb2145c9c7c0bd29e26374", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", "shasum": "" }, "require": { @@ -7088,9 +7084,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.1" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" }, - "time": "2026-01-12T11:33:04+00:00" + "time": "2026-01-25T14:56:51+00:00" }, { "name": "phpunit/php-code-coverage", @@ -7413,16 +7409,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.31", + "version": "9.6.34", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "945d0b7f346a084ce5549e95289962972c4272e5" + "reference": "b36f02317466907a230d3aa1d34467041271ef4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/945d0b7f346a084ce5549e95289962972c4272e5", - "reference": "945d0b7f346a084ce5549e95289962972c4272e5", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b36f02317466907a230d3aa1d34467041271ef4a", + "reference": "b36f02317466907a230d3aa1d34467041271ef4a", "shasum": "" }, "require": { @@ -7444,7 +7440,7 @@ "phpunit/php-timer": "^5.0.3", "sebastian/cli-parser": "^1.0.2", "sebastian/code-unit": "^1.0.8", - "sebastian/comparator": "^4.0.9", + "sebastian/comparator": "^4.0.10", "sebastian/diff": "^4.0.6", "sebastian/environment": "^5.1.5", "sebastian/exporter": "^4.0.8", @@ -7496,7 +7492,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.31" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.34" }, "funding": [ { @@ -7520,7 +7516,7 @@ "type": "tidelift" } ], - "time": "2025-12-06T07:45:52+00:00" + "time": "2026-01-27T05:45:00+00:00" }, { "name": "psr/clock", @@ -8023,16 +8019,16 @@ }, { "name": "sebastian/comparator", - "version": "4.0.9", + "version": "4.0.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5" + "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5", - "reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e4df00b9b3571187db2831ae9aada2c6efbd715d", + "reference": "e4df00b9b3571187db2831ae9aada2c6efbd715d", "shasum": "" }, "require": { @@ -8085,7 +8081,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9" + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.10" }, "funding": [ { @@ -8105,7 +8101,7 @@ "type": "tidelift" } ], - "time": "2025-08-10T06:51:50+00:00" + "time": "2026-01-24T09:22:56+00:00" }, { "name": "sebastian/complexity", @@ -11076,16 +11072,16 @@ }, { "name": "wp-cli/eval-command", - "version": "v2.2.7", + "version": "v2.2.9", "source": { "type": "git", "url": "https://github.com/wp-cli/eval-command.git", - "reference": "2fb2a9d40861741eafaa1df86ed0dbd62de6e5ca" + "reference": "827c7208c74ebd6ab81c6051f515381d4f276e32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/eval-command/zipball/2fb2a9d40861741eafaa1df86ed0dbd62de6e5ca", - "reference": "2fb2a9d40861741eafaa1df86ed0dbd62de6e5ca", + "url": "https://api.github.com/repos/wp-cli/eval-command/zipball/827c7208c74ebd6ab81c6051f515381d4f276e32", + "reference": "827c7208c74ebd6ab81c6051f515381d4f276e32", "shasum": "" }, "require": { @@ -11128,22 +11124,22 @@ "homepage": "https://github.com/wp-cli/eval-command", "support": { "issues": "https://github.com/wp-cli/eval-command/issues", - "source": "https://github.com/wp-cli/eval-command/tree/v2.2.7" + "source": "https://github.com/wp-cli/eval-command/tree/v2.2.9" }, - "time": "2025-12-02T18:17:50+00:00" + "time": "2026-03-18T09:03:46+00:00" }, { "name": "wp-cli/export-command", - "version": "v2.1.14", + "version": "v2.1.16", "source": { "type": "git", "url": "https://github.com/wp-cli/export-command.git", - "reference": "2af32bf12c1bccd6561a215dbbafc2f272647ee8" + "reference": "cf85ae0105617c106a0c8d6b9f77bc4983140707" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/export-command/zipball/2af32bf12c1bccd6561a215dbbafc2f272647ee8", - "reference": "2af32bf12c1bccd6561a215dbbafc2f272647ee8", + "url": "https://api.github.com/repos/wp-cli/export-command/zipball/cf85ae0105617c106a0c8d6b9f77bc4983140707", + "reference": "cf85ae0105617c106a0c8d6b9f77bc4983140707", "shasum": "" }, "require": { @@ -11156,7 +11152,7 @@ "wp-cli/extension-command": "^1.2 || ^2", "wp-cli/import-command": "^1 || ^2", "wp-cli/media-command": "^1 || ^2", - "wp-cli/wp-cli-tests": "^4" + "wp-cli/wp-cli-tests": "^5" }, "type": "wp-cli-package", "extra": { @@ -11191,9 +11187,9 @@ "homepage": "https://github.com/wp-cli/export-command", "support": { "issues": "https://github.com/wp-cli/export-command/issues", - "source": "https://github.com/wp-cli/export-command/tree/v2.1.14" + "source": "https://github.com/wp-cli/export-command/tree/v2.1.16" }, - "time": "2025-04-02T15:29:08+00:00" + "time": "2026-03-17T08:25:40+00:00" }, { "name": "wp-cli/extension-command", @@ -11295,16 +11291,16 @@ }, { "name": "wp-cli/i18n-command", - "version": "v2.6.6", + "version": "v2.7.0", "source": { "type": "git", "url": "https://github.com/wp-cli/i18n-command.git", - "reference": "94f72ddc4be8919f2cea181ba39cd140dd480d64" + "reference": "e91e6903d212486e32ed2c916171f661bfc539ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/i18n-command/zipball/94f72ddc4be8919f2cea181ba39cd140dd480d64", - "reference": "94f72ddc4be8919f2cea181ba39cd140dd480d64", + "url": "https://api.github.com/repos/wp-cli/i18n-command/zipball/e91e6903d212486e32ed2c916171f661bfc539ce", + "reference": "e91e6903d212486e32ed2c916171f661bfc539ce", "shasum": "" }, "require": { @@ -11326,6 +11322,7 @@ "bundled": true, "commands": [ "i18n", + "i18n audit", "i18n make-pot", "i18n make-json", "i18n make-mo", @@ -11358,22 +11355,22 @@ "homepage": "https://github.com/wp-cli/i18n-command", "support": { "issues": "https://github.com/wp-cli/i18n-command/issues", - "source": "https://github.com/wp-cli/i18n-command/tree/v2.6.6" + "source": "https://github.com/wp-cli/i18n-command/tree/v2.7.0" }, - "time": "2025-11-21T04:23:34+00:00" + "time": "2026-03-16T17:13:39+00:00" }, { "name": "wp-cli/import-command", - "version": "v2.0.15", + "version": "v2.0.16", "source": { "type": "git", "url": "https://github.com/wp-cli/import-command.git", - "reference": "277de5a245cbf846ec822e23067703c7e3b9cb48" + "reference": "64033264b9f4b9c9a32d14e33b365a58de6f3bf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/import-command/zipball/277de5a245cbf846ec822e23067703c7e3b9cb48", - "reference": "277de5a245cbf846ec822e23067703c7e3b9cb48", + "url": "https://api.github.com/repos/wp-cli/import-command/zipball/64033264b9f4b9c9a32d14e33b365a58de6f3bf6", + "reference": "64033264b9f4b9c9a32d14e33b365a58de6f3bf6", "shasum": "" }, "require": { @@ -11419,9 +11416,9 @@ "homepage": "https://github.com/wp-cli/import-command", "support": { "issues": "https://github.com/wp-cli/import-command/issues", - "source": "https://github.com/wp-cli/import-command/tree/v2.0.15" + "source": "https://github.com/wp-cli/import-command/tree/v2.0.16" }, - "time": "2025-12-09T15:41:55+00:00" + "time": "2026-03-16T15:17:43+00:00" }, { "name": "wp-cli/language-command", @@ -11566,16 +11563,16 @@ }, { "name": "wp-cli/media-command", - "version": "v2.2.2", + "version": "v2.2.5", "source": { "type": "git", "url": "https://github.com/wp-cli/media-command.git", - "reference": "a810ea0e68473fce6a234e67c6c5f19bb820a753" + "reference": "5696bba2e8c7d5c373fa20024edb1a4b682d1511" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/media-command/zipball/a810ea0e68473fce6a234e67c6c5f19bb820a753", - "reference": "a810ea0e68473fce6a234e67c6c5f19bb820a753", + "url": "https://api.github.com/repos/wp-cli/media-command/zipball/5696bba2e8c7d5c373fa20024edb1a4b682d1511", + "reference": "5696bba2e8c7d5c373fa20024edb1a4b682d1511", "shasum": "" }, "require": { @@ -11584,13 +11581,14 @@ "require-dev": { "wp-cli/entity-command": "^1.3 || ^2", "wp-cli/extension-command": "^2.0", - "wp-cli/wp-cli-tests": "^4" + "wp-cli/wp-cli-tests": "^5" }, "type": "wp-cli-package", "extra": { "bundled": true, "commands": [ "media", + "media fix-orientation", "media import", "media regenerate", "media image-size" @@ -11622,9 +11620,9 @@ "homepage": "https://github.com/wp-cli/media-command", "support": { "issues": "https://github.com/wp-cli/media-command/issues", - "source": "https://github.com/wp-cli/media-command/tree/v2.2.2" + "source": "https://github.com/wp-cli/media-command/tree/v2.2.5" }, - "time": "2025-04-11T09:28:29+00:00" + "time": "2026-03-04T13:53:32+00:00" }, { "name": "wp-cli/mustache", @@ -11680,16 +11678,16 @@ }, { "name": "wp-cli/mustangostang-spyc", - "version": "0.6.3", + "version": "0.6.6", "source": { "type": "git", "url": "https://github.com/wp-cli/spyc.git", - "reference": "6aa0b4da69ce9e9a2c8402dab8d43cf32c581cc7" + "reference": "30f25baaaba939caaff1f4b8c7ed998632f59fe2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/spyc/zipball/6aa0b4da69ce9e9a2c8402dab8d43cf32c581cc7", - "reference": "6aa0b4da69ce9e9a2c8402dab8d43cf32c581cc7", + "url": "https://api.github.com/repos/wp-cli/spyc/zipball/30f25baaaba939caaff1f4b8c7ed998632f59fe2", + "reference": "30f25baaaba939caaff1f4b8c7ed998632f59fe2", "shasum": "" }, "require": { @@ -11725,9 +11723,9 @@ "description": "A simple YAML loader/dumper class for PHP (WP-CLI fork)", "homepage": "https://github.com/mustangostang/spyc/", "support": { - "source": "https://github.com/wp-cli/spyc/tree/autoload" + "source": "https://github.com/wp-cli/spyc/tree/0.6.6" }, - "time": "2017-04-25T11:26:20+00:00" + "time": "2026-03-12T12:30:41+00:00" }, { "name": "wp-cli/package-command", @@ -11796,16 +11794,16 @@ }, { "name": "wp-cli/php-cli-tools", - "version": "v0.12.6", + "version": "v0.12.9", "source": { "type": "git", "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "f12b650d3738e471baed6dd47982d53c5c0ab1c3" + "reference": "c3d25138ce46a66647ec0dc9b17bf300338494aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/f12b650d3738e471baed6dd47982d53c5c0ab1c3", - "reference": "f12b650d3738e471baed6dd47982d53c5c0ab1c3", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/c3d25138ce46a66647ec0dc9b17bf300338494aa", + "reference": "c3d25138ce46a66647ec0dc9b17bf300338494aa", "shasum": "" }, "require": { @@ -11818,7 +11816,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "0.12.x-dev" + "dev-main": "0.12.x-dev" } }, "autoload": { @@ -11853,9 +11851,9 @@ ], "support": { "issues": "https://github.com/wp-cli/php-cli-tools/issues", - "source": "https://github.com/wp-cli/php-cli-tools/tree/v0.12.6" + "source": "https://github.com/wp-cli/php-cli-tools/tree/v0.12.9" }, - "time": "2025-09-11T12:43:04+00:00" + "time": "2026-03-29T11:12:54+00:00" }, { "name": "wp-cli/process", @@ -12102,16 +12100,16 @@ }, { "name": "wp-cli/search-replace-command", - "version": "v2.1.9", + "version": "v2.1.11", "source": { "type": "git", "url": "https://github.com/wp-cli/search-replace-command.git", - "reference": "14aea81eca68effbc651d5fca4891a89c0667b2e" + "reference": "a04ff12b2077aae88ebb4075f8bab7f959c08927" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/search-replace-command/zipball/14aea81eca68effbc651d5fca4891a89c0667b2e", - "reference": "14aea81eca68effbc651d5fca4891a89c0667b2e", + "url": "https://api.github.com/repos/wp-cli/search-replace-command/zipball/a04ff12b2077aae88ebb4075f8bab7f959c08927", + "reference": "a04ff12b2077aae88ebb4075f8bab7f959c08927", "shasum": "" }, "require": { @@ -12156,9 +12154,9 @@ "homepage": "https://github.com/wp-cli/search-replace-command", "support": { "issues": "https://github.com/wp-cli/search-replace-command/issues", - "source": "https://github.com/wp-cli/search-replace-command/tree/v2.1.9" + "source": "https://github.com/wp-cli/search-replace-command/tree/v2.1.11" }, - "time": "2025-11-11T13:31:01+00:00" + "time": "2026-03-18T08:50:38+00:00" }, { "name": "wp-cli/server-command", @@ -12338,16 +12336,16 @@ }, { "name": "wp-cli/widget-command", - "version": "v2.1.12", + "version": "v2.2.1", "source": { "type": "git", "url": "https://github.com/wp-cli/widget-command.git", - "reference": "73084053f7b32d92583e44d870b81f287beea6a9" + "reference": "d5faa8f5b47828b2c103e9411fb52d4a63b53b99" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/widget-command/zipball/73084053f7b32d92583e44d870b81f287beea6a9", - "reference": "73084053f7b32d92583e44d870b81f287beea6a9", + "url": "https://api.github.com/repos/wp-cli/widget-command/zipball/d5faa8f5b47828b2c103e9411fb52d4a63b53b99", + "reference": "d5faa8f5b47828b2c103e9411fb52d4a63b53b99", "shasum": "" }, "require": { @@ -12355,7 +12353,7 @@ }, "require-dev": { "wp-cli/extension-command": "^1.2 || ^2", - "wp-cli/wp-cli-tests": "^4" + "wp-cli/wp-cli-tests": "^5" }, "type": "wp-cli-package", "extra": { @@ -12367,9 +12365,12 @@ "widget delete", "widget list", "widget move", + "widget patch", "widget reset", "widget update", "sidebar", + "sidebar exists", + "sidebar get", "sidebar list" ], "branch-alias": { @@ -12399,9 +12400,9 @@ "homepage": "https://github.com/wp-cli/widget-command", "support": { "issues": "https://github.com/wp-cli/widget-command/issues", - "source": "https://github.com/wp-cli/widget-command/tree/v2.1.12" + "source": "https://github.com/wp-cli/widget-command/tree/v2.2.1" }, - "time": "2025-04-11T09:29:37+00:00" + "time": "2026-03-17T12:28:44+00:00" }, { "name": "wp-cli/wp-cli", @@ -12548,16 +12549,16 @@ }, { "name": "wp-cli/wp-config-transformer", - "version": "v1.4.3", + "version": "v1.4.5", "source": { "type": "git", "url": "https://github.com/wp-cli/wp-config-transformer.git", - "reference": "5ade4e70349a1d5cd07efc33880ceb5eebb9e9fa" + "reference": "8f5e66c717a7371dfb6559086880bee528aee858" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/wp-config-transformer/zipball/5ade4e70349a1d5cd07efc33880ceb5eebb9e9fa", - "reference": "5ade4e70349a1d5cd07efc33880ceb5eebb9e9fa", + "url": "https://api.github.com/repos/wp-cli/wp-config-transformer/zipball/8f5e66c717a7371dfb6559086880bee528aee858", + "reference": "8f5e66c717a7371dfb6559086880bee528aee858", "shasum": "" }, "require": { @@ -12591,9 +12592,9 @@ "homepage": "https://github.com/wp-cli/wp-config-transformer", "support": { "issues": "https://github.com/wp-cli/wp-config-transformer/issues", - "source": "https://github.com/wp-cli/wp-config-transformer/tree/v1.4.3" + "source": "https://github.com/wp-cli/wp-config-transformer/tree/v1.4.5" }, - "time": "2025-11-11T13:31:09+00:00" + "time": "2026-03-20T07:28:10+00:00" }, { "name": "wp-coding-standards/wpcs", diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php index 3fbd08026..6270e2dd4 100644 --- a/includes/resources/Harbor/Harbor_Provider.php +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -22,9 +22,7 @@ public function register(): void { lw_harbor_register_submenu( 'kadence-blocks' ); add_filter( 'lw-harbor/legacy_licenses', new Report_Legacy_Licenses() ); - add_filter( 'kadence_blocks_ai_disabled', [ $this, 'is_ai_disabled' ] ); add_filter( 'kadence_blocks_ai_disabled_message', [ $this, 'ai_disabled_message' ] ); - add_filter( 'kadence_blocks_ai_hidden', [ $this, 'is_ai_hidden' ] ); foreach ( ( new Get_Known_Plugins() )() as $slug => $plugin ) { add_action( @@ -36,26 +34,6 @@ public function register(): void { add_action( 'admin_init', new Suppress_Legacy_Inactive_Notices() ); } - /** - * Disables Kadence AI for Harbor-licensed customers. - * AI features are not yet supported under Harbor licensing. - * - * @param bool $disabled Whether AI is disabled. - * - * @return bool - */ - public function is_ai_disabled( bool $disabled ): bool { - if ( $disabled ) { - return true; - } - - if ( kadence_blocks_is_legacy_license_authorized() ) { - return false; - } - - return true; - } - /** * Overrides the AI disabled message for Harbor-licensed customers. * @@ -75,18 +53,4 @@ public function ai_disabled_message( string $message ): string { return $message; } - /** - * Filters the AI hidden state for Harbor-licensed customers. - * - * @param bool $hidden Whether AI is hidden. - * - * @return bool - */ - public function is_ai_hidden( bool $hidden ): bool { - if ( kadence_blocks_is_legacy_license_authorized() ) { - return false; - } - - return true; - } } diff --git a/includes/resources/Home/Banner_Config_View_Model.php b/includes/resources/Home/Banner_Config_View_Model.php new file mode 100644 index 000000000..d2354b220 --- /dev/null +++ b/includes/resources/Home/Banner_Config_View_Model.php @@ -0,0 +1,62 @@ + __( 'Kadence AI is evolving.', 'kadence-blocks' ), + 'body' => __( "We're building something new. Kadence AI as you know it is no longer available for new activations — but great things are on the way. Stay tuned for what's next.", 'kadence-blocks' ), + 'primaryCtaText' => __( 'Learn More', 'kadence-blocks' ), + 'primaryCtaUrl' => 'https://www.kadencewp.com/kadence-blocks/', + ]; + } + + if ( $is_authorized ) { + return [ + 'heading' => __( 'Kadence is better with AI.', 'kadence-blocks' ), + 'body' => __( "Elevate your web development game with Kadence AI. Supercharge your pattern and page library's potential with tailored content — get building pages in no time. You have AI credits remaining on your account.", 'kadence-blocks' ), + 'primaryCtaText' => __( 'Open Kadence AI', 'kadence-blocks' ), + 'primaryCtaUrl' => '', + 'secondaryCtaText' => __( 'Manage AI Credits', 'kadence-blocks' ), + 'secondaryCtaUrl' => 'https://app.kadencewp.com/', + ]; + } + + return [ + 'heading' => __( 'Kadence AI is evolving.', 'kadence-blocks' ), + 'body' => __( "Kadence AI is being reimagined. Activate your license key to check whether you have existing AI credits — or stay tuned for what's coming next.", 'kadence-blocks' ), + 'primaryCtaText' => __( 'Activate License Key', 'kadence-blocks' ), + 'primaryCtaUrl' => esc_url( build_auth_url( apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), get_license_domain() ) ), + 'secondaryCtaText' => __( 'Learn More', 'kadence-blocks' ), + 'secondaryCtaUrl' => 'https://www.kadencewp.com/kadence-blocks/', + ]; + } + +} diff --git a/includes/settings/class-kadence-blocks-settings.php b/includes/settings/class-kadence-blocks-settings.php index 8a1dce16a..fc5bb0b64 100644 --- a/includes/settings/class-kadence-blocks-settings.php +++ b/includes/settings/class-kadence-blocks-settings.php @@ -12,6 +12,7 @@ use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_disconnect_url; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_domain; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\build_auth_url; +use KadenceWP\KadenceBlocks\Home\Banner_Config_View_Model; /** * Build Welcome Page class @@ -810,6 +811,7 @@ public function home_scripts() { if ( $is_authorized ) { $disconnect_url = get_disconnect_url( 'kadence-blocks' ); } + // Icons Scripts & Styles. $kadence_icons_meta = kadence_blocks_get_asset_file( 'dist/icons' ); wp_register_script( 'kadence-icons', KADENCE_BLOCKS_URL . 'dist/icons.js', array_merge( $kadence_icons_meta['dependencies'], [ 'wp-api' ] ), $kadence_icons_meta['version'], true ); @@ -836,6 +838,10 @@ public function home_scripts() { $kadence_home_meta = kadence_blocks_get_asset_file( 'dist/admin-kadence-home' ); wp_enqueue_script( 'admin-kadence-home', KADENCE_BLOCKS_URL . 'dist/admin-kadence-home.js', $kadence_home_meta['dependencies'], $kadence_home_meta['version'], true ); wp_enqueue_style( 'admin-kadence-home', KADENCE_BLOCKS_URL . 'dist/admin-kadence-home.css', [ 'wp-edit-blocks', 'kadence-components' ], $kadence_home_meta['version'] ); + + // Banner Config. + $banner_config = new Banner_Config_View_Model(); + wp_localize_script( 'admin-kadence-home', 'kadenceHomeParams', @@ -845,7 +851,7 @@ public function home_scripts() { 'site_name' => sanitize_title( get_bloginfo( 'name' ) ), 'pSlug' => apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), 'isAIDisabled' => kadence_blocks_is_ai_disabled(), - 'isAIHidden' => (bool) apply_filters( 'kadence_blocks_ai_hidden', false ), + 'bannerConfig' => $banner_config->exports(), 'aiDisabledMessage' => kadence_blocks_get_ai_disabled_message(), 'pVersion' => KADENCE_BLOCKS_VERSION, 'isAuthorized' => $is_authorized, diff --git a/src/dashboard/components/large-banner/ai-banner.js b/src/dashboard/components/large-banner/ai-banner.js new file mode 100644 index 000000000..efdd91e7a --- /dev/null +++ b/src/dashboard/components/large-banner/ai-banner.js @@ -0,0 +1,175 @@ +import { Button, SVG, Popover, Spinner } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { aiIcon } from '@kadence/icons'; +import { SafeParseJSON } from '@kadence/helpers'; +import { useState } from '@wordpress/element'; +import { getAsyncData } from '../../../plugins/prebuilt-library/data-fetch/get-async-data'; + +const kbLogo = ( + + + + + + + + + + +); + +/** + * Banner driven entirely by server-side config from kadenceHomeParams.bannerConfig. + * + * Props: + * onUpdateWizard — callback to open the AI wizard (used when primaryCtaUrl is empty) + * showControls — whether the current user can control AI activation + * isNetworkAdmin — whether this is a network admin context + * isUserAuthenticated — whether the user has an active legacy AI connection + */ +export function AiBanner({ onUpdateWizard, showControls, isNetworkAdmin, isUserAuthenticated }) { + const { + heading = '', + body = '', + primaryCtaText = '', + primaryCtaUrl = '', + secondaryCtaText = '', + secondaryCtaUrl = '', + } = window?.kadenceHomeParams?.bannerConfig || {}; + + const [isVisible, setIsVisible] = useState(false); + const [availableCredits, setAvailableCredits] = useState(false); + const { getAvailableCredits } = getAsyncData(); + + const toggleVisible = () => { + if (availableCredits === false) { + getRemoteAvailableCredits(); + } + setIsVisible((state) => !state); + }; + + async function getRemoteAvailableCredits() { + const response = await getAvailableCredits(); + const tempActiveStorage = SafeParseJSON(localStorage.getItem('kadenceBlocksPrebuilt'), true); + if (response === 'error') { + tempActiveStorage.credits = 'fetch'; + localStorage.setItem('kadenceBlocksPrebuilt', JSON.stringify(tempActiveStorage)); + setAvailableCredits(0); + } else if (response === '') { + tempActiveStorage.credits = 0; + localStorage.setItem('kadenceBlocksPrebuilt', JSON.stringify(tempActiveStorage)); + setAvailableCredits(0); + } else { + tempActiveStorage.credits = parseInt(response); + localStorage.setItem('kadenceBlocksPrebuilt', JSON.stringify(tempActiveStorage)); + setAvailableCredits(parseInt(response)); + } + } + + const renderPrimaryCta = () => { + if (!primaryCtaText) { + return null; + } + // External/internal link — render as anchor. + if (primaryCtaUrl) { + return ( + + {primaryCtaText} + + ); + } + // No URL — open the AI wizard. Respect network-admin restriction. + if (!showControls) { + return ( +

+ {__('Authorization needed from network admin', 'kadence-blocks')} +

+ ); + } + if (isNetworkAdmin) { + return null; + } + return ( + +
+ )} +
+ ); +} diff --git a/src/dashboard/components/large-banner/large-banner.scss b/src/dashboard/components/large-banner/large-banner.scss index 2a97a56b9..93836f8b7 100644 --- a/src/dashboard/components/large-banner/large-banner.scss +++ b/src/dashboard/components/large-banner/large-banner.scss @@ -36,6 +36,31 @@ opacity: .8; } } + .kadence-open-ai-button { + &.components-button { + background: #0073E6; + color: #fff; + border-radius: 4px; + padding: 12px 24px; + height: auto; + font-size: 14px; + &:not(:disabled,[aria-disabled=true]):hover { + background: #005bb5; + color: #fff; + } + } + } + .kb-large-banner__secondary-link { + display: inline-block; + margin-top: 12px; + color: rgba(255, 255, 255, 0.75); + font-size: 14px; + text-decoration: underline; + text-underline-offset: 3px; + &:hover { + color: #fff; + } + } .disabled-authorize-note { background: #891c23; padding: 0.5em 1em; diff --git a/src/dashboard/constants.js b/src/dashboard/constants.js index 33a17dd33..e6fd0eb97 100644 --- a/src/dashboard/constants.js +++ b/src/dashboard/constants.js @@ -10,11 +10,6 @@ import blocksPro from './images/blocks-pro.png'; import bundles from './images/bundles.png'; export const AUTHENTICATED_CONTENT = { - largeBanner: { - heading: <>{__("Let's build,", 'kadence-blocks')}, - subHeading: '', - imageSrc: '', - }, actionCards: { title: , cards: [ @@ -204,22 +199,6 @@ export const AUTHENTICATED_CONTENT = { }; export const UNAUTHENTICATED_CONTENT = { - largeBanner: { - heading: ( - <> - {__('Kadence is better with AI.', 'kadence-blocks')} {aiIcon} - - ), - subHeading: __( - "Elevate your web development game with Kadence AI. Supercharge your pattern and page library's potential with tailored content - get building pages in no time. Try Kadence AI today with 250 free credits!", - 'kadence-blocks' - ), - subHeadingPro: __( - "Elevate your web development game with Kadence AI. Supercharge your pattern and page library's potential with tailored content - get building pages in no time. Connect to your account to use Kadence AI with Kadence Blocks Pro", - 'kadence-blocks' - ), - buttonText: __('Get Started with Kadence AI', 'kadence-blocks'), - }, actionCards: { title: , cards: [ diff --git a/src/dashboard/index.js b/src/dashboard/index.js index d2fd1d1a7..7ad8e9414 100644 --- a/src/dashboard/index.js +++ b/src/dashboard/index.js @@ -4,9 +4,10 @@ import { AiWizard } from '../plugins/prebuilt-library/ai-wizard'; import { getAsyncData } from '../plugins/prebuilt-library/data-fetch/get-async-data'; import Notices from './notices'; -import { ActionCard, ArticleSlider, LargeBanner, SectionTitle, UpsellContent } from './components'; +import { ActionCard, ArticleSlider, SectionTitle, UpsellContent } from './components'; import { AUTHENTICATED_CONTENT, UNAUTHENTICATED_CONTENT } from './constants'; import { DisabledBanner } from './components/large-banner/disabled-banner'; +import { AiBanner } from './components/large-banner/ai-banner'; /** * Import Css @@ -33,7 +34,6 @@ export default function KadenceBlocksHome() { const isNetworkAdmin = kadenceHomeParams.isNetworkAdmin ? true : false; const isNetworkEnabled = kadenceHomeParams.isNetworkEnabled ? true : false; const isAIDisabled = kadenceHomeParams.isAIDisabled ? true : false; - const isAIHidden = kadenceHomeParams.isAIHidden ? true : false; const hasPro = window?.kadenceHomeParams?.pro && kadenceHomeParams.pro === 'true' ? true : false; const showControls = (isNetworkAdmin && isNetworkEnabled) || (!isNetworkAdmin && !isNetworkEnabled) ? true : false; @@ -137,7 +137,11 @@ export default function KadenceBlocksHome() { if (isAIDisabled) { return ( <> - {!isAIHidden && } + {kadenceHomeParams.bannerConfig ? ( + + ) : ( + + )}
@@ -150,9 +154,7 @@ export default function KadenceBlocksHome() { } return ( <> - setWizardState(true)} isUserAuthenticated={authenticated} showControls={showControls} From adcca319d9131d5b4fa0d2719acebeaa98a59fb4 Mon Sep 17 00:00:00 2001 From: Lint Action Date: Tue, 14 Apr 2026 15:01:55 +0000 Subject: [PATCH 15/19] Fix code style issues with ESLint --- src/dashboard/components/large-banner/ai-banner.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/dashboard/components/large-banner/ai-banner.js b/src/dashboard/components/large-banner/ai-banner.js index efdd91e7a..eaef35b95 100644 --- a/src/dashboard/components/large-banner/ai-banner.js +++ b/src/dashboard/components/large-banner/ai-banner.js @@ -83,12 +83,7 @@ export function AiBanner({ onUpdateWizard, showControls, isNetworkAdmin, isUserA // External/internal link — render as anchor. if (primaryCtaUrl) { return ( - + {primaryCtaText} ); From 69147d63c92f3ae2dd8091d40cb443d7af788887 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Tue, 14 Apr 2026 11:14:59 -0400 Subject: [PATCH 16/19] fix: link and spacing --- includes/resources/Home/Banner_Config_View_Model.php | 2 +- src/dashboard/components/large-banner/large-banner.scss | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/includes/resources/Home/Banner_Config_View_Model.php b/includes/resources/Home/Banner_Config_View_Model.php index d2354b220..85b5d84ff 100644 --- a/includes/resources/Home/Banner_Config_View_Model.php +++ b/includes/resources/Home/Banner_Config_View_Model.php @@ -45,7 +45,7 @@ public function exports(): array { 'primaryCtaText' => __( 'Open Kadence AI', 'kadence-blocks' ), 'primaryCtaUrl' => '', 'secondaryCtaText' => __( 'Manage AI Credits', 'kadence-blocks' ), - 'secondaryCtaUrl' => 'https://app.kadencewp.com/', + 'secondaryCtaUrl' => esc_url( build_auth_url( apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), get_license_domain() ) ), ]; } diff --git a/src/dashboard/components/large-banner/large-banner.scss b/src/dashboard/components/large-banner/large-banner.scss index 93836f8b7..d6034f44a 100644 --- a/src/dashboard/components/large-banner/large-banner.scss +++ b/src/dashboard/components/large-banner/large-banner.scss @@ -53,6 +53,7 @@ .kb-large-banner__secondary-link { display: inline-block; margin-top: 12px; + margin-left: 16px; color: rgba(255, 255, 255, 0.75); font-size: 14px; text-decoration: underline; From 9ceccac7846f751de24b6a875fbce6fd898819f4 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Tue, 14 Apr 2026 16:07:56 -0400 Subject: [PATCH 17/19] feature: create home content view model with conditional exports --- .../Home/Banner_Config_View_Model.php | 62 ---- .../Home/Home_Content_View_Model.php | 225 +++++++++++++ .../class-kadence-blocks-settings.php | 6 +- .../components/large-banner/ai-banner.js | 6 +- src/dashboard/constants.js | 302 ------------------ src/dashboard/index.js | 46 ++- 6 files changed, 267 insertions(+), 380 deletions(-) delete mode 100644 includes/resources/Home/Banner_Config_View_Model.php create mode 100644 includes/resources/Home/Home_Content_View_Model.php diff --git a/includes/resources/Home/Banner_Config_View_Model.php b/includes/resources/Home/Banner_Config_View_Model.php deleted file mode 100644 index 85b5d84ff..000000000 --- a/includes/resources/Home/Banner_Config_View_Model.php +++ /dev/null @@ -1,62 +0,0 @@ - __( 'Kadence AI is evolving.', 'kadence-blocks' ), - 'body' => __( "We're building something new. Kadence AI as you know it is no longer available for new activations — but great things are on the way. Stay tuned for what's next.", 'kadence-blocks' ), - 'primaryCtaText' => __( 'Learn More', 'kadence-blocks' ), - 'primaryCtaUrl' => 'https://www.kadencewp.com/kadence-blocks/', - ]; - } - - if ( $is_authorized ) { - return [ - 'heading' => __( 'Kadence is better with AI.', 'kadence-blocks' ), - 'body' => __( "Elevate your web development game with Kadence AI. Supercharge your pattern and page library's potential with tailored content — get building pages in no time. You have AI credits remaining on your account.", 'kadence-blocks' ), - 'primaryCtaText' => __( 'Open Kadence AI', 'kadence-blocks' ), - 'primaryCtaUrl' => '', - 'secondaryCtaText' => __( 'Manage AI Credits', 'kadence-blocks' ), - 'secondaryCtaUrl' => esc_url( build_auth_url( apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), get_license_domain() ) ), - ]; - } - - return [ - 'heading' => __( 'Kadence AI is evolving.', 'kadence-blocks' ), - 'body' => __( "Kadence AI is being reimagined. Activate your license key to check whether you have existing AI credits — or stay tuned for what's coming next.", 'kadence-blocks' ), - 'primaryCtaText' => __( 'Activate License Key', 'kadence-blocks' ), - 'primaryCtaUrl' => esc_url( build_auth_url( apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), get_license_domain() ) ), - 'secondaryCtaText' => __( 'Learn More', 'kadence-blocks' ), - 'secondaryCtaUrl' => 'https://www.kadencewp.com/kadence-blocks/', - ]; - } - -} diff --git a/includes/resources/Home/Home_Content_View_Model.php b/includes/resources/Home/Home_Content_View_Model.php new file mode 100644 index 000000000..1c2174b1a --- /dev/null +++ b/includes/resources/Home/Home_Content_View_Model.php @@ -0,0 +1,225 @@ + $this->banner_config( $is_authorized, $is_liquid_web ), + 'actionCards' => $this->action_cards( $is_authorized ), + 'knowledgeBase' => $this->knowledge_base( $is_authorized ), + ]; + } + + /** + * @return array{ + * heading: string, + * body: string, + * primaryCtaText: string, + * primaryCtaUrl: string, + * secondaryCtaText?: string, + * secondaryCtaUrl?: string, + * } + */ + private function banner_config( bool $is_authorized, bool $is_liquid_web ): array { + if ( $is_liquid_web ) { + return [ + 'heading' => __( 'Kadence AI is evolving.', 'kadence-blocks' ), + 'body' => __( "We're building something new. Kadence AI as you know it is no longer available for new activations — but great things are on the way. Stay tuned for what's next.", 'kadence-blocks' ), + 'primaryCtaText' => __( 'Learn More', 'kadence-blocks' ), + 'primaryCtaUrl' => 'https://www.kadencewp.com/kadence-blocks/', + ]; + } + + if ( $is_authorized ) { + return [ + 'heading' => __( 'Kadence is better with AI.', 'kadence-blocks' ), + 'body' => __( "Elevate your web development game with Kadence AI. Supercharge your pattern and page library's potential with tailored content — get building pages in no time. You have AI credits remaining on your account.", 'kadence-blocks' ), + 'primaryCtaText' => __( 'Get Started with Kadence AI', 'kadence-blocks' ), + 'primaryCtaUrl' => '', + 'secondaryCtaText' => __( 'Manage AI Credits', 'kadence-blocks' ), + 'secondaryCtaUrl' => esc_url( build_auth_url( apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), get_license_domain() ) ), + ]; + } + + return [ + 'heading' => __( 'Kadence AI is evolving.', 'kadence-blocks' ), + 'body' => __( "Kadence AI is being reimagined. Activate your license key to check whether you have existing AI credits — or stay tuned for what's coming next.", 'kadence-blocks' ), + 'primaryCtaText' => __( 'Activate License Key', 'kadence-blocks' ), + 'primaryCtaUrl' => esc_url( build_auth_url( apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), get_license_domain() ) ), + 'secondaryCtaText' => __( 'Learn More', 'kadence-blocks' ), + 'secondaryCtaUrl' => 'https://www.kadencewp.com/kadence-blocks/', + ]; + } + + /** + * @return array{ + * title: string, + * showAiIcon: bool, + * cards: array, + * } + */ + private function action_cards( bool $is_authorized ): array { + if ( $is_authorized ) { + return [ + 'title' => __( 'Start building with Kadence AI.', 'kadence-blocks' ), + 'showAiIcon' => true, + 'cards' => [ + [ + 'heading' => __( 'Build a page with AI-powered patterns', 'kadence-blocks' ), + 'content' => __( 'Take your site further with hundreds of beautiful patterns filled with custom content developed just for your site.', 'kadence-blocks' ), + 'link' => admin_url( 'post-new.php?post_type=page' ), + 'variant' => 'blue', + ], + [ + 'heading' => __( 'Get started with full pages', 'kadence-blocks' ), + 'content' => __( 'Choose from a variety of pages featuring exclusively tailored content for your site.', 'kadence-blocks' ), + 'link' => admin_url( 'post-new.php?post_type=page' ), + 'variant' => 'green', + ], + [ + 'heading' => __( 'Fine-tune your content', 'kadence-blocks' ), + 'content' => __( 'Write your own prompts to generate AI content from scratch or fine-tune existing copy.', 'kadence-blocks' ), + 'link' => '', + 'variant' => 'yellow', + ], + ], + ]; + } + + return [ + 'title' => __( 'Start building with Kadence', 'kadence-blocks' ), + 'showAiIcon' => false, + 'cards' => [ + [ + 'heading' => __( 'Build a page using pre-designed patterns', 'kadence-blocks' ), + 'content' => __( "Elevate your site's design with hundreds of beautiful patterns, customized with your site's style.", 'kadence-blocks' ), + // TODO: add query param to open Design Library on Patterns tab once URL param is established. + 'link' => admin_url( 'post-new.php?post_type=page' ), + 'variant' => 'blue', + ], + [ + 'heading' => __( 'Get started with full pages', 'kadence-blocks' ), + 'content' => __( "Kickstart your site with a variety of pre-designed page layouts, customized with your site's style.", 'kadence-blocks' ), + // TODO: add query param to open Design Library on Pages tab once URL param is established. + 'link' => admin_url( 'post-new.php?post_type=page' ), + 'variant' => 'green', + ], + [ + 'heading' => __( 'Start from scratch', 'kadence-blocks' ), + 'content' => __( "Build your website from scratch, using Kadence's blocks for layout, content and interactions.", 'kadence-blocks' ), + 'link' => admin_url( 'post-new.php?post_type=page' ), + 'variant' => 'yellow', + ], + ], + ]; + } + + /** + * @return array{ + * heading: string, + * articles: array, + * } + */ + private function knowledge_base( bool $is_authorized ): array { + return [ + 'heading' => __( 'Need Help Getting Started?', 'kadence-blocks' ), + 'articles' => $is_authorized ? $this->knowledge_base_authorized() : $this->knowledge_base_default(), + ]; + } + + private function knowledge_base_authorized(): array { + return [ + [ + 'category' => __( 'Kadence AI', 'kadence-blocks' ), + 'heading' => __( 'Update AI Settings', 'kadence-blocks' ), + 'description' => __( 'Update Kadence AI settings. Regenerate contexts for patterns and pages to reflect your updated needs.', 'kadence-blocks' ), + 'link' => 'https://www.kadencewp.com/help-center/docs/kadence-blocks/design-libary-changing-ai-details/', + 'linkTarget' => '_blank', + ], + [ + 'category' => __( 'Kadence AI', 'kadence-blocks' ), + 'heading' => __( 'Customize Image Collections', 'kadence-blocks' ), + 'description' => __( 'Update your Design Library imagery using premade collections or create and customize your own.', 'kadence-blocks' ), + 'link' => 'https://www.kadencewp.com/help-center/docs/kadence-blocks/design-library-changing-ai-image-collections/', + 'linkTarget' => '_blank', + ], + [ + 'category' => __( 'Kadence Blocks', 'kadence-blocks' ), + 'heading' => __( 'Row Layout Block', 'kadence-blocks' ), + 'description' => __( 'Use the Row Layout block to improve the column functionality and create responsive post/page layouts.', 'kadence-blocks' ), + 'link' => 'https://www.kadencewp.com/help-center/docs/kadence-blocks/row-layout-block-2/', + 'linkTarget' => '_blank', + ], + [ + 'category' => __( 'Kadence Blocks', 'kadence-blocks' ), + 'heading' => __( 'Advanced Text Block', 'kadence-blocks' ), + 'description' => __( 'Use the Advanced Text block to add text to your page/post with advanced customization - now with AI.', 'kadence-blocks' ), + 'link' => 'https://www.kadencewp.com/help-center/docs/kadence-blocks/advanced-heading-block/', + 'linkTarget' => '_blank', + ], + [ + 'category' => __( 'Support', 'kadence-blocks' ), + 'heading' => __( 'Need more help?', 'kadence-blocks' ), + 'description' => __( "Didn't find what you were looking for? Find more articles in our knowledge base.", 'kadence-blocks' ), + 'link' => 'https://www.kadencewp.com/help-center/', + 'linkTarget' => '_blank', + ], + ]; + } + + private function knowledge_base_default(): array { + return [ + [ + 'category' => __( 'Kadence Blocks', 'kadence-blocks' ), + 'heading' => __( 'Using the Design Library', 'kadence-blocks' ), + 'description' => __( 'Use fully designed patterns and pages on your site with your own customizer settings - now with AI.', 'kadence-blocks' ), + 'link' => 'https://www.kadencewp.com/help-center/docs/kadence-blocks/how-to-control-the-kadence-design-library/', + 'linkTarget' => '_blank', + ], + [ + 'category' => __( 'Kadence Blocks', 'kadence-blocks' ), + 'heading' => __( 'Row Layout Block', 'kadence-blocks' ), + 'description' => __( 'Use the Row Layout block to improve the column functionality and create responsive post/page layouts.', 'kadence-blocks' ), + 'link' => 'https://www.kadencewp.com/help-center/docs/kadence-blocks/row-layout-block-2/', + 'linkTarget' => '_blank', + ], + [ + 'category' => __( 'Kadence Blocks', 'kadence-blocks' ), + 'heading' => __( 'Advanced Text Block', 'kadence-blocks' ), + 'description' => __( 'Use the Advanced Text block to add text to your page/post with advanced customization - now with AI.', 'kadence-blocks' ), + 'link' => 'https://www.kadencewp.com/help-center/docs/kadence-blocks/advanced-heading-block/', + 'linkTarget' => '_blank', + ], + [ + 'category' => __( 'Kadence Blocks Pro', 'kadence-blocks' ), + 'heading' => __( 'Kadence Blocks Pro Plugin', 'kadence-blocks' ), + 'description' => __( 'Install and activate the Kadence Blocks Pro plugin, and get an overview of the Pro features available.', 'kadence-blocks' ), + 'link' => 'https://www.kadencewp.com/help-center/docs/kadence-blocks/kadence-blocks-pro-plugin/', + 'linkTarget' => '_blank', + ], + [ + 'category' => __( 'Support', 'kadence-blocks' ), + 'heading' => __( 'Need more help?', 'kadence-blocks' ), + 'description' => __( "Didn't find what you were looking for? Find more articles in our knowledge base.", 'kadence-blocks' ), + 'link' => 'https://www.kadencewp.com/help-center/', + 'linkTarget' => '_blank', + ], + ]; + } + +} diff --git a/includes/settings/class-kadence-blocks-settings.php b/includes/settings/class-kadence-blocks-settings.php index fc5bb0b64..87d69c173 100644 --- a/includes/settings/class-kadence-blocks-settings.php +++ b/includes/settings/class-kadence-blocks-settings.php @@ -12,7 +12,7 @@ use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_disconnect_url; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\get_license_domain; use function KadenceWP\KadenceBlocks\StellarWP\Uplink\build_auth_url; -use KadenceWP\KadenceBlocks\Home\Banner_Config_View_Model; +use KadenceWP\KadenceBlocks\Home\Home_Content_View_Model; /** * Build Welcome Page class @@ -840,7 +840,7 @@ public function home_scripts() { wp_enqueue_style( 'admin-kadence-home', KADENCE_BLOCKS_URL . 'dist/admin-kadence-home.css', [ 'wp-edit-blocks', 'kadence-components' ], $kadence_home_meta['version'] ); // Banner Config. - $banner_config = new Banner_Config_View_Model(); + $home_content = new Home_Content_View_Model(); wp_localize_script( 'admin-kadence-home', @@ -851,7 +851,7 @@ public function home_scripts() { 'site_name' => sanitize_title( get_bloginfo( 'name' ) ), 'pSlug' => apply_filters( 'kadence-blocks-auth-slug', 'kadence-blocks' ), 'isAIDisabled' => kadence_blocks_is_ai_disabled(), - 'bannerConfig' => $banner_config->exports(), + 'homeContent' => $home_content->exports(), 'aiDisabledMessage' => kadence_blocks_get_ai_disabled_message(), 'pVersion' => KADENCE_BLOCKS_VERSION, 'isAuthorized' => $is_authorized, diff --git a/src/dashboard/components/large-banner/ai-banner.js b/src/dashboard/components/large-banner/ai-banner.js index eaef35b95..0c9b27355 100644 --- a/src/dashboard/components/large-banner/ai-banner.js +++ b/src/dashboard/components/large-banner/ai-banner.js @@ -37,7 +37,7 @@ const kbLogo = ( * isNetworkAdmin — whether this is a network admin context * isUserAuthenticated — whether the user has an active legacy AI connection */ -export function AiBanner({ onUpdateWizard, showControls, isNetworkAdmin, isUserAuthenticated }) { +export function AiBanner({ onUpdateWizard, showControls, isNetworkAdmin, isUserAuthenticated, aiStatus }) { const { heading = '', body = '', @@ -45,7 +45,7 @@ export function AiBanner({ onUpdateWizard, showControls, isNetworkAdmin, isUserA primaryCtaUrl = '', secondaryCtaText = '', secondaryCtaUrl = '', - } = window?.kadenceHomeParams?.bannerConfig || {}; + } = window?.kadenceHomeParams?.homeContent?.bannerConfig || {}; const [isVisible, setIsVisible] = useState(false); const [availableCredits, setAvailableCredits] = useState(false); @@ -104,7 +104,7 @@ export function AiBanner({ onUpdateWizard, showControls, isNetworkAdmin, isUserA onClick={onUpdateWizard} iconPosition="left" icon={aiIcon} - text={primaryCtaText} + text={aiStatus === 'infoLoaded' ? __('Update Kadence AI Details', 'kadence-blocks') : primaryCtaText} className="kadence-open-ai-button" variant="primary" /> diff --git a/src/dashboard/constants.js b/src/dashboard/constants.js index e6fd0eb97..c186cb580 100644 --- a/src/dashboard/constants.js +++ b/src/dashboard/constants.js @@ -1,7 +1,4 @@ -import { SectionTitle } from './components'; -import { Icon, SVG } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { aiIcon } from '@kadence/icons'; /** * Images @@ -10,112 +7,6 @@ import blocksPro from './images/blocks-pro.png'; import bundles from './images/bundles.png'; export const AUTHENTICATED_CONTENT = { - actionCards: { - title: , - cards: [ - { - icon: ( - - - - - - - - - - - } - /> - ), - heading: __('Build a page with AI-powered patterns', 'kadence-blocks'), - content: __( - 'Take your site further with hundreds of beautiful patterns filled with custom content developed just for your site.', - 'kadence-blocks' - ), - variant: 'blue', - link: '/wp-admin/post-new.php?post_type=page', - }, - { - icon: ( - - - - - - - - - - - } - /> - ), - heading: __('Get started with full pages', 'kadence-blocks'), - content: __( - 'Choose from a variety of pages featuring exclusively tailored content for your site.', - 'kadence-blocks' - ), - variant: 'green', - link: '/wp-admin/post-new.php?post_type=page', - }, - { - icon: ( - - - - - - - - - - - } - /> - ), - heading: __('Fine-tune your content', 'kadence-blocks'), - content: __( - 'Write your own prompts to generate AI content from scratch or fine-tune existing copy.', - 'kadence-blocks' - ), - variant: 'yellow', - }, - ], - }, upsellContents: [ { image: blocksPro, @@ -141,137 +32,9 @@ export const AUTHENTICATED_CONTENT = { flip: true, }, ], - knowledgeBase: { - heading: __('Need Help Getting Started?', 'kadence-blocks'), - articles: [ - { - category: __('Kadence AI', 'kadence-blocks'), - heading: __('Update AI Settings', 'kadence-blocks'), - description: __( - 'Update Kadence AI settings. Regenerate contexts for patterns and pages to reflect your updated needs.', - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/help-center/docs/kadence-blocks/design-libary-changing-ai-details/', - linkTarget: '_blank', - }, - { - category: __('Kadence AI', 'kadence-blocks'), - heading: __('Customize Image Collections', 'kadence-blocks'), - description: __( - 'Update your Design Library imagery using premade collections or create and customize your own.', - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/help-center/docs/kadence-blocks/design-library-changing-ai-image-collections/', - linkTarget: '_blank', - }, - { - category: __('Kadence Blocks', 'kadence-blocks'), - heading: __('Row Layout Block', 'kadence-blocks'), - description: __( - 'Use the Row Layout block to improve the column functionality and create responsive post/page layouts.', - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/help-center/docs/kadence-blocks/row-layout-block-2/', - linkTarget: '_blank', - }, - { - category: __('Kadence Blocks', 'kadence-blocks'), - heading: __('Advanced Text Block', 'kadence-blocks'), - description: __( - 'Use the Advanced Text block to add text to your page/post with advanced customization - now with AI.', - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/help-center/docs/kadence-blocks/advanced-heading-block/', - linkTarget: '_blank', - }, - { - category: __('Support', 'kadence-blocks'), - heading: __('Need more help?', 'kadence-blocks'), - description: __( - "Didn't find what you were looking for? Find more articles in our knowledge base.", - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/help-center/', - linkTarget: '_blank', - }, - ], - }, }; export const UNAUTHENTICATED_CONTENT = { - actionCards: { - title: , - cards: [ - { - icon: ( - - - - - - - - - - - } - /> - ), - heading: __('A content-rich design library that is uniquely yours', 'kadence-blocks'), - content: __( - 'Jump-start your site-building process with unique content and gorgeous designs. Learn more about the AI-Powered Design Library.', - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/wordpress-solutions/kadence-ai/', - variant: 'blue', - }, - { - icon: ( - - - - - - - - - - - } - /> - ), - heading: __('Fine-Tuned Editing', 'kadence-blocks'), - content: __( - 'Get your messaging on point with in-line AI-assisted editing. Learn More about the inline AI.', - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/wordpress-solutions/kadence-ai/', - variant: 'green', - }, - ], - }, upsellContents: [ { image: blocksPro, @@ -297,69 +60,4 @@ export const UNAUTHENTICATED_CONTENT = { flip: true, }, ], - knowledgeBase: { - heading: __('Need Help Getting Started?', 'kadence-blocks'), - articles: [ - { - category: __('Kadence Blocks', 'kadence-blocks'), - heading: __('Using the Design Library', 'kadence-blocks'), - description: __( - 'Use fully designed patterns and pages on your site with your own customizer settings - now with AI.', - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/help-center/docs/kadence-blocks/how-to-control-the-kadence-design-library/', - linkTarget: '_blank', - }, - { - category: __('Kadence Blocks', 'kadence-blocks'), - heading: __('Row Layout Block', 'kadence-blocks'), - description: __( - 'Use the Row Layout block to improve the column functionality and create responsive post/page layouts.', - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/help-center/docs/kadence-blocks/row-layout-block-2/', - linkTarget: '_blank', - }, - { - category: __('Kadence Blocks', 'kadence-blocks'), - heading: __('Advanced Text Block', 'kadence-blocks'), - description: __( - 'Use the Advanced Text block to add text to your page/post with advanced customization - now with AI.', - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/help-center/docs/kadence-blocks/advanced-heading-block/', - linkTarget: '_blank', - }, - { - category: __('Kadence Blocks Pro', 'kadence-blocks'), - heading: __('Kadence Blocks Pro Plugin', 'kadence-blocks'), - description: __( - 'Install and activate the Kadence Blocks Pro plugin, and get an overview of the Pro features available.', - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/help-center/docs/kadence-blocks/kadence-blocks-pro-plugin/', - linkTarget: '_blank', - }, - { - category: __('Kadence Blocks Pro', 'kadence-blocks'), - heading: __('Advanced Slider', 'kadence-blocks'), - description: __( - 'Showcase products or highlight important visual content using the Advanced Slider block.', - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/help-center/docs/kadence-blocks/advanced-slider/', - linkTarget: '_blank', - }, - { - category: __('Support', 'kadence-blocks'), - heading: __('Need more help?', 'kadence-blocks'), - description: __( - "Didn't find what you were looking for? Find more articles in our knowledge base.", - 'kadence-blocks' - ), - link: 'https://www.kadencewp.com/help-center/', - linkTarget: '_blank', - }, - ], - }, }; diff --git a/src/dashboard/index.js b/src/dashboard/index.js index 7ad8e9414..d0fdb2dc2 100644 --- a/src/dashboard/index.js +++ b/src/dashboard/index.js @@ -8,6 +8,8 @@ import { ActionCard, ArticleSlider, SectionTitle, UpsellContent } from './compon import { AUTHENTICATED_CONTENT, UNAUTHENTICATED_CONTENT } from './constants'; import { DisabledBanner } from './components/large-banner/disabled-banner'; import { AiBanner } from './components/large-banner/ai-banner'; +import { Icon, SVG } from '@wordpress/components'; +import { aiIcon } from '@kadence/icons'; /** * Import Css @@ -38,6 +40,26 @@ export default function KadenceBlocksHome() { const showControls = (isNetworkAdmin && isNetworkEnabled) || (!isNetworkAdmin && !isNetworkEnabled) ? true : false; const content = authenticated ? AUTHENTICATED_CONTENT : UNAUTHENTICATED_CONTENT; + const homeContent = window?.kadenceHomeParams?.homeContent || {}; + const cardIcon = ( + + + + + + + + + + + } + /> + ); const getInitialAIStatus = () => { if (authenticated && 'start' === aiStatus) { checkAIStatus(); @@ -137,7 +159,7 @@ export default function KadenceBlocksHome() { if (isAIDisabled) { return ( <> - {kadenceHomeParams.bannerConfig ? ( + {kadenceHomeParams.homeContent?.bannerConfig ? ( ) : ( @@ -145,8 +167,8 @@ export default function KadenceBlocksHome() {
- - + +
@@ -159,6 +181,7 @@ export default function KadenceBlocksHome() { isUserAuthenticated={authenticated} showControls={showControls} isNetworkAdmin={isNetworkAdmin} + aiStatus={aiStatus} /> {aiStatus === 'getInitial' && (
@@ -174,12 +197,15 @@ export default function KadenceBlocksHome() {
- {content.actionCards.title} - {content.actionCards.cards.length > 0 && ( + + {homeContent?.actionCards?.cards?.length > 0 && (
- {content.actionCards.cards.map((card) => { - return ; - })} + {homeContent.actionCards.cards.map((card) => ( + + ))}
)}
@@ -206,8 +232,8 @@ export default function KadenceBlocksHome() {
- - + +
From 42cd7accb406b3f74129a502fc9ce88f9308ad51 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Tue, 14 Apr 2026 16:54:38 -0400 Subject: [PATCH 18/19] udpate: use is ai disabled for hiding ui pieces --- includes/resources/Harbor/Harbor_Provider.php | 18 +++++- .../large-banner/disabled-banner.js | 57 ------------------- src/dashboard/index.js | 20 ------- 3 files changed, 17 insertions(+), 78 deletions(-) delete mode 100644 src/dashboard/components/large-banner/disabled-banner.js diff --git a/includes/resources/Harbor/Harbor_Provider.php b/includes/resources/Harbor/Harbor_Provider.php index 6270e2dd4..4e0bd58b0 100644 --- a/includes/resources/Harbor/Harbor_Provider.php +++ b/includes/resources/Harbor/Harbor_Provider.php @@ -22,6 +22,7 @@ public function register(): void { lw_harbor_register_submenu( 'kadence-blocks' ); add_filter( 'lw-harbor/legacy_licenses', new Report_Legacy_Licenses() ); + add_filter( 'kadence_blocks_ai_disabled', [ $this, 'is_ai_disabled' ] ); add_filter( 'kadence_blocks_ai_disabled_message', [ $this, 'ai_disabled_message' ] ); foreach ( ( new Get_Known_Plugins() )() as $slug => $plugin ) { @@ -34,6 +35,21 @@ public function register(): void { add_action( 'admin_init', new Suppress_Legacy_Inactive_Notices() ); } + /** + * Disables Kadence AI for new Harbor customers who don't have legacy AI access. + * + * @param bool $disabled Whether AI is already disabled. + * + * @return bool + */ + public function is_ai_disabled( bool $disabled ): bool { + if ( $disabled ) { + return true; + } + + return ! kadence_blocks_is_legacy_license_authorized() && lw_harbor_is_product_license_active( 'kadence' ); + } + /** * Overrides the AI disabled message for Harbor-licensed customers. * @@ -47,7 +63,7 @@ public function ai_disabled_message( string $message ): string { } if ( lw_harbor_is_product_license_active( 'kadence' ) ) { - return __( 'Kadence AI is not yet available with your plan.', 'kadence-blocks' ); + return __( 'We\'re building something new. Kadence AI as you know it is no longer available for new activations — but great things are on the way. Stay tuned for what\'s next.', 'kadence-blocks' ); } return $message; diff --git a/src/dashboard/components/large-banner/disabled-banner.js b/src/dashboard/components/large-banner/disabled-banner.js deleted file mode 100644 index d57497340..000000000 --- a/src/dashboard/components/large-banner/disabled-banner.js +++ /dev/null @@ -1,57 +0,0 @@ -import { Button, Icon, Tooltip, SVG, Popover, Spinner } from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; -import { kadenceNewIcon, aiIcon, aiSettings } from '@kadence/icons'; -import { SafeParseJSON } from '@kadence/helpers'; -import { DashboardButton } from '../dashboard-button'; -import { useEffect, useState } from '@wordpress/element'; - -import './large-banner.scss'; -import { getAsyncData } from '../../../plugins/prebuilt-library/data-fetch/get-async-data'; - -const kbLogo = ( - - - - - - - - - - -); - -export function DisabledBanner() { - return ( -
-
{kbLogo}
-
-
- {__('Kadence is better with AI.', 'kadence-blocks')} {aiIcon} -
- <> -
- {__( - "Elevate your web development game with Kadence AI. Supercharge your pattern and page library's potential with tailored content - get building pages in no time.", - 'kadence-blocks' - )} -
-

- {window?.kadenceHomeParams?.aiDisabledMessage || - __('Kadence AI is disabled by site admin.', 'kadence-blocks')} -

- -
-
- ); -} diff --git a/src/dashboard/index.js b/src/dashboard/index.js index d0fdb2dc2..85318ae65 100644 --- a/src/dashboard/index.js +++ b/src/dashboard/index.js @@ -6,7 +6,6 @@ import { getAsyncData } from '../plugins/prebuilt-library/data-fetch/get-async-d import Notices from './notices'; import { ActionCard, ArticleSlider, SectionTitle, UpsellContent } from './components'; import { AUTHENTICATED_CONTENT, UNAUTHENTICATED_CONTENT } from './constants'; -import { DisabledBanner } from './components/large-banner/disabled-banner'; import { AiBanner } from './components/large-banner/ai-banner'; import { Icon, SVG } from '@wordpress/components'; import { aiIcon } from '@kadence/icons'; @@ -35,7 +34,6 @@ export default function KadenceBlocksHome() { const authenticated = kadenceHomeParams.isAuthorized ? true : false; const isNetworkAdmin = kadenceHomeParams.isNetworkAdmin ? true : false; const isNetworkEnabled = kadenceHomeParams.isNetworkEnabled ? true : false; - const isAIDisabled = kadenceHomeParams.isAIDisabled ? true : false; const hasPro = window?.kadenceHomeParams?.pro && kadenceHomeParams.pro === 'true' ? true : false; const showControls = (isNetworkAdmin && isNetworkEnabled) || (!isNetworkAdmin && !isNetworkEnabled) ? true : false; @@ -156,24 +154,6 @@ export default function KadenceBlocksHome() { {__('Disconnect?', 'kadence-blocks')} ); - if (isAIDisabled) { - return ( - <> - {kadenceHomeParams.homeContent?.bannerConfig ? ( - - ) : ( - - )} - -
-
- - -
-
- - ); - } return ( <> Date: Tue, 14 Apr 2026 17:07:49 -0400 Subject: [PATCH 19/19] chore: fix imoprt --- src/dashboard/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/dashboard/index.js b/src/dashboard/index.js index 85318ae65..8ffde3ca2 100644 --- a/src/dashboard/index.js +++ b/src/dashboard/index.js @@ -7,7 +7,6 @@ import Notices from './notices'; import { ActionCard, ArticleSlider, SectionTitle, UpsellContent } from './components'; import { AUTHENTICATED_CONTENT, UNAUTHENTICATED_CONTENT } from './constants'; import { AiBanner } from './components/large-banner/ai-banner'; -import { Icon, SVG } from '@wordpress/components'; import { aiIcon } from '@kadence/icons'; /** @@ -21,7 +20,7 @@ import { useEffect, useState } from '@wordpress/element'; import { __, _n, sprintf } from '@wordpress/i18n'; import { store as noticesStore } from '@wordpress/notices'; import { useDispatch } from '@wordpress/data'; -import { Button, Spinner } from '@wordpress/components'; +import { Icon, SVG, Spinner } from '@wordpress/components'; export default function KadenceBlocksHome() { const [wizardState, setWizardState] = useState(false);