From ee0b26f078d3571cd556d16bb5f3b356d190c66a Mon Sep 17 00:00:00 2001 From: pramodjodhani Date: Wed, 29 Jul 2026 11:23:05 +0530 Subject: [PATCH 1/4] Add global functions for licensed products and capability checks Expose lw_harbor_get_licensed_products(), lw_harbor_is_capability_licensed(), and lw_harbor_is_capability_license_active() so consuming plugins can query the cached license catalog without reimplementing License_Repository logic. --- docs/guides/integration.md | 3 + .../Functions/Global_Function_Registry.php | 45 ++++ .../Repositories/License_Repository.php | 96 +++++++++ src/Harbor/global-functions.php | 61 ++++++ .../API/Functions/GlobalFunctionsTest.php | 204 ++++++++++++++++++ .../Repositories/License_RepositoryTest.php | 92 ++++++++ 6 files changed, 501 insertions(+) diff --git a/docs/guides/integration.md b/docs/guides/integration.md index 1633b84e..f4f5a932 100644 --- a/docs/guides/integration.md +++ b/docs/guides/integration.md @@ -291,6 +291,9 @@ See [Section 2](#2-bundling-a-license-key). Bundling a key is done entirely thro | Function | Signature | Purpose | | ---------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------- | | `lw_harbor_is_product_license_active` | `(string $slug): bool` | Check if a specific product slug has an active license. | +| `lw_harbor_get_licensed_products` | `(): ?Product_Collection` | Get the locally cached licensed products from the unified key (no remote call). | +| `lw_harbor_is_capability_licensed` | `(string $slug): bool` | Check if the unified key includes a capability, regardless of domain activation. | +| `lw_harbor_is_capability_license_active` | `(string $slug): bool` | Check if a capability is valid and activated on the current domain. | | `lw_harbor_has_unified_license_key` | `(): bool` | Check if a unified key is stored locally (no remote call). | | `lw_harbor_get_unified_license_key` | `(): ?string` | Retrieve the stored unified license key. | | `lw_harbor_is_feature_enabled` | `(string $slug): bool` | Check if a feature is currently active locally on this site. | diff --git a/src/Harbor/API/Functions/Global_Function_Registry.php b/src/Harbor/API/Functions/Global_Function_Registry.php index c95af2c0..f7274731 100644 --- a/src/Harbor/API/Functions/Global_Function_Registry.php +++ b/src/Harbor/API/Functions/Global_Function_Registry.php @@ -7,6 +7,7 @@ use LiquidWeb\Harbor\API\Functions\Actions\Register_Submenu; use LiquidWeb\Harbor\Config; use LiquidWeb\Harbor\Features\Manager; +use LiquidWeb\Harbor\Licensing\Product_Collection; use LiquidWeb\Harbor\Licensing\Repositories\License_Repository; use LiquidWeb\Harbor\Portal\Catalog_Repository; use LiquidWeb\Harbor\Site\Data; @@ -79,6 +80,50 @@ static function ( string $product ): bool { } ); + \_lw_harbor_global_function_registry( + 'lw_harbor_get_licensed_products', + $version, + static function (): ?Product_Collection { + try { + $products = Config::get_container()->get( License_Repository::class )->get_products(); + + return $products instanceof Product_Collection ? $products : null; + } catch ( Throwable $e ) { + self::debug_log_throwable( $e, 'Error getting licensed products' ); + + return null; + } + } + ); + + \_lw_harbor_global_function_registry( + 'lw_harbor_is_capability_licensed', + $version, + static function ( string $capability_slug ): bool { + try { + return Config::get_container()->get( License_Repository::class )->has_capability( $capability_slug ); + } catch ( Throwable $e ) { + self::debug_log_throwable( $e, 'Error checking capability license' ); + + return false; + } + } + ); + + \_lw_harbor_global_function_registry( + 'lw_harbor_is_capability_license_active', + $version, + static function ( string $capability_slug ): bool { + try { + return Config::get_container()->get( License_Repository::class )->is_capability_active( $capability_slug ); + } catch ( Throwable $e ) { + self::debug_log_throwable( $e, 'Error checking active capability license' ); + + return false; + } + } + ); + \_lw_harbor_global_function_registry( 'lw_harbor_is_feature_enabled', $version, diff --git a/src/Harbor/Licensing/Repositories/License_Repository.php b/src/Harbor/Licensing/Repositories/License_Repository.php index 8df542bc..12953684 100644 --- a/src/Harbor/Licensing/Repositories/License_Repository.php +++ b/src/Harbor/Licensing/Repositories/License_Repository.php @@ -2,6 +2,7 @@ namespace LiquidWeb\Harbor\Licensing\Repositories; +use LiquidWeb\Harbor\Licensing\Enums\Validation_Status; use LiquidWeb\Harbor\Licensing\Product_Collection; use LiquidWeb\Harbor\Licensing\Validation_State; use LiquidWeb\Harbor\Utils\Sanitize; @@ -458,6 +459,70 @@ public function is_product_valid( string $slug ): bool { return false; } + /** + * Whether the unified license includes a capability, regardless of domain activation. + * + * Returns true when at least one cached product entry lists the capability and + * the entry is not in a status that indicates the license does not cover it + * (e.g. expired, no entitlement). + * + * @since TBD + * + * @param string $capability_slug The capability slug to check. + * + * @return bool + */ + public function has_capability( string $capability_slug ): bool { + $products = $this->get_products(); + + if ( ! $products instanceof Product_Collection ) { + return false; + } + + foreach ( $products as $entry ) { + if ( + $this->is_capability_covered_by_license( $entry->get_validation_status() ) + && in_array( $capability_slug, $entry->get_capabilities(), true ) + ) { + return true; + } + } + + return false; + } + + /** + * Whether a capability is active on the current domain under the unified license. + * + * Returns true when at least one cached product entry is valid, activated on + * this domain, and lists the capability. + * + * @since TBD + * + * @param string $capability_slug The capability slug to check. + * + * @return bool + */ + public function is_capability_active( string $capability_slug ): bool { + $products = $this->get_products(); + + if ( ! $products instanceof Product_Collection ) { + return false; + } + + foreach ( $products as $entry ) { + if ( + $entry->is_valid() + && $entry->get_activated_here() + && in_array( $capability_slug, $entry->get_capabilities(), true ) + ) { + return true; + } + } + + return false; + } + /** * Whether a product has a valid, active license. * @@ -559,6 +624,37 @@ private function is_in_grace_period( string $slug ): bool { return $current_time <= $last_active + $this->get_grace_period_in_seconds(); } + /** + * Whether a validation status indicates the license covers the product. + * + * Excludes statuses where the unified key does not entitle the product + * (expired, suspended, no entitlement, etc.). Includes not_activated and + * similar states where the product is on the license but not active here. + * + * @since TBD + * + * @param string|null $status A Validation_Status constant value, or null. + * + * @return bool + */ + private function is_capability_covered_by_license( ?string $status ): bool { + if ( $status === null ) { + return false; + } + + $not_covered = [ + Validation_Status::EXPIRED, + Validation_Status::SUSPENDED, + Validation_Status::CANCELLED, + Validation_Status::LICENSE_SUSPENDED, + Validation_Status::LICENSE_BANNED, + Validation_Status::NO_ENTITLEMENT, + Validation_Status::INVALID_KEY, + ]; + + return ! in_array( $status, $not_covered, true ); + } + /** * Get the cached WP_Error from the most recent failed validation attempt * for the given license key if it is still within the supplied TTL. diff --git a/src/Harbor/global-functions.php b/src/Harbor/global-functions.php index 60b254fb..067df3aa 100644 --- a/src/Harbor/global-functions.php +++ b/src/Harbor/global-functions.php @@ -263,6 +263,67 @@ function lw_harbor_refresh_catalog(): bool { } } +if ( ! function_exists( 'lw_harbor_get_licensed_products' ) ) { + /** + * Get the cached licensed products from the unified license key. + * + * Returns the locally stored product catalog without making any remote API + * calls. Use License_Manager::get_products() when a fetch on cache miss is + * needed. + * + * @since TBD + * + * @return \LiquidWeb\Harbor\Licensing\Product_Collection|null The cached products, or null when none are stored. + */ + function lw_harbor_get_licensed_products(): ?\LiquidWeb\Harbor\Licensing\Product_Collection { + $callback = _lw_harbor_global_function_registry( 'lw_harbor_get_licensed_products' ); + + // @phpstan-ignore return.type + return $callback ? $callback() : null; + } +} + +if ( ! function_exists( 'lw_harbor_is_capability_licensed' ) ) { + /** + * Whether the unified license includes a capability, regardless of domain activation. + * + * Does not make any remote API calls — only checks the locally cached + * product catalog. + * + * @since TBD + * + * @param string $capability_slug The capability slug to check. + * + * @return bool + */ + function lw_harbor_is_capability_licensed( string $capability_slug ): bool { + $callback = _lw_harbor_global_function_registry( 'lw_harbor_is_capability_licensed' ); + + return $callback ? (bool) $callback( $capability_slug ) : false; + } +} + +if ( ! function_exists( 'lw_harbor_is_capability_license_active' ) ) { + /** + * Whether a capability is active on the current domain under the unified license. + * + * Returns true when the capability is covered by the unified key and the + * product is valid and activated on this domain. Does not make any remote + * API calls — only checks the locally cached product catalog. + * + * @since TBD + * + * @param string $capability_slug The capability slug to check. + * + * @return bool + */ + function lw_harbor_is_capability_license_active( string $capability_slug ): bool { + $callback = _lw_harbor_global_function_registry( 'lw_harbor_is_capability_license_active' ); + + return $callback ? (bool) $callback( $capability_slug ) : false; + } +} + if ( ! function_exists( 'lw_harbor_display_legacy_license_page_notice' ) ) { /** * Displays an informational admin notice on legacy plugin license pages. diff --git a/tests/wpunit/API/Functions/GlobalFunctionsTest.php b/tests/wpunit/API/Functions/GlobalFunctionsTest.php index 4d30b8e3..be9710c3 100644 --- a/tests/wpunit/API/Functions/GlobalFunctionsTest.php +++ b/tests/wpunit/API/Functions/GlobalFunctionsTest.php @@ -189,6 +189,210 @@ public function test_is_product_license_active_returns_false_for_unknown_product $this->assertFalse( lw_harbor_is_product_license_active( 'learndash' ) ); } + // ------------------------------------------------------------------------- + // lw_harbor_get_licensed_products() + // ------------------------------------------------------------------------- + + public function test_get_licensed_products_returns_null_without_cached_products(): void { + $this->assertNull( lw_harbor_get_licensed_products() ); + } + + public function test_get_licensed_products_returns_cached_collection(): void { + $collection = Product_Collection::from_array( + [ + Product_Entry::from_array( + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2030-12-31 23:59:59', + 'validation_status' => 'valid', + 'capabilities' => [ 'give' ], + ] + ), + ] + ); + + update_option( + License_Repository::PRODUCTS_STATE_OPTION_NAME, + [ + 'collection' => $collection->to_array(), + 'last_success_at' => null, + 'last_error' => null, + ] + ); + + $result = lw_harbor_get_licensed_products(); + + $this->assertInstanceOf( Product_Collection::class, $result ); + $this->assertCount( 1, $result ); + } + + // ------------------------------------------------------------------------- + // lw_harbor_is_capability_licensed() + // ------------------------------------------------------------------------- + + public function test_is_capability_licensed_returns_false_without_cached_products(): void { + $this->assertFalse( lw_harbor_is_capability_licensed( 'give' ) ); + } + + public function test_is_capability_licensed_returns_true_for_valid_capability(): void { + $this->seed_capability_products( + [ + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2030-12-31 23:59:59', + 'validation_status' => 'valid', + 'activated_here' => true, + 'capabilities' => [ 'give', 'give-recurring' ], + ], + ] + ); + + $this->assertTrue( lw_harbor_is_capability_licensed( 'give-recurring' ) ); + } + + public function test_is_capability_licensed_returns_true_when_not_activated_on_domain(): void { + $this->seed_capability_products( + [ + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2030-12-31 23:59:59', + 'validation_status' => 'not_activated', + 'activated_here' => false, + 'capabilities' => [ 'give', 'give-recurring' ], + ], + ] + ); + + $this->assertTrue( lw_harbor_is_capability_licensed( 'give-recurring' ) ); + } + + public function test_is_capability_licensed_returns_false_for_expired_product(): void { + $this->seed_capability_products( + [ + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2020-12-31 23:59:59', + 'validation_status' => 'expired', + 'activated_here' => false, + 'capabilities' => [ 'give', 'give-recurring' ], + ], + ] + ); + + $this->assertFalse( lw_harbor_is_capability_licensed( 'give-recurring' ) ); + } + + public function test_is_capability_licensed_returns_false_for_unknown_capability(): void { + $this->seed_capability_products( + [ + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2030-12-31 23:59:59', + 'validation_status' => 'valid', + 'activated_here' => true, + 'capabilities' => [ 'give' ], + ], + ] + ); + + $this->assertFalse( lw_harbor_is_capability_licensed( 'give-recurring' ) ); + } + + // ------------------------------------------------------------------------- + // lw_harbor_is_capability_license_active() + // ------------------------------------------------------------------------- + + public function test_is_capability_license_active_returns_false_without_cached_products(): void { + $this->assertFalse( lw_harbor_is_capability_license_active( 'give' ) ); + } + + public function test_is_capability_license_active_returns_true_for_valid_activated_capability(): void { + $this->seed_capability_products( + [ + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2030-12-31 23:59:59', + 'validation_status' => 'valid', + 'activated_here' => true, + 'capabilities' => [ 'give', 'give-recurring' ], + ], + ] + ); + + $this->assertTrue( lw_harbor_is_capability_license_active( 'give-recurring' ) ); + } + + public function test_is_capability_license_active_returns_false_when_not_activated_on_domain(): void { + $this->seed_capability_products( + [ + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2030-12-31 23:59:59', + 'validation_status' => 'not_activated', + 'activated_here' => false, + 'capabilities' => [ 'give', 'give-recurring' ], + ], + ] + ); + + $this->assertFalse( lw_harbor_is_capability_license_active( 'give-recurring' ) ); + } + + public function test_is_capability_license_active_returns_false_for_unknown_capability(): void { + $this->seed_capability_products( + [ + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2030-12-31 23:59:59', + 'validation_status' => 'valid', + 'activated_here' => true, + 'capabilities' => [ 'give' ], + ], + ] + ); + + $this->assertFalse( lw_harbor_is_capability_license_active( 'give-recurring' ) ); + } + + /** + * @param array> $products + */ + private function seed_capability_products( array $products ): void { + $entries = array_map( + static function ( array $product ): Product_Entry { + return Product_Entry::from_array( $product ); + }, + $products + ); + + $collection = Product_Collection::from_array( $entries ); + + update_option( + License_Repository::PRODUCTS_STATE_OPTION_NAME, + [ + 'collection' => $collection->to_array(), + 'last_success_at' => null, + 'last_error' => null, + ] + ); + } + // ------------------------------------------------------------------------- // lw_harbor_is_feature_enabled() / lw_harbor_is_feature_available() // ------------------------------------------------------------------------- diff --git a/tests/wpunit/Licensing/Repositories/License_RepositoryTest.php b/tests/wpunit/Licensing/Repositories/License_RepositoryTest.php index 36eb25c2..ae7c4ad5 100644 --- a/tests/wpunit/Licensing/Repositories/License_RepositoryTest.php +++ b/tests/wpunit/Licensing/Repositories/License_RepositoryTest.php @@ -555,6 +555,98 @@ public function test_is_product_valid_returns_false_for_invalid_product(): void $this->assertFalse( $this->repository->is_product_valid( 'give' ) ); } + public function test_has_capability_returns_false_without_cached_products(): void { + $this->assertFalse( $this->repository->has_capability( 'give-recurring' ) ); + } + + public function test_has_capability_returns_true_for_not_activated_product(): void { + $this->repository->set_products( + Product_Collection::from_array( + [ + Product_Entry::from_array( + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2030-12-31 23:59:59', + 'validation_status' => 'not_activated', + 'activated_here' => false, + 'capabilities' => [ 'give', 'give-recurring' ], + ] + ), + ] + ) + ); + + $this->assertTrue( $this->repository->has_capability( 'give-recurring' ) ); + } + + public function test_has_capability_returns_false_for_expired_product(): void { + $this->repository->set_products( + Product_Collection::from_array( + [ + Product_Entry::from_array( + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2020-12-31 23:59:59', + 'validation_status' => 'expired', + 'activated_here' => false, + 'capabilities' => [ 'give', 'give-recurring' ], + ] + ), + ] + ) + ); + + $this->assertFalse( $this->repository->has_capability( 'give-recurring' ) ); + } + + public function test_is_capability_active_returns_true_for_valid_activated_product(): void { + $this->repository->set_products( + Product_Collection::from_array( + [ + Product_Entry::from_array( + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2030-12-31 23:59:59', + 'validation_status' => 'valid', + 'activated_here' => true, + 'capabilities' => [ 'give', 'give-recurring' ], + ] + ), + ] + ) + ); + + $this->assertTrue( $this->repository->is_capability_active( 'give-recurring' ) ); + } + + public function test_is_capability_active_returns_false_for_not_activated_product(): void { + $this->repository->set_products( + Product_Collection::from_array( + [ + Product_Entry::from_array( + [ + 'product_slug' => 'give', + 'tier' => 'pro', + 'status' => 'active', + 'expires' => '2030-12-31 23:59:59', + 'validation_status' => 'not_activated', + 'activated_here' => false, + 'capabilities' => [ 'give', 'give-recurring' ], + ] + ), + ] + ) + ); + + $this->assertFalse( $this->repository->is_capability_active( 'give-recurring' ) ); + } + public function test_store_fires_action_when_key_changes(): void { $fired = []; From 39ec08b9fcb3f16fa8b63cba4df8c9d2a21a94e2 Mon Sep 17 00:00:00 2001 From: pramodjodhani Date: Wed, 29 Jul 2026 11:29:58 +0530 Subject: [PATCH 2/4] remove lw_harbor_get_licensed_products and rename lw_harbor_is_capability_licensed to lw_harbor_is_capability_license_active --- docs/guides/integration.md | 3 +- .../Functions/Global_Function_Registry.php | 19 +----- src/Harbor/global-functions.php | 26 +------- .../API/Functions/GlobalFunctionsTest.php | 61 ++++--------------- 4 files changed, 16 insertions(+), 93 deletions(-) diff --git a/docs/guides/integration.md b/docs/guides/integration.md index f4f5a932..2b120dc0 100644 --- a/docs/guides/integration.md +++ b/docs/guides/integration.md @@ -291,8 +291,7 @@ See [Section 2](#2-bundling-a-license-key). Bundling a key is done entirely thro | Function | Signature | Purpose | | ---------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------- | | `lw_harbor_is_product_license_active` | `(string $slug): bool` | Check if a specific product slug has an active license. | -| `lw_harbor_get_licensed_products` | `(): ?Product_Collection` | Get the locally cached licensed products from the unified key (no remote call). | -| `lw_harbor_is_capability_licensed` | `(string $slug): bool` | Check if the unified key includes a capability, regardless of domain activation. | +| `lw_harbor_is_capability_license_available` | `(string $slug): bool` | Check if the unified key includes a capability, regardless of domain activation. | | `lw_harbor_is_capability_license_active` | `(string $slug): bool` | Check if a capability is valid and activated on the current domain. | | `lw_harbor_has_unified_license_key` | `(): bool` | Check if a unified key is stored locally (no remote call). | | `lw_harbor_get_unified_license_key` | `(): ?string` | Retrieve the stored unified license key. | diff --git a/src/Harbor/API/Functions/Global_Function_Registry.php b/src/Harbor/API/Functions/Global_Function_Registry.php index f7274731..e31b99ec 100644 --- a/src/Harbor/API/Functions/Global_Function_Registry.php +++ b/src/Harbor/API/Functions/Global_Function_Registry.php @@ -7,7 +7,6 @@ use LiquidWeb\Harbor\API\Functions\Actions\Register_Submenu; use LiquidWeb\Harbor\Config; use LiquidWeb\Harbor\Features\Manager; -use LiquidWeb\Harbor\Licensing\Product_Collection; use LiquidWeb\Harbor\Licensing\Repositories\License_Repository; use LiquidWeb\Harbor\Portal\Catalog_Repository; use LiquidWeb\Harbor\Site\Data; @@ -81,23 +80,7 @@ static function ( string $product ): bool { ); \_lw_harbor_global_function_registry( - 'lw_harbor_get_licensed_products', - $version, - static function (): ?Product_Collection { - try { - $products = Config::get_container()->get( License_Repository::class )->get_products(); - - return $products instanceof Product_Collection ? $products : null; - } catch ( Throwable $e ) { - self::debug_log_throwable( $e, 'Error getting licensed products' ); - - return null; - } - } - ); - - \_lw_harbor_global_function_registry( - 'lw_harbor_is_capability_licensed', + 'lw_harbor_is_capability_license_available', $version, static function ( string $capability_slug ): bool { try { diff --git a/src/Harbor/global-functions.php b/src/Harbor/global-functions.php index 067df3aa..b05dec22 100644 --- a/src/Harbor/global-functions.php +++ b/src/Harbor/global-functions.php @@ -263,27 +263,7 @@ function lw_harbor_refresh_catalog(): bool { } } -if ( ! function_exists( 'lw_harbor_get_licensed_products' ) ) { - /** - * Get the cached licensed products from the unified license key. - * - * Returns the locally stored product catalog without making any remote API - * calls. Use License_Manager::get_products() when a fetch on cache miss is - * needed. - * - * @since TBD - * - * @return \LiquidWeb\Harbor\Licensing\Product_Collection|null The cached products, or null when none are stored. - */ - function lw_harbor_get_licensed_products(): ?\LiquidWeb\Harbor\Licensing\Product_Collection { - $callback = _lw_harbor_global_function_registry( 'lw_harbor_get_licensed_products' ); - - // @phpstan-ignore return.type - return $callback ? $callback() : null; - } -} - -if ( ! function_exists( 'lw_harbor_is_capability_licensed' ) ) { +if ( ! function_exists( 'lw_harbor_is_capability_license_available' ) ) { /** * Whether the unified license includes a capability, regardless of domain activation. * @@ -296,8 +276,8 @@ function lw_harbor_get_licensed_products(): ?\LiquidWeb\Harbor\Licensing\Product * * @return bool */ - function lw_harbor_is_capability_licensed( string $capability_slug ): bool { - $callback = _lw_harbor_global_function_registry( 'lw_harbor_is_capability_licensed' ); + function lw_harbor_is_capability_license_available( string $capability_slug ): bool { + $callback = _lw_harbor_global_function_registry( 'lw_harbor_is_capability_license_available' ); return $callback ? (bool) $callback( $capability_slug ) : false; } diff --git a/tests/wpunit/API/Functions/GlobalFunctionsTest.php b/tests/wpunit/API/Functions/GlobalFunctionsTest.php index be9710c3..a35377fd 100644 --- a/tests/wpunit/API/Functions/GlobalFunctionsTest.php +++ b/tests/wpunit/API/Functions/GlobalFunctionsTest.php @@ -190,53 +190,14 @@ public function test_is_product_license_active_returns_false_for_unknown_product } // ------------------------------------------------------------------------- - // lw_harbor_get_licensed_products() + // lw_harbor_is_capability_license_available() // ------------------------------------------------------------------------- - public function test_get_licensed_products_returns_null_without_cached_products(): void { - $this->assertNull( lw_harbor_get_licensed_products() ); + public function test_is_capability_license_available_returns_false_without_cached_products(): void { + $this->assertFalse( lw_harbor_is_capability_license_available( 'give' ) ); } - public function test_get_licensed_products_returns_cached_collection(): void { - $collection = Product_Collection::from_array( - [ - Product_Entry::from_array( - [ - 'product_slug' => 'give', - 'tier' => 'pro', - 'status' => 'active', - 'expires' => '2030-12-31 23:59:59', - 'validation_status' => 'valid', - 'capabilities' => [ 'give' ], - ] - ), - ] - ); - - update_option( - License_Repository::PRODUCTS_STATE_OPTION_NAME, - [ - 'collection' => $collection->to_array(), - 'last_success_at' => null, - 'last_error' => null, - ] - ); - - $result = lw_harbor_get_licensed_products(); - - $this->assertInstanceOf( Product_Collection::class, $result ); - $this->assertCount( 1, $result ); - } - - // ------------------------------------------------------------------------- - // lw_harbor_is_capability_licensed() - // ------------------------------------------------------------------------- - - public function test_is_capability_licensed_returns_false_without_cached_products(): void { - $this->assertFalse( lw_harbor_is_capability_licensed( 'give' ) ); - } - - public function test_is_capability_licensed_returns_true_for_valid_capability(): void { + public function test_is_capability_license_available_returns_true_for_valid_capability(): void { $this->seed_capability_products( [ [ @@ -251,10 +212,10 @@ public function test_is_capability_licensed_returns_true_for_valid_capability(): ] ); - $this->assertTrue( lw_harbor_is_capability_licensed( 'give-recurring' ) ); + $this->assertTrue( lw_harbor_is_capability_license_available( 'give-recurring' ) ); } - public function test_is_capability_licensed_returns_true_when_not_activated_on_domain(): void { + public function test_is_capability_license_available_returns_true_when_not_activated_on_domain(): void { $this->seed_capability_products( [ [ @@ -269,10 +230,10 @@ public function test_is_capability_licensed_returns_true_when_not_activated_on_d ] ); - $this->assertTrue( lw_harbor_is_capability_licensed( 'give-recurring' ) ); + $this->assertTrue( lw_harbor_is_capability_license_available( 'give-recurring' ) ); } - public function test_is_capability_licensed_returns_false_for_expired_product(): void { + public function test_is_capability_license_available_returns_false_for_expired_product(): void { $this->seed_capability_products( [ [ @@ -287,10 +248,10 @@ public function test_is_capability_licensed_returns_false_for_expired_product(): ] ); - $this->assertFalse( lw_harbor_is_capability_licensed( 'give-recurring' ) ); + $this->assertFalse( lw_harbor_is_capability_license_available( 'give-recurring' ) ); } - public function test_is_capability_licensed_returns_false_for_unknown_capability(): void { + public function test_is_capability_license_available_returns_false_for_unknown_capability(): void { $this->seed_capability_products( [ [ @@ -305,7 +266,7 @@ public function test_is_capability_licensed_returns_false_for_unknown_capability ] ); - $this->assertFalse( lw_harbor_is_capability_licensed( 'give-recurring' ) ); + $this->assertFalse( lw_harbor_is_capability_license_available( 'give-recurring' ) ); } // ------------------------------------------------------------------------- From 27b11ba249f3346c2cd88630d95a3cbaa7cd966b Mon Sep 17 00:00:00 2001 From: pramodjodhani Date: Wed, 29 Jul 2026 11:50:05 +0530 Subject: [PATCH 3/4] fix markdown error --- docs/guides/integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/integration.md b/docs/guides/integration.md index 2b120dc0..f490de13 100644 --- a/docs/guides/integration.md +++ b/docs/guides/integration.md @@ -291,7 +291,7 @@ See [Section 2](#2-bundling-a-license-key). Bundling a key is done entirely thro | Function | Signature | Purpose | | ---------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------- | | `lw_harbor_is_product_license_active` | `(string $slug): bool` | Check if a specific product slug has an active license. | -| `lw_harbor_is_capability_license_available` | `(string $slug): bool` | Check if the unified key includes a capability, regardless of domain activation. | +| `lw_harbor_is_capability_license_available` | `(string $slug): bool` | Check if the unified key includes a capability, regardless of domain activation. | | `lw_harbor_is_capability_license_active` | `(string $slug): bool` | Check if a capability is valid and activated on the current domain. | | `lw_harbor_has_unified_license_key` | `(): bool` | Check if a unified key is stored locally (no remote call). | | `lw_harbor_get_unified_license_key` | `(): ?string` | Retrieve the stored unified license key. | From 08d1f6da0b4ed54024886915f1143f6731fa1f20 Mon Sep 17 00:00:00 2001 From: pramodjodhani Date: Wed, 29 Jul 2026 12:03:31 +0530 Subject: [PATCH 4/4] markdown --- docs/guides/integration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/integration.md b/docs/guides/integration.md index f490de13..fda51418 100644 --- a/docs/guides/integration.md +++ b/docs/guides/integration.md @@ -291,7 +291,7 @@ See [Section 2](#2-bundling-a-license-key). Bundling a key is done entirely thro | Function | Signature | Purpose | | ---------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------- | | `lw_harbor_is_product_license_active` | `(string $slug): bool` | Check if a specific product slug has an active license. | -| `lw_harbor_is_capability_license_available` | `(string $slug): bool` | Check if the unified key includes a capability, regardless of domain activation. | +| `lw_harbor_is_capability_license_available` | `(string $slug): bool` | Check if the unified key includes a capability, regardless of domain activation. | | `lw_harbor_is_capability_license_active` | `(string $slug): bool` | Check if a capability is valid and activated on the current domain. | | `lw_harbor_has_unified_license_key` | `(): bool` | Check if a unified key is stored locally (no remote call). | | `lw_harbor_get_unified_license_key` | `(): ?string` | Retrieve the stored unified license key. |