2026-01-21 22:18:27 +01:00
< ? php
/**
* Order License Admin Controller
*
* @ package Jeremias\WcLicensedProduct\Admin
*/
declare ( strict_types = 1 );
namespace Jeremias\WcLicensedProduct\Admin ;
use Jeremias\WcLicensedProduct\License\License ;
use Jeremias\WcLicensedProduct\License\LicenseManager ;
/**
* Handles license display and editing on order admin pages
*/
final class OrderLicenseController
{
private LicenseManager $licenseManager ;
public function __construct ( LicenseManager $licenseManager )
{
$this -> licenseManager = $licenseManager ;
$this -> registerHooks ();
}
/**
* Register WordPress hooks
*/
private function registerHooks () : void
{
// Add licenses meta box to order edit page
add_action ( 'add_meta_boxes' , [ $this , 'addLicensesMetaBox' ]);
// Handle AJAX actions
add_action ( 'wp_ajax_wclp_update_order_domain' , [ $this , 'ajaxUpdateOrderDomain' ]);
add_action ( 'wp_ajax_wclp_update_license_domain' , [ $this , 'ajaxUpdateLicenseDomain' ]);
2026-01-24 16:06:13 +01:00
add_action ( 'wp_ajax_wclp_generate_order_licenses' , [ $this , 'ajaxGenerateOrderLicenses' ]);
2026-01-21 22:18:27 +01:00
// Enqueue admin scripts
add_action ( 'admin_enqueue_scripts' , [ $this , 'enqueueScripts' ]);
}
/**
* Add licenses meta box to order edit page
*/
public function addLicensesMetaBox () : void
{
// Support both classic post type and HPOS
$screen = wc_get_container () -> get ( \Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController :: class ) -> custom_orders_table_usage_is_enabled ()
? wc_get_page_screen_id ( 'shop-order' )
: 'shop_order' ;
add_meta_box (
'wclp_order_licenses' ,
__ ( 'Product Licenses' , 'wc-licensed-product' ),
[ $this , 'renderLicensesMetaBox' ],
$screen ,
'normal' ,
'default'
);
}
/**
* Render licenses meta box
*/
public function renderLicensesMetaBox ( $post_or_order ) : void
{
// Get order object - support both classic and HPOS
if ( $post_or_order instanceof \WC_Order ) {
$order = $post_or_order ;
} else {
$order = wc_get_order ( $post_or_order -> ID );
}
if ( ! $order ) {
echo '<p>' . esc_html__ ( 'Order not found.' , 'wc-licensed-product' ) . '</p>' ;
return ;
}
// Check if order has licensed products
$hasLicensedProduct = false ;
foreach ( $order -> get_items () as $item ) {
$product = $item -> get_product ();
if ( $product && $product -> is_type ( 'licensed' )) {
$hasLicensedProduct = true ;
break ;
}
}
if ( ! $hasLicensedProduct ) {
echo '<p>' . esc_html__ ( 'This order does not contain licensed products.' , 'wc-licensed-product' ) . '</p>' ;
return ;
}
2026-01-25 18:31:36 +01:00
// Check for multi-domain format first, then fall back to legacy single domain
$multiDomainData = $order -> get_meta ( '_licensed_product_domains' );
$legacyDomain = $order -> get_meta ( '_licensed_product_domain' );
$hasMultiDomain = ! empty ( $multiDomainData ) && is_array ( $multiDomainData );
2026-01-21 22:18:27 +01:00
// Get licenses for this order
$licenses = $this -> licenseManager -> getLicensesByOrder ( $order -> get_id ());
wp_nonce_field ( 'wclp_order_license_actions' , 'wclp_order_license_nonce' );
?>
< div class = " wclp-order-licenses " >
< div class = " wclp-order-domain-section " >
2026-01-25 18:31:36 +01:00
< h4 >< ? php esc_html_e ( 'Order Domains' , 'wc-licensed-product' ); ?> </h4>
< ? php if ( $hasMultiDomain ) : ?>
< p class = " description " >
< ? php esc_html_e ( 'Domains specified during checkout (multi-domain order).' , 'wc-licensed-product' ); ?>
</ p >
< div class = " wclp-multi-domain-display " style = " margin-top: 10px; " >
< ? php foreach ( $multiDomainData as $item ) : ?>
< ? php
$product = wc_get_product ( $item [ 'product_id' ]);
$productName = $product ? $product -> get_name () : __ ( 'Unknown Product' , 'wc-licensed-product' );
?>
< div class = " wclp-product-domains-item " style = " margin-bottom: 10px; padding: 10px; background: #f8f8f8; border-radius: 4px; " >
< strong >< ? php echo esc_html ( $productName ); ?> :</strong><br>
< code >< ? php echo esc_html ( implode ( ', ' , $item [ 'domains' ])); ?> </code>
</ div >
< ? php endforeach ; ?>
</ div >
< ? php else : ?>
< p class = " description " >
< ? php esc_html_e ( 'The domain specified during checkout. Changing this will not automatically update existing license domains.' , 'wc-licensed-product' ); ?>
</ p >
< div class = " wclp-inline-edit " >
< input type = " text "
id = " wclp-order-domain "
class = " regular-text "
value = " <?php echo esc_attr( $legacyDomain ); ?> "
data - order - id = " <?php echo esc_attr( $order->get_id ()); ?> "
placeholder = " <?php esc_attr_e('example.com', 'wc-licensed-product'); ?> " />
< button type = " button " class = " button " id = " wclp-save-order-domain " >
< ? php esc_html_e ( 'Save' , 'wc-licensed-product' ); ?>
</ button >
< span class = " spinner " ></ span >
< span class = " wclp-status-message " ></ span >
</ div >
< ? php endif ; ?>
2026-01-21 22:18:27 +01:00
</ div >
< hr />
< h4 >< ? php esc_html_e ( 'Licenses' , 'wc-licensed-product' ); ?> </h4>
2026-01-24 16:06:13 +01:00
< ? php
2026-01-25 18:31:36 +01:00
// Count expected licenses based on domain data
$expectedLicenses = 0 ;
if ( $hasMultiDomain ) {
// Multi-domain: count total domains across all products
foreach ( $multiDomainData as $item ) {
if ( isset ( $item [ 'domains' ]) && is_array ( $item [ 'domains' ])) {
$expectedLicenses += count ( $item [ 'domains' ]);
}
}
} else {
// Legacy: one license per licensed product
foreach ( $order -> get_items () as $item ) {
$product = $item -> get_product ();
if ( $product && $product -> is_type ( 'licensed' )) {
$expectedLicenses ++ ;
}
2026-01-24 16:06:13 +01:00
}
}
2026-01-25 18:31:36 +01:00
$missingLicenses = $expectedLicenses - count ( $licenses );
$hasDomainData = $hasMultiDomain || ! empty ( $legacyDomain );
2026-01-24 16:06:13 +01:00
?>
2026-01-21 22:18:27 +01:00
< ? php if ( empty ( $licenses )) : ?>
< p class = " description " >
< ? php esc_html_e ( 'No licenses have been generated for this order yet.' , 'wc-licensed-product' ); ?>
< ? php if ( $order -> is_paid ()) : ?>
< br />
< em >< ? php esc_html_e ( 'Licenses should be generated automatically when an order is paid. If missing, check that a domain was specified during checkout.' , 'wc-licensed-product' ); ?> </em>
< ? php else : ?>
< br />
< em >< ? php esc_html_e ( 'Licenses will be generated when the order is marked as paid/completed.' , 'wc-licensed-product' ); ?> </em>
< ? php endif ; ?>
</ p >
2026-01-25 18:31:36 +01:00
< ? php if ( $hasDomainData && $order -> is_paid ()) : ?>
2026-01-24 16:06:13 +01:00
< p style = " margin-top: 10px; " >
< button type = " button " class = " button button-primary " id = " wclp-generate-licenses " data - order - id = " <?php echo esc_attr( $order->get_id ()); ?> " >
< ? php esc_html_e ( 'Generate Licenses' , 'wc-licensed-product' ); ?>
</ button >
< span class = " spinner " style = " float: none; margin-top: 4px; " ></ span >
< span class = " wclp-generate-status " ></ span >
</ p >
2026-01-25 18:31:36 +01:00
< ? php elseif ( ! $hasDomainData ) : ?>
2026-01-24 16:06:13 +01:00
< p class = " description " style = " margin-top: 10px; color: #d63638; " >
< span class = " dashicons dashicons-warning " ></ span >
< ? php esc_html_e ( 'Please set the order domain above before generating licenses.' , 'wc-licensed-product' ); ?>
</ p >
< ? php endif ; ?>
2026-01-21 22:18:27 +01:00
< ? php else : ?>
< table class = " widefat striped wclp-licenses-table " >
< thead >
< tr >
< th >< ? php esc_html_e ( 'License Key' , 'wc-licensed-product' ); ?> </th>
< th >< ? php esc_html_e ( 'Product' , 'wc-licensed-product' ); ?> </th>
< th >< ? php esc_html_e ( 'Domain' , 'wc-licensed-product' ); ?> </th>
< th >< ? php esc_html_e ( 'Status' , 'wc-licensed-product' ); ?> </th>
< th >< ? php esc_html_e ( 'Expires' , 'wc-licensed-product' ); ?> </th>
< th >< ? php esc_html_e ( 'Actions' , 'wc-licensed-product' ); ?> </th>
</ tr >
</ thead >
< tbody >
< ? php foreach ( $licenses as $license ) : ?>
< ? php
$product = wc_get_product ( $license -> getProductId ());
$statusClass = 'wclp-status-' . $license -> getStatus ();
?>
< tr data - license - id = " <?php echo esc_attr( $license->getId ()); ?> " >
< td >
< code class = " wclp-license-key " >< ? php echo esc_html ( $license -> getLicenseKey ()); ?> </code>
</ td >
< td >
< ? php if ( $product ) : ?>
< a href = " <?php echo esc_url(get_edit_post_link( $product->get_id ())); ?> " >
< ? php echo esc_html ( $product -> get_name ()); ?>
</ a >
< ? php else : ?>
< ? php esc_html_e ( 'Unknown' , 'wc-licensed-product' ); ?>
< ? php endif ; ?>
</ td >
< td >
< div class = " wclp-license-domain-edit " >
< span class = " wclp-domain-display " >< ? php echo esc_html ( $license -> getDomain ()); ?> </span>
< input type = " text "
class = " wclp-domain-input regular-text "
value = " <?php echo esc_attr( $license->getDomain ()); ?> "
style = " display: none; " />
< button type = " button " class = " button-link wclp-edit-domain-btn " title = " <?php esc_attr_e('Edit domain', 'wc-licensed-product'); ?> " >
< span class = " dashicons dashicons-edit " ></ span >
</ button >
< button type = " button " class = " button button-small wclp-save-domain-btn " style = " display: none; " >
< ? php esc_html_e ( 'Save' , 'wc-licensed-product' ); ?>
</ button >
< button type = " button " class = " button-link wclp-cancel-domain-btn " style = " display: none; " >
< ? php esc_html_e ( 'Cancel' , 'wc-licensed-product' ); ?>
</ button >
< span class = " spinner " ></ span >
</ div >
</ td >
< td >
< span class = " wclp-license-status <?php echo esc_attr( $statusClass ); ?> " >
< ? php echo esc_html ( ucfirst ( $license -> getStatus ())); ?>
</ span >
</ td >
< td >
< ? php
$expiresAt = $license -> getExpiresAt ();
if ( $expiresAt ) {
echo esc_html ( $expiresAt -> format ( get_option ( 'date_format' )));
} else {
echo '<span class="wclp-lifetime">' . esc_html__ ( 'Lifetime' , 'wc-licensed-product' ) . '</span>' ;
}
?>
</ td >
< td >
< a href = " <?php echo esc_url(admin_url('admin.php?page=wc-licenses&s=' . urlencode( $license->getLicenseKey ()))); ?> "
class = " button button-small "
title = " <?php esc_attr_e('View in Licenses', 'wc-licensed-product'); ?> " >
< span class = " dashicons dashicons-visibility " style = " vertical-align: middle; " ></ span >
</ a >
</ td >
</ tr >
< ? php endforeach ; ?>
</ tbody >
</ table >
< p class = " description " style = " margin-top: 10px; " >
< ? php
printf (
/* translators: %s: Link to licenses page */
esc_html__ ( 'For more actions (revoke, extend, delete), go to the %s page.' , 'wc-licensed-product' ),
'<a href="' . esc_url ( admin_url ( 'admin.php?page=wc-licenses' )) . '">' . esc_html__ ( 'Licenses' , 'wc-licensed-product' ) . '</a>'
);
?>
</ p >
2026-01-24 16:06:13 +01:00
2026-01-25 18:31:36 +01:00
< ? php if ( $missingLicenses > 0 && $hasDomainData && $order -> is_paid ()) : ?>
2026-01-24 16:06:13 +01:00
< p style = " margin-top: 10px; " >
< span class = " dashicons dashicons-warning " style = " color: #dba617; " ></ span >
< ? php
printf (
/* translators: %d: Number of missing licenses */
esc_html ( _n (
'%d licensed product is missing a license.' ,
'%d licensed products are missing licenses.' ,
$missingLicenses ,
'wc-licensed-product'
)),
$missingLicenses
);
?>
< button type = " button " class = " button " id = " wclp-generate-licenses " data - order - id = " <?php echo esc_attr( $order->get_id ()); ?> " >
< ? php esc_html_e ( 'Generate Missing Licenses' , 'wc-licensed-product' ); ?>
</ button >
< span class = " spinner " style = " float: none; margin-top: 4px; " ></ span >
< span class = " wclp-generate-status " ></ span >
</ p >
< ? php endif ; ?>
2026-01-21 22:18:27 +01:00
< ? php endif ; ?>
</ div >
< style >
. wclp - order - licenses { padding : 10 px 0 ; }
. wclp - order - domain - section { margin - bottom : 15 px ; }
. wclp - inline - edit { display : flex ; align - items : center ; gap : 8 px ; margin - top : 8 px ; }
. wclp - inline - edit . spinner { float : none ; margin : 0 ; }
. wclp - status - message { font - style : italic ; color : #666; }
. wclp - status - message . success { color : #46b450; }
. wclp - status - message . error { color : #dc3232; }
. wclp - licenses - table { margin - top : 10 px ; }
. wclp - licenses - table th , . wclp - licenses - table td { padding : 8 px 10 px ; vertical - align : middle ; }
. wclp - license - key { font - size : 12 px ; }
. wclp - license - domain - edit { display : flex ; align - items : center ; gap : 5 px ; flex - wrap : wrap ; }
. wclp - license - domain - edit . spinner { float : none ; margin : 0 ; }
. wclp - domain - input { max - width : 200 px ; }
. wclp - license - status { padding : 3 px 8 px ; border - radius : 3 px ; font - size : 11 px ; font - weight : 600 ; text - transform : uppercase ; }
. wclp - status - active { background : #d4edda; color: #155724; }
. wclp - status - inactive { background : #fff3cd; color: #856404; }
. wclp - status - expired { background : #f8d7da; color: #721c24; }
. wclp - status - revoked { background : #d6d8db; color: #383d41; }
. wclp - lifetime { color : #0073aa; font-weight: 500; }
. wclp - edit - domain - btn { color : #0073aa; text-decoration: none; }
. wclp - edit - domain - btn . dashicons { font - size : 16 px ; width : 16 px ; height : 16 px ; }
2026-01-24 16:06:13 +01:00
. wclp - generate - status { font - style : italic ; margin - left : 8 px ; }
. wclp - generate - status . success { color : #46b450; }
. wclp - generate - status . error { color : #dc3232; }
2026-01-21 22:18:27 +01:00
</ style >
< ? php
}
/**
* Enqueue admin scripts
*/
public function enqueueScripts ( string $hook ) : void
{
// Check if we're on an order edit page
$screen = get_current_screen ();
if ( ! $screen ) {
return ;
}
$isOrderEdit = in_array ( $screen -> id , [ 'shop_order' , 'woocommerce_page_wc-orders' ], true )
|| ( isset ( $_GET [ 'page' ]) && $_GET [ 'page' ] === 'wc-orders' && isset ( $_GET [ 'action' ]) && $_GET [ 'action' ] === 'edit' );
if ( ! $isOrderEdit ) {
return ;
}
wp_enqueue_script (
'wclp-order-licenses' ,
WC_LICENSED_PRODUCT_PLUGIN_URL . 'assets/js/order-licenses.js' ,
[ 'jquery' ],
WC_LICENSED_PRODUCT_VERSION ,
true
);
wp_localize_script ( 'wclp-order-licenses' , 'wclpOrderLicenses' , [
'ajaxUrl' => admin_url ( 'admin-ajax.php' ),
'nonce' => wp_create_nonce ( 'wclp_order_license_actions' ),
'strings' => [
'saving' => __ ( 'Saving...' , 'wc-licensed-product' ),
'saved' => __ ( 'Saved!' , 'wc-licensed-product' ),
2026-01-24 16:06:13 +01:00
'error' => __ ( 'Error. Please try again.' , 'wc-licensed-product' ),
2026-01-21 22:18:27 +01:00
'invalidDomain' => __ ( 'Please enter a valid domain.' , 'wc-licensed-product' ),
2026-01-24 16:06:13 +01:00
'generating' => __ ( 'Generating...' , 'wc-licensed-product' ),
2026-01-21 22:18:27 +01:00
],
]);
}
/**
* AJAX handler for updating order domain
*/
public function ajaxUpdateOrderDomain () : void
{
check_ajax_referer ( 'wclp_order_license_actions' , 'nonce' );
if ( ! current_user_can ( 'manage_woocommerce' )) {
wp_send_json_error ([ 'message' => __ ( 'Permission denied.' , 'wc-licensed-product' )]);
}
$orderId = absint ( $_POST [ 'order_id' ] ? ? 0 );
$domain = sanitize_text_field ( $_POST [ 'domain' ] ? ? '' );
if ( ! $orderId ) {
wp_send_json_error ([ 'message' => __ ( 'Invalid order ID.' , 'wc-licensed-product' )]);
}
$order = wc_get_order ( $orderId );
if ( ! $order ) {
wp_send_json_error ([ 'message' => __ ( 'Order not found.' , 'wc-licensed-product' )]);
}
// Normalize and validate domain
$normalizedDomain = $this -> licenseManager -> normalizeDomain ( $domain );
if ( ! empty ( $domain ) && ! $this -> isValidDomain ( $normalizedDomain )) {
wp_send_json_error ([ 'message' => __ ( 'Invalid domain format.' , 'wc-licensed-product' )]);
}
// Update order meta
$order -> update_meta_data ( '_licensed_product_domain' , $normalizedDomain );
$order -> save ();
wp_send_json_success ([
'message' => __ ( 'Order domain updated.' , 'wc-licensed-product' ),
'domain' => $normalizedDomain ,
]);
}
/**
* AJAX handler for updating license domain
*/
public function ajaxUpdateLicenseDomain () : void
{
check_ajax_referer ( 'wclp_order_license_actions' , 'nonce' );
if ( ! current_user_can ( 'manage_woocommerce' )) {
wp_send_json_error ([ 'message' => __ ( 'Permission denied.' , 'wc-licensed-product' )]);
}
$licenseId = absint ( $_POST [ 'license_id' ] ? ? 0 );
$domain = sanitize_text_field ( $_POST [ 'domain' ] ? ? '' );
if ( ! $licenseId ) {
wp_send_json_error ([ 'message' => __ ( 'Invalid license ID.' , 'wc-licensed-product' )]);
}
if ( empty ( $domain )) {
wp_send_json_error ([ 'message' => __ ( 'Domain cannot be empty.' , 'wc-licensed-product' )]);
}
// Normalize and validate domain
$normalizedDomain = $this -> licenseManager -> normalizeDomain ( $domain );
if ( ! $this -> isValidDomain ( $normalizedDomain )) {
wp_send_json_error ([ 'message' => __ ( 'Invalid domain format.' , 'wc-licensed-product' )]);
}
// Get license to verify it exists
$license = $this -> licenseManager -> getLicenseById ( $licenseId );
if ( ! $license ) {
wp_send_json_error ([ 'message' => __ ( 'License not found.' , 'wc-licensed-product' )]);
}
// Update license domain
$success = $this -> licenseManager -> updateLicenseDomain ( $licenseId , $normalizedDomain );
if ( $success ) {
wp_send_json_success ([
'message' => __ ( 'License domain updated.' , 'wc-licensed-product' ),
'domain' => $normalizedDomain ,
]);
} else {
wp_send_json_error ([ 'message' => __ ( 'Failed to update license domain.' , 'wc-licensed-product' )]);
}
}
/**
* Validate domain format
*/
private function isValidDomain ( string $domain ) : bool
{
if ( empty ( $domain )) {
return true ; // Empty is allowed for order domain
}
if ( strlen ( $domain ) > 255 ) {
return false ;
}
$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 );
}
2026-01-24 16:06:13 +01:00
/**
* AJAX handler for generating order licenses
*/
public function ajaxGenerateOrderLicenses () : void
{
check_ajax_referer ( 'wclp_order_license_actions' , 'nonce' );
if ( ! current_user_can ( 'manage_woocommerce' )) {
wp_send_json_error ([ 'message' => __ ( 'Permission denied.' , 'wc-licensed-product' )]);
}
$orderId = absint ( $_POST [ 'order_id' ] ? ? 0 );
if ( ! $orderId ) {
wp_send_json_error ([ 'message' => __ ( 'Invalid order ID.' , 'wc-licensed-product' )]);
}
$order = wc_get_order ( $orderId );
if ( ! $order ) {
wp_send_json_error ([ 'message' => __ ( 'Order not found.' , 'wc-licensed-product' )]);
}
// Check if order is paid
if ( ! $order -> is_paid ()) {
wp_send_json_error ([ 'message' => __ ( 'Order must be paid before licenses can be generated.' , 'wc-licensed-product' )]);
}
2026-01-25 18:31:36 +01:00
// Check for multi-domain format first
$multiDomainData = $order -> get_meta ( '_licensed_product_domains' );
$legacyDomain = $order -> get_meta ( '_licensed_product_domain' );
2026-01-24 16:06:13 +01:00
2026-01-25 18:31:36 +01:00
if ( ! empty ( $multiDomainData ) && is_array ( $multiDomainData )) {
// Multi-domain format
$result = $this -> generateMultiDomainLicenses ( $order , $multiDomainData );
} elseif ( ! empty ( $legacyDomain )) {
// Legacy single domain format
$result = $this -> generateLegacyLicenses ( $order , $legacyDomain );
} else {
wp_send_json_error ([ 'message' => __ ( 'Please set the order domain before generating licenses.' , 'wc-licensed-product' )]);
return ;
2026-01-24 16:06:13 +01:00
}
2026-01-25 18:31:36 +01:00
if ( $result [ 'generated' ] > 0 ) {
2026-01-24 16:06:13 +01:00
wp_send_json_success ([
'message' => sprintf (
/* translators: %d: Number of licenses generated */
_n (
'%d license generated successfully.' ,
'%d licenses generated successfully.' ,
2026-01-25 18:31:36 +01:00
$result [ 'generated' ],
2026-01-24 16:06:13 +01:00
'wc-licensed-product'
),
2026-01-25 18:31:36 +01:00
$result [ 'generated' ]
2026-01-24 16:06:13 +01:00
),
2026-01-25 18:31:36 +01:00
'generated' => $result [ 'generated' ],
'skipped' => $result [ 'skipped' ],
2026-01-24 16:06:13 +01:00
'reload' => true ,
]);
} else {
wp_send_json_success ([
'message' => __ ( 'All licenses already exist for this order.' , 'wc-licensed-product' ),
'generated' => 0 ,
2026-01-25 18:31:36 +01:00
'skipped' => $result [ 'skipped' ],
2026-01-24 16:06:13 +01:00
'reload' => false ,
]);
}
}
2026-01-25 18:31:36 +01:00
/**
* Generate licenses for multi - domain format
*/
private function generateMultiDomainLicenses ( \WC_Order $order , array $domainData ) : array
{
$generated = 0 ;
$skipped = 0 ;
$orderId = $order -> get_id ();
$customerId = $order -> get_customer_id ();
// Index domains by product ID
$domainsByProduct = [];
foreach ( $domainData as $item ) {
if ( isset ( $item [ 'product_id' ]) && isset ( $item [ 'domains' ]) && is_array ( $item [ 'domains' ])) {
$domainsByProduct [( int ) $item [ 'product_id' ]] = $item [ 'domains' ];
}
}
foreach ( $order -> get_items () as $item ) {
$product = $item -> get_product ();
if ( ! $product || ! $product -> is_type ( 'licensed' )) {
continue ;
}
$productId = $product -> get_id ();
$domains = $domainsByProduct [ $productId ] ? ? [];
// Get existing licenses for this product
$existingLicenses = $this -> licenseManager -> getLicensesByOrderAndProduct ( $orderId , $productId );
$existingDomains = array_map ( fn ( $l ) => $l -> getDomain (), $existingLicenses );
foreach ( $domains as $domain ) {
$normalizedDomain = $this -> licenseManager -> normalizeDomain ( $domain );
// Skip if license already exists for this domain
if ( in_array ( $normalizedDomain , $existingDomains , true )) {
$skipped ++ ;
continue ;
}
$license = $this -> licenseManager -> generateLicense (
$orderId ,
$productId ,
$customerId ,
$normalizedDomain
);
if ( $license ) {
$generated ++ ;
}
}
}
return [ 'generated' => $generated , 'skipped' => $skipped ];
}
/**
* Generate licenses for legacy single domain format
*/
private function generateLegacyLicenses ( \WC_Order $order , string $domain ) : array
{
$generated = 0 ;
$skipped = 0 ;
$orderId = $order -> get_id ();
$customerId = $order -> get_customer_id ();
foreach ( $order -> get_items () as $item ) {
$product = $item -> get_product ();
if ( ! $product || ! $product -> is_type ( 'licensed' )) {
continue ;
}
// Check if license already exists
$existing = $this -> licenseManager -> getLicenseByOrderAndProduct ( $orderId , $product -> get_id ());
if ( $existing ) {
$skipped ++ ;
continue ;
}
$license = $this -> licenseManager -> generateLicense (
$orderId ,
$product -> get_id (),
$customerId ,
$domain
);
if ( $license ) {
$generated ++ ;
}
}
return [ 'generated' => $generated , 'skipped' => $skipped ];
}
2026-01-21 22:18:27 +01:00
}