2026-01-21 18:55:18 +01:00
|
|
|
|
<?php
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Checkout Controller
|
|
|
|
|
|
*
|
|
|
|
|
|
* @package Jeremias\WcLicensedProduct\Checkout
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
|
|
namespace Jeremias\WcLicensedProduct\Checkout;
|
|
|
|
|
|
|
|
|
|
|
|
use Jeremias\WcLicensedProduct\License\LicenseManager;
|
2026-01-25 18:31:36 +01:00
|
|
|
|
use Jeremias\WcLicensedProduct\Admin\SettingsController;
|
2026-01-21 18:55:18 +01:00
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Handles checkout modifications for licensed products
|
|
|
|
|
|
*/
|
|
|
|
|
|
final class CheckoutController
|
|
|
|
|
|
{
|
|
|
|
|
|
private LicenseManager $licenseManager;
|
|
|
|
|
|
|
|
|
|
|
|
public function __construct(LicenseManager $licenseManager)
|
|
|
|
|
|
{
|
|
|
|
|
|
$this->licenseManager = $licenseManager;
|
|
|
|
|
|
$this->registerHooks();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Register WordPress hooks
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function registerHooks(): void
|
|
|
|
|
|
{
|
|
|
|
|
|
// Add domain field to checkout
|
|
|
|
|
|
add_action('woocommerce_after_order_notes', [$this, 'addDomainField']);
|
|
|
|
|
|
|
|
|
|
|
|
// Validate domain field
|
|
|
|
|
|
add_action('woocommerce_checkout_process', [$this, 'validateDomainField']);
|
|
|
|
|
|
|
|
|
|
|
|
// Save domain field to order meta
|
|
|
|
|
|
add_action('woocommerce_checkout_update_order_meta', [$this, 'saveDomainField']);
|
|
|
|
|
|
|
|
|
|
|
|
// Display domain in order details (admin)
|
|
|
|
|
|
add_action('woocommerce_admin_order_data_after_billing_address', [$this, 'displayDomainInAdmin']);
|
|
|
|
|
|
|
|
|
|
|
|
// Display domain in order email
|
|
|
|
|
|
add_action('woocommerce_email_after_order_table', [$this, 'displayDomainInEmail'], 10, 3);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Check if cart contains licensed products
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function cartHasLicensedProducts(): bool
|
2026-01-25 18:31:36 +01:00
|
|
|
|
{
|
|
|
|
|
|
return !empty($this->getLicensedProductsFromCart());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get licensed products from cart with quantities
|
|
|
|
|
|
*
|
|
|
|
|
|
* @return array<int, array{product_id: int, name: string, quantity: int}>
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function getLicensedProductsFromCart(): array
|
2026-01-21 18:55:18 +01:00
|
|
|
|
{
|
|
|
|
|
|
if (!WC()->cart) {
|
2026-01-25 18:31:36 +01:00
|
|
|
|
return [];
|
2026-01-21 18:55:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-25 18:31:36 +01:00
|
|
|
|
$licensedProducts = [];
|
2026-01-21 18:55:18 +01:00
|
|
|
|
foreach (WC()->cart->get_cart() as $cartItem) {
|
|
|
|
|
|
$product = $cartItem['data'];
|
|
|
|
|
|
if ($product && $product->is_type('licensed')) {
|
2026-01-25 18:31:36 +01:00
|
|
|
|
$productId = $product->get_id();
|
|
|
|
|
|
$licensedProducts[$productId] = [
|
|
|
|
|
|
'product_id' => $productId,
|
|
|
|
|
|
'name' => $product->get_name(),
|
|
|
|
|
|
'quantity' => (int) $cartItem['quantity'],
|
|
|
|
|
|
];
|
2026-01-21 18:55:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-25 18:31:36 +01:00
|
|
|
|
return $licensedProducts;
|
2026-01-21 18:55:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-25 18:31:36 +01:00
|
|
|
|
* Add domain fields to checkout form
|
|
|
|
|
|
* Shows multiple domain fields if multi-domain is enabled, otherwise single field
|
2026-01-21 18:55:18 +01:00
|
|
|
|
*/
|
|
|
|
|
|
public function addDomainField(): void
|
|
|
|
|
|
{
|
2026-01-25 18:31:36 +01:00
|
|
|
|
$licensedProducts = $this->getLicensedProductsFromCart();
|
|
|
|
|
|
if (empty($licensedProducts)) {
|
2026-01-21 18:55:18 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-25 18:31:36 +01:00
|
|
|
|
// Check if multi-domain licensing is enabled
|
|
|
|
|
|
if (SettingsController::isMultiDomainEnabled()) {
|
|
|
|
|
|
$this->renderMultiDomainFields($licensedProducts);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$this->renderSingleDomainField();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Render single domain field (legacy mode)
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function renderSingleDomainField(): void
|
|
|
|
|
|
{
|
|
|
|
|
|
$savedValue = '';
|
|
|
|
|
|
|
|
|
|
|
|
// Check POST data first (validation failure case)
|
|
|
|
|
|
if (isset($_POST['licensed_product_domain'])) {
|
|
|
|
|
|
$savedValue = sanitize_text_field($_POST['licensed_product_domain']);
|
|
|
|
|
|
} elseif (WC()->session) {
|
|
|
|
|
|
$savedValue = WC()->session->get('licensed_product_domain', '');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-21 18:55:18 +01:00
|
|
|
|
?>
|
|
|
|
|
|
<div id="licensed-product-domain-field">
|
|
|
|
|
|
<h3><?php esc_html_e('License Domain', 'wc-licensed-product'); ?></h3>
|
|
|
|
|
|
<p class="form-row form-row-wide">
|
|
|
|
|
|
<label for="licensed_product_domain">
|
2026-01-25 18:31:36 +01:00
|
|
|
|
<?php esc_html_e('Domain', 'wc-licensed-product'); ?>
|
2026-01-21 18:55:18 +01:00
|
|
|
|
<abbr class="required" title="<?php esc_attr_e('required', 'wc-licensed-product'); ?>">*</abbr>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
class="input-text"
|
|
|
|
|
|
name="licensed_product_domain"
|
|
|
|
|
|
id="licensed_product_domain"
|
|
|
|
|
|
placeholder="<?php esc_attr_e('example.com', 'wc-licensed-product'); ?>"
|
2026-01-25 18:31:36 +01:00
|
|
|
|
value="<?php echo esc_attr($savedValue); ?>"
|
2026-01-21 18:55:18 +01:00
|
|
|
|
/>
|
|
|
|
|
|
<span class="description">
|
2026-01-25 18:31:36 +01:00
|
|
|
|
<?php esc_html_e('Enter the domain where you will use the license (without http:// or www).', 'wc-licensed-product'); ?>
|
2026-01-21 18:55:18 +01:00
|
|
|
|
</span>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-25 18:31:36 +01:00
|
|
|
|
* Render multi-domain fields (one per quantity)
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function renderMultiDomainFields(array $licensedProducts): void
|
|
|
|
|
|
{
|
|
|
|
|
|
?>
|
|
|
|
|
|
<div id="licensed-product-domain-fields">
|
|
|
|
|
|
<h3><?php esc_html_e('License Domains', 'wc-licensed-product'); ?></h3>
|
|
|
|
|
|
<p class="wclp-domain-description">
|
|
|
|
|
|
<?php esc_html_e('Enter a unique domain for each license (without http:// or www).', 'wc-licensed-product'); ?>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<?php foreach ($licensedProducts as $productId => $productData): ?>
|
|
|
|
|
|
<div class="wclp-product-domains" data-product-id="<?php echo esc_attr($productId); ?>">
|
|
|
|
|
|
<h4>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
echo esc_html($productData['name']);
|
|
|
|
|
|
if ($productData['quantity'] > 1) {
|
|
|
|
|
|
printf(' (×%d)', $productData['quantity']);
|
|
|
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
|
|
</h4>
|
|
|
|
|
|
|
|
|
|
|
|
<?php for ($i = 0; $i < $productData['quantity']; $i++): ?>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$fieldName = sprintf('licensed_domains[%d][%d]', $productId, $i);
|
|
|
|
|
|
$fieldId = sprintf('licensed_domain_%d_%d', $productId, $i);
|
|
|
|
|
|
$savedValue = $this->getSavedDomainValue($productId, $i);
|
|
|
|
|
|
?>
|
|
|
|
|
|
<p class="form-row form-row-wide wclp-domain-row">
|
|
|
|
|
|
<label for="<?php echo esc_attr($fieldId); ?>">
|
|
|
|
|
|
<?php
|
|
|
|
|
|
printf(
|
|
|
|
|
|
/* translators: %d: license number */
|
|
|
|
|
|
esc_html__('License %d:', 'wc-licensed-product'),
|
|
|
|
|
|
$i + 1
|
|
|
|
|
|
);
|
|
|
|
|
|
?>
|
|
|
|
|
|
<abbr class="required" title="<?php esc_attr_e('required', 'wc-licensed-product'); ?>">*</abbr>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="text"
|
|
|
|
|
|
class="input-text wclp-domain-input"
|
|
|
|
|
|
name="<?php echo esc_attr($fieldName); ?>"
|
|
|
|
|
|
id="<?php echo esc_attr($fieldId); ?>"
|
|
|
|
|
|
placeholder="<?php esc_attr_e('example.com', 'wc-licensed-product'); ?>"
|
|
|
|
|
|
value="<?php echo esc_attr($savedValue); ?>"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<?php endfor; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<style>
|
|
|
|
|
|
#licensed-product-domain-fields { margin-bottom: 20px; }
|
|
|
|
|
|
#licensed-product-domain-fields h3 { margin-bottom: 10px; }
|
|
|
|
|
|
.wclp-domain-description { margin-bottom: 15px; color: #666; }
|
|
|
|
|
|
.wclp-product-domains { margin-bottom: 20px; padding: 15px; background: #f8f8f8; border-radius: 4px; }
|
|
|
|
|
|
.wclp-product-domains h4 { margin: 0 0 10px 0; font-size: 1em; }
|
|
|
|
|
|
.wclp-domain-row { margin-bottom: 10px; }
|
|
|
|
|
|
.wclp-domain-row:last-child { margin-bottom: 0; }
|
|
|
|
|
|
.wclp-domain-row label { display: block; margin-bottom: 5px; }
|
|
|
|
|
|
</style>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Get saved domain value from session/POST
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function getSavedDomainValue(int $productId, int $index): string
|
|
|
|
|
|
{
|
|
|
|
|
|
// Check POST data first (validation failure case)
|
|
|
|
|
|
if (isset($_POST['licensed_domains'][$productId][$index])) {
|
|
|
|
|
|
return sanitize_text_field($_POST['licensed_domains'][$productId][$index]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Check session for blocks checkout
|
|
|
|
|
|
if (WC()->session) {
|
|
|
|
|
|
$sessionDomains = WC()->session->get('licensed_product_domains', []);
|
|
|
|
|
|
foreach ($sessionDomains as $item) {
|
|
|
|
|
|
if (isset($item['product_id']) && (int) $item['product_id'] === $productId) {
|
|
|
|
|
|
if (isset($item['domains'][$index])) {
|
|
|
|
|
|
return $item['domains'][$index];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Validate domain fields during checkout
|
2026-01-21 18:55:18 +01:00
|
|
|
|
*/
|
|
|
|
|
|
public function validateDomainField(): void
|
|
|
|
|
|
{
|
2026-01-25 18:31:36 +01:00
|
|
|
|
$licensedProducts = $this->getLicensedProductsFromCart();
|
|
|
|
|
|
if (empty($licensedProducts)) {
|
2026-01-21 18:55:18 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-25 18:31:36 +01:00
|
|
|
|
// Check if multi-domain licensing is enabled
|
|
|
|
|
|
if (SettingsController::isMultiDomainEnabled()) {
|
|
|
|
|
|
$this->validateMultiDomainFields($licensedProducts);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$this->validateSingleDomainField();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Validate single domain field
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function validateSingleDomainField(): void
|
|
|
|
|
|
{
|
|
|
|
|
|
$domain = isset($_POST['licensed_product_domain']) ? sanitize_text_field($_POST['licensed_product_domain']) : '';
|
2026-01-21 18:55:18 +01:00
|
|
|
|
|
|
|
|
|
|
if (empty($domain)) {
|
2026-01-25 18:31:36 +01:00
|
|
|
|
wc_add_notice(__('Please enter a domain for your license.', 'wc-licensed-product'), 'error');
|
2026-01-21 18:55:18 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$normalizedDomain = $this->licenseManager->normalizeDomain($domain);
|
|
|
|
|
|
if (!$this->isValidDomain($normalizedDomain)) {
|
2026-01-25 18:31:36 +01:00
|
|
|
|
wc_add_notice(__('Please enter a valid domain for your license.', 'wc-licensed-product'), 'error');
|
2026-01-21 18:55:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-25 18:31:36 +01:00
|
|
|
|
* Validate multi-domain fields
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function validateMultiDomainFields(array $licensedProducts): void
|
|
|
|
|
|
{
|
|
|
|
|
|
$licensedDomains = $_POST['licensed_domains'] ?? [];
|
|
|
|
|
|
|
|
|
|
|
|
foreach ($licensedProducts as $productId => $productData) {
|
|
|
|
|
|
$productDomains = $licensedDomains[$productId] ?? [];
|
|
|
|
|
|
$normalizedDomains = [];
|
|
|
|
|
|
|
|
|
|
|
|
for ($i = 0; $i < $productData['quantity']; $i++) {
|
|
|
|
|
|
$domain = isset($productDomains[$i]) ? sanitize_text_field($productDomains[$i]) : '';
|
|
|
|
|
|
|
|
|
|
|
|
// Check if domain is empty
|
|
|
|
|
|
if (empty($domain)) {
|
|
|
|
|
|
wc_add_notice(
|
|
|
|
|
|
sprintf(
|
|
|
|
|
|
/* translators: 1: product name, 2: license number */
|
|
|
|
|
|
__('Please enter a domain for %1$s (License %2$d).', 'wc-licensed-product'),
|
|
|
|
|
|
$productData['name'],
|
|
|
|
|
|
$i + 1
|
|
|
|
|
|
),
|
|
|
|
|
|
'error'
|
|
|
|
|
|
);
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Validate domain format
|
|
|
|
|
|
$normalizedDomain = $this->licenseManager->normalizeDomain($domain);
|
|
|
|
|
|
if (!$this->isValidDomain($normalizedDomain)) {
|
|
|
|
|
|
wc_add_notice(
|
|
|
|
|
|
sprintf(
|
|
|
|
|
|
/* translators: 1: product name, 2: license number */
|
|
|
|
|
|
__('Please enter a valid domain for %1$s (License %2$d).', 'wc-licensed-product'),
|
|
|
|
|
|
$productData['name'],
|
|
|
|
|
|
$i + 1
|
|
|
|
|
|
),
|
|
|
|
|
|
'error'
|
|
|
|
|
|
);
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Check for duplicate domains within same product
|
|
|
|
|
|
if (in_array($normalizedDomain, $normalizedDomains, true)) {
|
|
|
|
|
|
wc_add_notice(
|
|
|
|
|
|
sprintf(
|
|
|
|
|
|
/* translators: 1: domain name, 2: product name */
|
|
|
|
|
|
__('The domain "%1$s" is used multiple times for %2$s. Each license requires a unique domain.', 'wc-licensed-product'),
|
|
|
|
|
|
$normalizedDomain,
|
|
|
|
|
|
$productData['name']
|
|
|
|
|
|
),
|
|
|
|
|
|
'error'
|
|
|
|
|
|
);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$normalizedDomains[] = $normalizedDomain;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Save domain fields to order meta
|
2026-01-21 18:55:18 +01:00
|
|
|
|
*/
|
|
|
|
|
|
public function saveDomainField(int $orderId): void
|
|
|
|
|
|
{
|
2026-01-25 18:31:36 +01:00
|
|
|
|
$licensedProducts = $this->getLicensedProductsFromCart();
|
|
|
|
|
|
if (empty($licensedProducts)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$order = wc_get_order($orderId);
|
|
|
|
|
|
if (!$order) {
|
2026-01-21 18:55:18 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-25 18:31:36 +01:00
|
|
|
|
// Check if multi-domain licensing is enabled
|
|
|
|
|
|
if (SettingsController::isMultiDomainEnabled()) {
|
|
|
|
|
|
$this->saveMultiDomainFields($order, $licensedProducts);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$this->saveSingleDomainField($order);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Save single domain field to order meta (legacy format)
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function saveSingleDomainField(\WC_Order $order): void
|
|
|
|
|
|
{
|
|
|
|
|
|
$domain = isset($_POST['licensed_product_domain']) ? sanitize_text_field($_POST['licensed_product_domain']) : '';
|
|
|
|
|
|
|
|
|
|
|
|
if (!empty($domain)) {
|
2026-01-21 18:55:18 +01:00
|
|
|
|
$normalizedDomain = $this->licenseManager->normalizeDomain($domain);
|
2026-01-25 18:31:36 +01:00
|
|
|
|
$order->update_meta_data('_licensed_product_domain', $normalizedDomain);
|
|
|
|
|
|
$order->save();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-21 18:55:18 +01:00
|
|
|
|
|
2026-01-25 18:31:36 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Save multi-domain fields to order meta
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function saveMultiDomainFields(\WC_Order $order, array $licensedProducts): void
|
|
|
|
|
|
{
|
|
|
|
|
|
$licensedDomains = $_POST['licensed_domains'] ?? [];
|
|
|
|
|
|
$domainData = [];
|
|
|
|
|
|
|
|
|
|
|
|
foreach ($licensedProducts as $productId => $productData) {
|
|
|
|
|
|
$productDomains = $licensedDomains[$productId] ?? [];
|
|
|
|
|
|
$normalizedDomains = [];
|
|
|
|
|
|
|
|
|
|
|
|
for ($i = 0; $i < $productData['quantity']; $i++) {
|
|
|
|
|
|
$domain = isset($productDomains[$i]) ? sanitize_text_field($productDomains[$i]) : '';
|
|
|
|
|
|
if (!empty($domain)) {
|
|
|
|
|
|
$normalizedDomains[] = $this->licenseManager->normalizeDomain($domain);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!empty($normalizedDomains)) {
|
|
|
|
|
|
$domainData[] = [
|
|
|
|
|
|
'product_id' => $productId,
|
|
|
|
|
|
'domains' => $normalizedDomains,
|
|
|
|
|
|
];
|
2026-01-21 18:55:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-25 18:31:36 +01:00
|
|
|
|
|
|
|
|
|
|
if (!empty($domainData)) {
|
|
|
|
|
|
$order->update_meta_data('_licensed_product_domains', $domainData);
|
|
|
|
|
|
$order->save();
|
|
|
|
|
|
}
|
2026-01-21 18:55:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-25 18:31:36 +01:00
|
|
|
|
* Display domains in admin order view
|
2026-01-21 18:55:18 +01:00
|
|
|
|
*/
|
|
|
|
|
|
public function displayDomainInAdmin(\WC_Order $order): void
|
|
|
|
|
|
{
|
2026-01-25 18:31:36 +01:00
|
|
|
|
// Try new multi-domain format first
|
|
|
|
|
|
$domainData = $order->get_meta('_licensed_product_domains');
|
|
|
|
|
|
if (!empty($domainData) && is_array($domainData)) {
|
|
|
|
|
|
$this->displayMultiDomainsInAdmin($domainData);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Fall back to legacy single domain
|
2026-01-21 18:55:18 +01:00
|
|
|
|
$domain = $order->get_meta('_licensed_product_domain');
|
|
|
|
|
|
if (!$domain) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
?>
|
|
|
|
|
|
<p>
|
|
|
|
|
|
<strong><?php esc_html_e('License Domain:', 'wc-licensed-product'); ?></strong>
|
|
|
|
|
|
<?php echo esc_html($domain); ?>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-01-25 18:31:36 +01:00
|
|
|
|
* Display multi-domain data in admin
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function displayMultiDomainsInAdmin(array $domainData): void
|
|
|
|
|
|
{
|
|
|
|
|
|
?>
|
|
|
|
|
|
<div class="wclp-order-domains">
|
|
|
|
|
|
<strong><?php esc_html_e('License Domains:', 'wc-licensed-product'); ?></strong>
|
|
|
|
|
|
<?php foreach ($domainData as $item): ?>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$product = wc_get_product($item['product_id']);
|
|
|
|
|
|
$productName = $product ? $product->get_name() : __('Unknown Product', 'wc-licensed-product');
|
|
|
|
|
|
?>
|
|
|
|
|
|
<p style="margin: 5px 0 5px 15px;">
|
|
|
|
|
|
<em><?php echo esc_html($productName); ?>:</em><br>
|
|
|
|
|
|
<?php echo esc_html(implode(', ', $item['domains'])); ?>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Display domains in order emails
|
2026-01-21 18:55:18 +01:00
|
|
|
|
*/
|
|
|
|
|
|
public function displayDomainInEmail(\WC_Order $order, bool $sentToAdmin, bool $plainText): void
|
|
|
|
|
|
{
|
2026-01-25 18:31:36 +01:00
|
|
|
|
// Try new multi-domain format first
|
|
|
|
|
|
$domainData = $order->get_meta('_licensed_product_domains');
|
|
|
|
|
|
if (!empty($domainData) && is_array($domainData)) {
|
|
|
|
|
|
$this->displayMultiDomainsInEmail($domainData, $plainText);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Fall back to legacy single domain
|
2026-01-21 18:55:18 +01:00
|
|
|
|
$domain = $order->get_meta('_licensed_product_domain');
|
|
|
|
|
|
if (!$domain) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ($plainText) {
|
|
|
|
|
|
echo "\n" . esc_html__('License Domain:', 'wc-licensed-product') . ' ' . esc_html($domain) . "\n";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
?>
|
|
|
|
|
|
<p>
|
|
|
|
|
|
<strong><?php esc_html_e('License Domain:', 'wc-licensed-product'); ?></strong>
|
|
|
|
|
|
<?php echo esc_html($domain); ?>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-25 18:31:36 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Display multi-domain data in email
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function displayMultiDomainsInEmail(array $domainData, bool $plainText): void
|
|
|
|
|
|
{
|
|
|
|
|
|
if ($plainText) {
|
|
|
|
|
|
echo "\n" . esc_html__('License Domains:', 'wc-licensed-product') . "\n";
|
|
|
|
|
|
foreach ($domainData as $item) {
|
|
|
|
|
|
$product = wc_get_product($item['product_id']);
|
|
|
|
|
|
$productName = $product ? $product->get_name() : __('Unknown Product', 'wc-licensed-product');
|
|
|
|
|
|
echo ' ' . esc_html($productName) . ': ' . esc_html(implode(', ', $item['domains'])) . "\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
?>
|
|
|
|
|
|
<div style="margin-bottom: 15px;">
|
|
|
|
|
|
<strong><?php esc_html_e('License Domains:', 'wc-licensed-product'); ?></strong>
|
|
|
|
|
|
<?php foreach ($domainData as $item): ?>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$product = wc_get_product($item['product_id']);
|
|
|
|
|
|
$productName = $product ? $product->get_name() : __('Unknown Product', 'wc-licensed-product');
|
|
|
|
|
|
?>
|
|
|
|
|
|
<p style="margin: 5px 0 5px 15px;">
|
|
|
|
|
|
<em><?php echo esc_html($productName); ?>:</em><br>
|
|
|
|
|
|
<?php echo esc_html(implode(', ', $item['domains'])); ?>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-21 18:55:18 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Validate domain format
|
|
|
|
|
|
*/
|
|
|
|
|
|
private function isValidDomain(string $domain): bool
|
|
|
|
|
|
{
|
|
|
|
|
|
// Basic domain validation
|
|
|
|
|
|
if (strlen($domain) > 255) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Check for valid domain pattern
|
|
|
|
|
|
$pattern = '/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/';
|
|
|
|
|
|
|
|
|
|
|
|
return (bool) preg_match($pattern, $domain);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|