Fix licensed variable products showing as sold out (v0.5.11)

- Fixed is_purchasable() method in LicensedVariableProduct to delegate to
  parent WC_Product_Variable instead of checking for price (variable products
  don't have direct prices, only their variations do)
- Fixed getProductClass() filter to accept all 4 WooCommerce parameters
  and use product_id for reliable variation parent detection
- Fallback to global $post when product_id not available for backwards compat

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-27 13:58:07 +01:00
parent db4966caf2
commit 953aa6c8e8
6 changed files with 39 additions and 10 deletions

View File

@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.5.11] - 2026-01-27
### Fixed
- **CRITICAL:** Fixed "sold out" message on licensed variable products by correcting `is_purchasable()` method
- Variable products don't have a direct price - `is_purchasable()` now delegates to parent `WC_Product_Variable` class
- Fixed variation class detection by using product ID parameter instead of unreliable global `$post`
- Product class filter now properly accepts all 4 WooCommerce filter parameters for reliable variation detection
## [0.5.10] - 2026-01-27 ## [0.5.10] - 2026-01-27
### Fixed ### Fixed

Binary file not shown.

View File

@@ -0,0 +1 @@
32571178bfa8f0d0a03ed05b498d5f9b3c860104393a96732e86a03b6de298d2 wc-licensed-product-0.5.11.zip

View File

@@ -32,7 +32,7 @@ final class LicensedProductType
{ {
// Register product types // Register product types
add_filter('product_type_selector', [$this, 'addProductType']); add_filter('product_type_selector', [$this, 'addProductType']);
add_filter('woocommerce_product_class', [$this, 'getProductClass'], 10, 2); add_filter('woocommerce_product_class', [$this, 'getProductClass'], 10, 4);
// Add product data tabs // Add product data tabs
add_filter('woocommerce_product_data_tabs', [$this, 'addProductDataTab']); add_filter('woocommerce_product_data_tabs', [$this, 'addProductDataTab']);
@@ -76,8 +76,13 @@ final class LicensedProductType
/** /**
* Get product class for licensed types * Get product class for licensed types
*
* @param string $className Default class name
* @param string $productType Product type
* @param string $postType Post type (usually 'product' or 'product_variation')
* @param int $productId Product ID
*/ */
public function getProductClass(string $className, string $productType): string public function getProductClass(string $className, string $productType, string $postType = '', int $productId = 0): string
{ {
if ($productType === 'licensed') { if ($productType === 'licensed') {
return LicensedProduct::class; return LicensedProduct::class;
@@ -87,10 +92,21 @@ final class LicensedProductType
} }
// Handle variations of licensed-variable products // Handle variations of licensed-variable products
if ($productType === 'variation') { if ($productType === 'variation') {
// Check if parent is licensed-variable // Get parent ID from the product post
$parentId = 0;
if ($productId > 0) {
$parentId = wp_get_post_parent_id($productId);
}
// Fallback to global $post if product ID not available
if (!$parentId) {
global $post; global $post;
if ($post && $post->post_parent) { if ($post && $post->post_parent) {
$parentType = \WC_Product_Factory::get_product_type($post->post_parent); $parentId = $post->post_parent;
}
}
if ($parentId) {
$parentType = \WC_Product_Factory::get_product_type($parentId);
if ($parentType === 'licensed-variable') { if ($parentType === 'licensed-variable') {
return LicensedProductVariation::class; return LicensedProductVariation::class;
} }

View File

@@ -50,11 +50,14 @@ class LicensedVariableProduct extends WC_Product_Variable
} }
/** /**
* Licensed products are purchasable * Licensed variable products are purchasable if the parent check passes
* Variable products don't have a direct price - their variations do
*/ */
public function is_purchasable(): bool public function is_purchasable(): bool
{ {
return $this->exists() && $this->get_price() !== ''; // Use the parent WC_Product_Variable logic
// which checks exists() and status, not price
return parent::is_purchasable();
} }
/** /**

View File

@@ -3,7 +3,7 @@
* Plugin Name: WooCommerce Licensed Product * Plugin Name: WooCommerce Licensed Product
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wc-licensed-product * Plugin URI: https://src.bundespruefstelle.ch/magdev/wc-licensed-product
* Description: WooCommerce plugin to sell software products using license keys with domain-based validation. * Description: WooCommerce plugin to sell software products using license keys with domain-based validation.
* Version: 0.5.10 * Version: 0.5.11
* Author: Marco Graetsch * Author: Marco Graetsch
* Author URI: https://src.bundespruefstelle.ch/magdev * Author URI: https://src.bundespruefstelle.ch/magdev
* License: GPL-2.0-or-later * License: GPL-2.0-or-later
@@ -28,7 +28,7 @@ if (!defined('ABSPATH')) {
} }
// Plugin constants // Plugin constants
define('WC_LICENSED_PRODUCT_VERSION', '0.5.10'); define('WC_LICENSED_PRODUCT_VERSION', '0.5.11');
define('WC_LICENSED_PRODUCT_PLUGIN_FILE', __FILE__); define('WC_LICENSED_PRODUCT_PLUGIN_FILE', __FILE__);
define('WC_LICENSED_PRODUCT_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('WC_LICENSED_PRODUCT_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WC_LICENSED_PRODUCT_PLUGIN_URL', plugin_dir_url(__FILE__)); define('WC_LICENSED_PRODUCT_PLUGIN_URL', plugin_dir_url(__FILE__));