Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions src/Harbor/Features/Resolve_Feature_Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,11 @@ private function resolve_capability_sources( Product_Collection $products, Catal
}

/**
* Returns the rank of the user's licensed tier for a product, or -1 if unlicensed.
* Returns the rank of the user's highest effective tier for a product, or -1 if unlicensed.
*
* Returns -1 when the license is known to be ineffective for this domain, matching
* the resolve_capability_sources() guard so both flags are consistent.
* Only entries activated here and not known to be ineffective count, matching
* the resolve_capability_sources() guard so both flags are consistent. A product
* can have several entries, and an invalid one must not hide a valid one.
*
* @since 1.0.0
*
Expand All @@ -262,19 +263,21 @@ private function resolve_capability_sources( Product_Collection $products, Catal
* @return int The license tier rank, or -1 if no license covers this product.
*/
private function resolve_license_tier_rank( Product_Catalog $product, Product_Collection $products ): int {
$license = $products->get_activated_entry( $product->get_product_slug() );
$rank = -1;

if ( null === $license ) {
return -1;
}
foreach ( $products->get_all_by_slug( $product->get_product_slug() ) as $license ) {
if ( ! $license->get_activated_here() || $this->is_license_invalid( $license->get_validation_status() ) ) {
continue;
}

if ( $this->is_license_invalid( $license->get_validation_status() ) ) {
return -1;
}
$tier = $product->get_tier_by_slug( $license->get_tier() );

$tier = $product->get_tier_by_slug( $license->get_tier() );
if ( $tier !== null ) {
$rank = max( $rank, $tier->get_rank() );
}
}

return $tier !== null ? $tier->get_rank() : -1;
return $rank;
}

/**
Expand Down
28 changes: 28 additions & 0 deletions tests/wpunit/Features/Resolve_Feature_CollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,34 @@ public function test_paid_feature_without_legacy_or_unified_license_is_unavailab
$this->assert_resolved_feature_flags( $resolver, 'kad-blocks-pro', false, false );
}

/**
* Tests that an invalid entry for a product does not hide a valid tier for the same product,
* whichever order Licensing returns them in.
*
* @return void
*/
public function test_invalid_entry_does_not_hide_a_valid_tier_of_the_same_product(): void {
$invalid = $this->make_product_entry( 'pro', [], 'license_banned' );
$valid = $this->make_product_entry( 'basic', [ 'kad-blocks-pro' ] );

$orders = [
'invalid first' => [ $invalid, $valid ],
'valid first' => [ $valid, $invalid ],
];

foreach ( $orders as $label => $entries ) {
$products = new Product_Collection();
foreach ( $entries as $entry ) {
$products->add( $entry );
}

$feature = ( $this->make_resolver( $this->make_catalog(), $products ) )()->get( 'kad-blocks-pro' );

$this->assertTrue( $feature->is_available(), $label );
$this->assertTrue( $feature->is_in_catalog_tier(), $label );
}
}

/**
* Tests that an active legacy entry without `use_for_updates` opt-in does not grant availability.
*
Expand Down
Loading