You've already forked wc-licensed-product
Add licensed variable product support for duration-based licenses (v0.5.3)
Customers can now purchase licenses with different durations (monthly, yearly, lifetime) through WooCommerce product variations. Each variation can have its own license validity settings. New features: - LicensedVariableProduct class for variable licensed products - LicensedProductVariation class for individual variations - Per-variation license duration and max activations settings - Duration labels in checkout (Monthly, Quarterly, Yearly, etc.) - Full support for WooCommerce Blocks checkout with variations - Updated translations for German (de_CH) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -11,12 +11,43 @@ namespace Jeremias\WcLicensedProduct\License;
|
||||
|
||||
use Jeremias\WcLicensedProduct\Installer;
|
||||
use Jeremias\WcLicensedProduct\Product\LicensedProduct;
|
||||
use Jeremias\WcLicensedProduct\Product\LicensedProductVariation;
|
||||
use Jeremias\WcLicensedProduct\Product\LicensedVariableProduct;
|
||||
|
||||
/**
|
||||
* Manages license operations (CRUD, validation, generation)
|
||||
*/
|
||||
class LicenseManager
|
||||
{
|
||||
/**
|
||||
* Check if a product is any type of licensed product
|
||||
*
|
||||
* @param \WC_Product $product Product to check
|
||||
* @return bool True if product is licensed (simple or variable or variation)
|
||||
*/
|
||||
public function isLicensedProduct(\WC_Product $product): bool
|
||||
{
|
||||
// Simple licensed product
|
||||
if ($product->is_type('licensed')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Variable licensed product
|
||||
if ($product->is_type('licensed-variable')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Variation of a licensed-variable product
|
||||
if ($product->is_type('variation') && $product->get_parent_id()) {
|
||||
$parent = wc_get_product($product->get_parent_id());
|
||||
if ($parent && $parent->is_type('licensed-variable')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique license key
|
||||
*/
|
||||
@@ -40,32 +71,63 @@ class LicenseManager
|
||||
|
||||
/**
|
||||
* Generate a license for a completed order
|
||||
*
|
||||
* @param int $orderId Order ID
|
||||
* @param int $productId Product ID (parent product for variations)
|
||||
* @param int $customerId Customer ID
|
||||
* @param string $domain Domain to bind the license to
|
||||
* @param int|null $variationId Optional variation ID for variable licensed products
|
||||
* @return License|null Generated license or null on failure
|
||||
*/
|
||||
public function generateLicense(
|
||||
int $orderId,
|
||||
int $productId,
|
||||
int $customerId,
|
||||
string $domain
|
||||
string $domain,
|
||||
?int $variationId = null
|
||||
): ?License {
|
||||
global $wpdb;
|
||||
|
||||
// Normalize domain first for duplicate detection
|
||||
$normalizedDomain = $this->normalizeDomain($domain);
|
||||
|
||||
// Check if license already exists for this order, product, and domain
|
||||
$existing = $this->getLicenseByOrderProductAndDomain($orderId, $productId, $normalizedDomain);
|
||||
// Check if license already exists for this order, product, domain, and variation
|
||||
$existing = $this->getLicenseByOrderProductDomainAndVariation($orderId, $productId, $normalizedDomain, $variationId);
|
||||
if ($existing) {
|
||||
return $existing;
|
||||
}
|
||||
|
||||
$product = wc_get_product($productId);
|
||||
if (!$product || !$product->is_type('licensed')) {
|
||||
return null;
|
||||
// Load the product that has the license settings
|
||||
// For variations, load the variation; otherwise load the parent product
|
||||
if ($variationId) {
|
||||
$settingsProduct = wc_get_product($variationId);
|
||||
$parentProduct = wc_get_product($productId);
|
||||
|
||||
// Verify parent is licensed-variable
|
||||
if (!$parentProduct || !$parentProduct->is_type('licensed-variable')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ensure we have the proper variation class
|
||||
if ($settingsProduct && !$settingsProduct instanceof LicensedProductVariation) {
|
||||
$settingsProduct = new LicensedProductVariation($variationId);
|
||||
}
|
||||
} else {
|
||||
$settingsProduct = wc_get_product($productId);
|
||||
|
||||
// Check if this is a licensed product (simple)
|
||||
if (!$settingsProduct || !$settingsProduct->is_type('licensed')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ensure we have the LicensedProduct instance for type hints
|
||||
if (!$settingsProduct instanceof LicensedProduct) {
|
||||
$settingsProduct = new LicensedProduct($productId);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we have the LicensedProduct instance for type hints
|
||||
if (!$product instanceof LicensedProduct) {
|
||||
$product = new LicensedProduct($productId);
|
||||
if (!$settingsProduct) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Generate unique license key
|
||||
@@ -74,16 +136,16 @@ class LicenseManager
|
||||
$licenseKey = $this->generateLicenseKey();
|
||||
}
|
||||
|
||||
// Calculate expiration date
|
||||
// Calculate expiration date from the settings product (variation or parent)
|
||||
$expiresAt = null;
|
||||
$validityDays = $product->get_validity_days();
|
||||
$validityDays = $settingsProduct->get_validity_days();
|
||||
if ($validityDays !== null && $validityDays > 0) {
|
||||
$expiresAt = (new \DateTimeImmutable())->modify("+{$validityDays} days")->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
// Determine version ID if bound to version
|
||||
// Determine version ID if bound to version (always use parent product ID for versions)
|
||||
$versionId = null;
|
||||
if ($product->is_bound_to_version()) {
|
||||
if ($settingsProduct->is_bound_to_version()) {
|
||||
$versionId = $this->getCurrentVersionId($productId);
|
||||
}
|
||||
|
||||
@@ -99,7 +161,7 @@ class LicenseManager
|
||||
'version_id' => $versionId,
|
||||
'status' => License::STATUS_ACTIVE,
|
||||
'activations_count' => 1,
|
||||
'max_activations' => $product->get_max_activations(),
|
||||
'max_activations' => $settingsProduct->get_max_activations(),
|
||||
'expires_at' => $expiresAt,
|
||||
],
|
||||
['%s', '%d', '%d', '%d', '%s', '%d', '%s', '%d', '%d', '%s']
|
||||
@@ -112,6 +174,16 @@ class LicenseManager
|
||||
return $this->getLicenseById((int) $wpdb->insert_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get license by order, product, domain, and optional variation
|
||||
*/
|
||||
public function getLicenseByOrderProductDomainAndVariation(int $orderId, int $productId, string $domain, ?int $variationId = null): ?License
|
||||
{
|
||||
// For now, just use the existing method since we don't store variation_id in licenses table yet
|
||||
// In the future, we could add a variation_id column to the licenses table
|
||||
return $this->getLicenseByOrderProductAndDomain($orderId, $productId, $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get license by ID
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user