Fix Product Versions meta box not appearing for licensed-variable products (v0.5.14)

- Product Versions meta box now always added to product pages, visibility controlled via CSS/JavaScript
- Added Installer::registerProductTypes() to create product type terms in the product_type taxonomy
- Product type terms are now ensured to exist on woocommerce_init hook for existing installations
- Fixed License Settings tab and Product Versions visibility toggling when changing product types

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-27 16:16:32 +01:00
parent d2e3b41a00
commit f9efe698ea
6 changed files with 107 additions and 69 deletions

View File

@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.5.14] - 2026-01-27
### Fixed
- **CRITICAL:** Fixed Product Versions meta box not appearing for licensed-variable products
- Product Versions meta box now always added to product pages, visibility controlled via CSS/JavaScript
- Added `Installer::registerProductTypes()` to create product type terms in the `product_type` taxonomy
- Product type terms are now ensured to exist on `woocommerce_init` hook for existing installations
- Fixed License Settings tab and Product Versions visibility toggling when changing product types
## [0.5.13] - 2026-01-27 ## [0.5.13] - 2026-01-27
### Fixed ### Fixed

View File

@@ -51,11 +51,18 @@ code.file-hash {
} }
/* License Product Tab - Hidden by default, shown via JS based on product type */ /* License Product Tab - Hidden by default, shown via JS based on product type */
#woocommerce-product-data .show_if_licensed, #woocommerce-product-data ul.wc-tabs li.show_if_licensed,
#woocommerce-product-data .show_if_licensed-variable { #woocommerce-product-data ul.wc-tabs li.show_if_licensed-variable {
display: none; display: none;
} }
/* When shown, restore proper display for tab list items */
#woocommerce-product-data ul.wc-tabs li.show_if_licensed.wclp-active,
#woocommerce-product-data ul.wc-tabs li.show_if_licensed-variable.wclp-active {
display: block;
}
/* Hide elements for non-licensed products */
#woocommerce-product-data .hide_if_licensed { #woocommerce-product-data .hide_if_licensed {
display: none !important; display: none !important;
} }

View File

@@ -43,25 +43,21 @@ final class VersionAdminController
/** /**
* Add versions meta box to product edit page * Add versions meta box to product edit page
* Always adds the meta box - visibility is controlled via CSS/JavaScript based on product type
*/ */
public function addVersionsMetaBox(): void public function addVersionsMetaBox(): void
{ {
global $post; global $post;
// Only add meta box for licensed products or new products
if ($post && $post->post_type === 'product') { if ($post && $post->post_type === 'product') {
$product = wc_get_product($post->ID); add_meta_box(
// Show for licensed products or new products (where type might be selected later) 'wc_licensed_product_versions',
if (!$product || $product->is_type('licensed') || $post->post_status === 'auto-draft') { __('Product Versions', 'wc-licensed-product'),
add_meta_box( [$this, 'renderVersionsMetaBox'],
'wc_licensed_product_versions', 'product',
__('Product Versions', 'wc-licensed-product'), 'normal',
[$this, 'renderVersionsMetaBox'], 'high'
'product', );
'normal',
'high'
);
}
} }
} }
@@ -280,12 +276,13 @@ final class VersionAdminController
} }
// Verify product exists and is of type licensed // Verify product exists and is of type licensed
$product = wc_get_product($productId); // Use WC_Product_Factory::get_product_type() for reliable type detection
if (!$product) { $productType = \WC_Product_Factory::get_product_type($productId);
if (!$productType) {
wp_send_json_error(['message' => __('Product not found.', 'wc-licensed-product')]); wp_send_json_error(['message' => __('Product not found.', 'wc-licensed-product')]);
} }
if (!$product->is_type('licensed')) { if (!in_array($productType, ['licensed', 'licensed-variable'], true)) {
wp_send_json_error(['message' => __('This product is not a licensed product.', 'wc-licensed-product')]); wp_send_json_error(['message' => __('This product is not a licensed product.', 'wc-licensed-product')]);
} }

View File

@@ -31,6 +31,7 @@ final class Installer
{ {
self::createTables(); self::createTables();
self::createCacheDir(); self::createCacheDir();
self::registerProductTypes();
// Set version in options // Set version in options
update_option('wc_licensed_product_version', WC_LICENSED_PRODUCT_VERSION); update_option('wc_licensed_product_version', WC_LICENSED_PRODUCT_VERSION);
@@ -43,6 +44,28 @@ final class Installer
flush_rewrite_rules(); flush_rewrite_rules();
} }
/**
* Register custom product type terms in the product_type taxonomy
* This is required for WC_Product_Factory::get_product_type() to work correctly
*/
public static function registerProductTypes(): void
{
// Ensure WooCommerce taxonomies are registered
if (!taxonomy_exists('product_type')) {
return;
}
// Register 'licensed' product type term if it doesn't exist
if (!term_exists('licensed', 'product_type')) {
wp_insert_term('licensed', 'product_type');
}
// Register 'licensed-variable' product type term if it doesn't exist
if (!term_exists('licensed-variable', 'product_type')) {
wp_insert_term('licensed-variable', 'product_type');
}
}
/** /**
* Run on plugin deactivation * Run on plugin deactivation
*/ */

View File

@@ -30,6 +30,9 @@ final class LicensedProductType
*/ */
private function registerHooks(): void private function registerHooks(): void
{ {
// Ensure product type terms exist in taxonomy (for WC_Product_Factory::get_product_type())
add_action('woocommerce_init', [$this, 'ensureProductTypeTermsExist']);
// 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, 4); add_filter('woocommerce_product_class', [$this, 'getProductClass'], 10, 4);
@@ -74,6 +77,15 @@ final class LicensedProductType
add_action('admin_footer', [$this, 'addVariableProductScripts']); add_action('admin_footer', [$this, 'addVariableProductScripts']);
} }
/**
* Ensure product type terms exist in the product_type taxonomy
* This is required for WC_Product_Factory::get_product_type() to work correctly
*/
public function ensureProductTypeTermsExist(): void
{
\Jeremias\WcLicensedProduct\Installer::registerProductTypes();
}
/** /**
* Add product types to selector * Add product types to selector
*/ */
@@ -227,35 +239,6 @@ final class LicensedProductType
?> ?>
</div> </div>
</div> </div>
<script type="text/javascript">
jQuery(document).ready(function($) {
// Show/hide panels based on product type for license settings tab
function toggleLicensedProductOptions() {
var productType = $('#product-type').val();
var isLicensed = productType === 'licensed';
var isLicensedVariable = productType === 'licensed-variable';
if (isLicensed || isLicensedVariable) {
// Show license settings tab
$('.show_if_licensed').show();
$('.show_if_licensed-variable').show();
$('.general_options').show();
$('.pricing').show();
$('.general_tab').show();
} else {
// Hide license settings tab for other product types
$('.show_if_licensed').hide();
$('.show_if_licensed-variable').hide();
}
}
// Initial state on page load
toggleLicensedProductOptions();
// On product type change
$('#product-type').on('change', toggleLicensedProductOptions);
});
</script>
<?php <?php
} }
@@ -642,7 +625,8 @@ final class LicensedProductType
} }
/** /**
* Add JavaScript for licensed-variable product type in admin * Add JavaScript for licensed product types in admin
* Handles visibility of License Settings tab and Product Versions meta box
*/ */
public function addVariableProductScripts(): void public function addVariableProductScripts(): void
{ {
@@ -659,21 +643,39 @@ final class LicensedProductType
?> ?>
<script type="text/javascript"> <script type="text/javascript">
jQuery(document).ready(function($) { jQuery(document).ready(function($) {
// Show/hide panels based on product type // Main function to handle all licensed product type visibility
function toggleLicensedVariableOptions() { function toggleLicensedProductVisibility() {
var productType = $('#product-type').val(); var productType = $('#product-type').val();
var isLicensed = productType === 'licensed';
var isLicensedVariable = productType === 'licensed-variable';
if (productType === 'licensed-variable') { // Handle License Settings tab visibility using class toggle (not show/hide)
// This preserves proper CSS display values for tab list items
if (isLicensed || isLicensedVariable) {
$('.show_if_licensed').addClass('wclp-active');
$('.show_if_licensed-variable').addClass('wclp-active');
$('.general_options').show();
$('.pricing').show();
$('.general_tab').show();
} else {
$('.show_if_licensed').removeClass('wclp-active');
$('.show_if_licensed-variable').removeClass('wclp-active');
}
// Handle Product Versions meta box visibility
if (isLicensed || isLicensedVariable) {
$('#wc_licensed_product_versions').show();
} else {
$('#wc_licensed_product_versions').hide();
}
// Handle licensed-variable specific options
if (isLicensedVariable) {
// Show variable product options // Show variable product options
$('.show_if_variable').show(); $('.show_if_variable').show();
$('.hide_if_variable').hide(); $('.hide_if_variable').hide();
// Show licensed product options // Show variations tab
$('.show_if_licensed-variable').show();
$('.show_if_licensed').show();
// Show general and variations tabs
$('.general_tab').show();
$('.variations_tab').show(); $('.variations_tab').show();
$('.variations_options').show(); $('.variations_options').show();
@@ -685,34 +687,33 @@ final class LicensedProductType
} }
} }
// Initial check // Initial check on page load
toggleLicensedVariableOptions(); toggleLicensedProductVisibility();
// On product type change // On product type change
$('#product-type').on('change', function() { $('#product-type').on('change', function() {
// Use setTimeout to let WooCommerce finish its own processing first // Use setTimeout to let WooCommerce finish its own processing first
setTimeout(toggleLicensedVariableOptions, 100); setTimeout(toggleLicensedProductVisibility, 100);
}); });
// Re-apply after WooCommerce AJAX operations that may reset visibility // Re-apply after WooCommerce AJAX operations that may reset visibility
$(document).on('woocommerce_variations_loaded', toggleLicensedVariableOptions); $(document).on('woocommerce_variations_loaded', toggleLicensedProductVisibility);
$(document).on('woocommerce_variations_added', toggleLicensedVariableOptions); $(document).on('woocommerce_variations_added', toggleLicensedProductVisibility);
$(document).on('woocommerce_variations_saved', toggleLicensedVariableOptions); $(document).on('woocommerce_variations_saved', toggleLicensedProductVisibility);
// Handle AJAX complete events for attribute saving // Handle AJAX complete events for attribute saving
$(document).ajaxComplete(function(event, xhr, settings) { $(document).ajaxComplete(function(event, xhr, settings) {
// Check if this was a product data save or attribute action
if (settings.data && ( if (settings.data && (
settings.data.indexOf('action=woocommerce_save_attributes') !== -1 || settings.data.indexOf('action=woocommerce_save_attributes') !== -1 ||
settings.data.indexOf('action=woocommerce_load_variations') !== -1 || settings.data.indexOf('action=woocommerce_load_variations') !== -1 ||
settings.data.indexOf('action=woocommerce_add_variation') !== -1 settings.data.indexOf('action=woocommerce_add_variation') !== -1
)) { )) {
setTimeout(toggleLicensedVariableOptions, 100); setTimeout(toggleLicensedProductVisibility, 100);
} }
}); });
// Also listen for the WooCommerce product type show/hide trigger // Listen for WooCommerce product type show/hide trigger
$('body').on('woocommerce-product-type-change', toggleLicensedVariableOptions); $('body').on('woocommerce-product-type-change', toggleLicensedProductVisibility);
}); });
</script> </script>
<?php <?php

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.13 * Version: 0.5.14
* 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.13'); define('WC_LICENSED_PRODUCT_VERSION', '0.5.14');
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__));