2025-12-21 05:14:19 +01:00
< ? php
/**
* WooCommerce Settings Integration
*
2026-01-25 19:39:12 +01:00
* Adds Tier & Package Prices settings to WooCommerce Settings with sub - tabs
2025-12-21 05:14:19 +01:00
*
* @ package WC_Tier_Package_Prices
*/
if ( ! defined ( 'ABSPATH' )) {
exit ;
}
if ( ! class_exists ( 'WC_Settings_Page' )) {
return ;
}
/**
* WC_TPP_Settings class
*/
Release version 1.1.13 - Critical class redeclaration fixes
Fixed critical class redeclaration errors affecting all plugin functionality
in version 1.1.12. All plugin component classes now properly guarded.
**CRITICAL FIXES:**
- Plugin completely non-functional in v1.1.12 (no settings, no frontend, no backend)
- Fatal errors for WC_TPP_Admin, WC_TPP_Product_Meta, WC_TPP_Frontend, WC_TPP_Cart, WC_TPP_Settings classes
- All classes now wrapped in class_exists() checks
**Files Modified:**
- includes/class-wc-tpp-admin.php
- includes/class-wc-tpp-product-meta.php
- includes/class-wc-tpp-frontend.php
- includes/class-wc-tpp-cart.php
- includes/class-wc-tpp-settings.php
**Technical Details:**
- Completes comprehensive redeclaration protection started in v1.1.9-1.1.12
- All 2 functions, 4 constants, and 6 classes now protected
- Plugin activates successfully and all features functional
- Settings page, product meta boxes, frontend display, cart integration all working
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 19:02:18 +01:00
if ( ! class_exists ( 'WC_TPP_Settings' )) {
class WC_TPP_Settings extends WC_Settings_Page {
2025-12-21 05:14:19 +01:00
2026-01-25 19:39:12 +01:00
/**
* Constructor
*/
public function __construct () {
$this -> id = 'tier_package_prices' ;
$this -> label = __ ( 'Tier & Package Prices' , 'wc-tier-package-prices' );
2025-12-21 05:14:19 +01:00
2026-01-25 19:39:12 +01:00
parent :: __construct ();
2025-12-21 05:14:19 +01:00
2026-01-25 19:39:12 +01:00
// Add AJAX handlers for license validation
add_action ( 'wp_ajax_wc_tpp_validate_license' , array ( $this , 'ajax_validate_license' ));
add_action ( 'wp_ajax_wc_tpp_activate_license' , array ( $this , 'ajax_activate_license' ));
}
/**
* Get own sections - Modern WooCommerce pattern
*
* @ return array
*/
protected function get_own_sections () {
return array (
'' => __ ( 'General' , 'wc-tier-package-prices' ),
'license' => __ ( 'License' , 'wc-tier-package-prices' ),
);
}
2025-12-21 05:14:19 +01:00
2026-01-25 19:39:12 +01:00
/**
* Get settings for the default ( General ) section
*
* @ return array
*/
protected function get_settings_for_default_section () {
return array (
2025-12-21 05:14:19 +01:00
array (
'title' => __ ( 'Tier & Package Prices Settings' , 'wc-tier-package-prices' ),
'type' => 'title' ,
'desc' => __ ( 'Configure tier pricing and package pricing options for your WooCommerce products.' , 'wc-tier-package-prices' ),
'id' => 'wc_tpp_settings' ,
),
array (
'title' => __ ( 'Enable Tier Pricing' , 'wc-tier-package-prices' ),
'desc' => __ ( 'Enable tier pricing for products' , 'wc-tier-package-prices' ),
'id' => 'wc_tpp_enable_tier_pricing' ,
'default' => 'yes' ,
'type' => 'checkbox' ,
'desc_tip' => __ ( 'Allow quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities.' , 'wc-tier-package-prices' ),
),
array (
'title' => __ ( 'Enable Package Pricing' , 'wc-tier-package-prices' ),
'desc' => __ ( 'Enable fixed-price packages for products' , 'wc-tier-package-prices' ),
'id' => 'wc_tpp_enable_package_pricing' ,
'default' => 'yes' ,
'type' => 'checkbox' ,
'desc_tip' => __ ( 'Allow fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100.' , 'wc-tier-package-prices' ),
),
array (
'title' => __ ( 'Display Pricing Table' , 'wc-tier-package-prices' ),
'desc' => __ ( 'Show tier and package pricing table on product pages' , 'wc-tier-package-prices' ),
'id' => 'wc_tpp_display_table' ,
'default' => 'yes' ,
'type' => 'checkbox' ,
'desc_tip' => __ ( 'Display the pricing table to customers on product pages.' , 'wc-tier-package-prices' ),
),
array (
'title' => __ ( 'Display Position' , 'wc-tier-package-prices' ),
'desc' => __ ( 'Choose where to display the pricing table on product pages.' , 'wc-tier-package-prices' ),
'id' => 'wc_tpp_display_position' ,
'default' => 'after_add_to_cart' ,
'type' => 'select' ,
'class' => 'wc-enhanced-select' ,
'css' => 'min-width:300px;' ,
'desc_tip' => true ,
'options' => array (
'before_add_to_cart' => __ ( 'Before Add to Cart Button' , 'wc-tier-package-prices' ),
'after_add_to_cart' => __ ( 'After Add to Cart Button' , 'wc-tier-package-prices' ),
'after_price' => __ ( 'After Price' , 'wc-tier-package-prices' ),
),
),
2025-12-21 15:54:04 +01:00
array (
'title' => __ ( 'Restrict to Package Quantities' , 'wc-tier-package-prices' ),
'desc' => __ ( 'Limit quantities to defined package sizes only' , 'wc-tier-package-prices' ),
'id' => 'wc_tpp_restrict_package_quantities' ,
'default' => 'no' ,
'type' => 'checkbox' ,
'desc_tip' => __ ( 'When enabled, customers can only purchase products in the exact quantities defined in packages. The quantity input field will be hidden and replaced with package selection buttons.' , 'wc-tier-package-prices' ),
),
2025-12-21 05:14:19 +01:00
array (
'type' => 'sectionend' ,
'id' => 'wc_tpp_settings' ,
),
);
}
2026-01-25 19:39:12 +01:00
/**
* Get settings for the License section
*
* @ return array
*/
protected function get_settings_for_license_section () {
return array (
array (
'title' => __ ( 'License Management' , 'wc-tier-package-prices' ),
'type' => 'title' ,
'desc' => __ ( 'Enter your license key to receive updates and support.' , 'wc-tier-package-prices' ),
'id' => 'wc_tpp_license_settings' ,
),
2025-12-21 05:14:19 +01:00
2026-01-25 19:39:12 +01:00
array (
'title' => __ ( 'License Server URL' , 'wc-tier-package-prices' ),
'desc' => __ ( 'The URL of the license server.' , 'wc-tier-package-prices' ),
'id' => 'wc_tpp_license_server_url' ,
'type' => 'url' ,
'default' => '' ,
'css' => 'min-width:400px;' ,
'desc_tip' => true ,
),
2025-12-21 05:14:19 +01:00
2026-01-25 19:39:12 +01:00
array (
'title' => __ ( 'License Key' , 'wc-tier-package-prices' ),
'desc' => __ ( 'Your license key for this plugin.' , 'wc-tier-package-prices' ),
'id' => 'wc_tpp_license_key' ,
'type' => 'text' ,
'default' => '' ,
'css' => 'min-width:400px;' ,
'desc_tip' => true ,
),
2026-01-27 19:23:42 +01:00
array (
'title' => __ ( 'Server Secret' , 'wc-tier-package-prices' ),
'desc' => __ ( 'The shared secret for secure communication with the license server.' , 'wc-tier-package-prices' ),
'id' => 'wc_tpp_license_server_secret' ,
'type' => 'password' ,
'default' => '' ,
'css' => 'min-width:400px;' ,
'desc_tip' => true ,
),
2026-01-25 19:39:12 +01:00
array (
'title' => __ ( 'License Status' , 'wc-tier-package-prices' ),
'type' => 'wc_tpp_license_status' ,
'id' => 'wc_tpp_license_status_display' ,
),
array (
'type' => 'sectionend' ,
'id' => 'wc_tpp_license_settings' ,
),
);
}
/**
* Get cached license status
*
* @ return array | false
*/
private function get_cached_license_status () {
return get_transient ( 'wc_tpp_license_status' );
}
/**
* AJAX handler for license validation
*/
public function ajax_validate_license () {
check_ajax_referer ( 'wc_tpp_license_nonce' , 'nonce' );
if ( ! current_user_can ( 'manage_woocommerce' )) {
wp_send_json_error ( array ( 'message' => __ ( 'Permission denied.' , 'wc-tier-package-prices' )));
}
$license_key = sanitize_text_field ( wp_unslash ( $_POST [ 'license_key' ] ? ? '' ));
$server_url = esc_url_raw ( wp_unslash ( $_POST [ 'server_url' ] ? ? '' ));
2026-01-27 19:23:42 +01:00
$server_secret = sanitize_text_field ( wp_unslash ( $_POST [ 'server_secret' ] ? ? '' ));
2026-01-25 19:39:12 +01:00
2026-01-27 19:23:42 +01:00
if ( empty ( $license_key ) || empty ( $server_url ) || empty ( $server_secret )) {
wp_send_json_error ( array ( 'message' => __ ( 'License key, server URL, and server secret are required.' , 'wc-tier-package-prices' )));
2026-01-25 19:39:12 +01:00
}
try {
2026-01-27 19:23:42 +01:00
$client = $this -> get_license_client ( $server_url , $server_secret );
2026-01-25 19:39:12 +01:00
$domain = $this -> get_current_domain ();
$result = $client -> validate ( $license_key , $domain );
// Cache the status
set_transient ( 'wc_tpp_license_status' , array (
'valid' => true ,
'product_id' => $result -> productId ,
'expires_at' => $result -> expiresAt ? -> format ( 'Y-m-d H:i:s' ),
'is_lifetime' => $result -> isLifetime (),
'checked_at' => current_time ( 'mysql' ),
), DAY_IN_SECONDS );
wp_send_json_success ( array (
'message' => __ ( 'License is valid!' , 'wc-tier-package-prices' ),
'status' => $this -> get_cached_license_status (),
));
2026-01-27 19:23:42 +01:00
} catch ( \Magdev\WcLicensedProductClient\Exception\RateLimitExceededException $e ) {
wp_send_json_error ( array (
'message' => sprintf (
/* translators: %d: Number of seconds to wait */
__ ( 'Rate limit exceeded. Please try again in %d seconds.' , 'wc-tier-package-prices' ),
$e -> retryAfter ? ? 60
),
'code' => 'rate_limit_exceeded' ,
'retry_after' => $e -> retryAfter ,
));
} catch ( \Magdev\WcLicensedProductClient\Security\SignatureException $e ) {
delete_transient ( 'wc_tpp_license_status' );
wp_send_json_error ( array (
'message' => __ ( 'Response signature verification failed. Please check your server secret.' , 'wc-tier-package-prices' ),
'code' => 'signature_error' ,
));
2026-01-25 19:39:12 +01:00
} catch ( \Magdev\WcLicensedProductClient\Exception\LicenseException $e ) {
delete_transient ( 'wc_tpp_license_status' );
wp_send_json_error ( array (
'message' => $e -> getMessage (),
'code' => $e -> errorCode ? ? 'unknown' ,
));
2026-01-27 19:23:42 +01:00
} catch ( \InvalidArgumentException $e ) {
wp_send_json_error ( array (
'message' => $e -> getMessage (),
'code' => 'invalid_url' ,
));
2026-01-25 19:39:12 +01:00
} catch ( \Exception $e ) {
delete_transient ( 'wc_tpp_license_status' );
wp_send_json_error ( array (
2026-01-27 19:23:42 +01:00
'message' => __ ( 'An unexpected error occurred. Please try again.' , 'wc-tier-package-prices' ),
2026-01-25 19:39:12 +01:00
'code' => 'exception' ,
));
}
}
/**
* AJAX handler for license activation
*/
public function ajax_activate_license () {
check_ajax_referer ( 'wc_tpp_license_nonce' , 'nonce' );
if ( ! current_user_can ( 'manage_woocommerce' )) {
wp_send_json_error ( array ( 'message' => __ ( 'Permission denied.' , 'wc-tier-package-prices' )));
}
$license_key = sanitize_text_field ( wp_unslash ( $_POST [ 'license_key' ] ? ? '' ));
$server_url = esc_url_raw ( wp_unslash ( $_POST [ 'server_url' ] ? ? '' ));
2026-01-27 19:23:42 +01:00
$server_secret = sanitize_text_field ( wp_unslash ( $_POST [ 'server_secret' ] ? ? '' ));
2026-01-25 19:39:12 +01:00
2026-01-27 19:23:42 +01:00
if ( empty ( $license_key ) || empty ( $server_url ) || empty ( $server_secret )) {
wp_send_json_error ( array ( 'message' => __ ( 'License key, server URL, and server secret are required.' , 'wc-tier-package-prices' )));
2026-01-25 19:39:12 +01:00
}
try {
2026-01-27 19:23:42 +01:00
$client = $this -> get_license_client ( $server_url , $server_secret );
2026-01-25 19:39:12 +01:00
$domain = $this -> get_current_domain ();
$result = $client -> activate ( $license_key , $domain );
if ( $result -> success ) {
// Validate to get full status after activation
$validate_result = $client -> validate ( $license_key , $domain );
set_transient ( 'wc_tpp_license_status' , array (
'valid' => true ,
'product_id' => $validate_result -> productId ,
'expires_at' => $validate_result -> expiresAt ? -> format ( 'Y-m-d H:i:s' ),
'is_lifetime' => $validate_result -> isLifetime (),
'checked_at' => current_time ( 'mysql' ),
), DAY_IN_SECONDS );
wp_send_json_success ( array (
'message' => __ ( 'License activated successfully!' , 'wc-tier-package-prices' ),
'status' => $this -> get_cached_license_status (),
));
}
wp_send_json_error ( array ( 'message' => $result -> message ));
2026-01-27 19:23:42 +01:00
} catch ( \Magdev\WcLicensedProductClient\Exception\RateLimitExceededException $e ) {
wp_send_json_error ( array (
'message' => sprintf (
/* translators: %d: Number of seconds to wait */
__ ( 'Rate limit exceeded. Please try again in %d seconds.' , 'wc-tier-package-prices' ),
$e -> retryAfter ? ? 60
),
'code' => 'rate_limit_exceeded' ,
'retry_after' => $e -> retryAfter ,
));
} catch ( \Magdev\WcLicensedProductClient\Security\SignatureException $e ) {
wp_send_json_error ( array (
'message' => __ ( 'Response signature verification failed. Please check your server secret.' , 'wc-tier-package-prices' ),
'code' => 'signature_error' ,
));
2026-01-25 19:39:12 +01:00
} catch ( \Magdev\WcLicensedProductClient\Exception\LicenseException $e ) {
wp_send_json_error ( array (
'message' => $e -> getMessage (),
'code' => $e -> errorCode ? ? 'unknown' ,
));
2026-01-27 19:23:42 +01:00
} catch ( \InvalidArgumentException $e ) {
2026-01-25 19:39:12 +01:00
wp_send_json_error ( array (
'message' => $e -> getMessage (),
2026-01-27 19:23:42 +01:00
'code' => 'invalid_url' ,
));
} catch ( \Exception $e ) {
wp_send_json_error ( array (
'message' => __ ( 'An unexpected error occurred. Please try again.' , 'wc-tier-package-prices' ),
2026-01-25 19:39:12 +01:00
'code' => 'exception' ,
));
}
}
/**
* Get license client instance
*
2026-01-27 19:23:42 +01:00
* Uses SecureLicenseClient for HMAC signature verification .
*
* @ param string $server_url License server URL .
* @ param string $server_secret Shared secret for signature verification .
2026-01-25 19:39:12 +01:00
* @ return \Magdev\WcLicensedProductClient\LicenseClientInterface
*/
2026-01-27 19:23:42 +01:00
private function get_license_client ( string $server_url , string $server_secret ) : \Magdev\WcLicensedProductClient\LicenseClientInterface {
2026-01-25 19:39:12 +01:00
$httpClient = \Symfony\Component\HttpClient\HttpClient :: create ();
2026-01-27 19:23:42 +01:00
return new \Magdev\WcLicensedProductClient\SecureLicenseClient (
2026-01-25 19:39:12 +01:00
httpClient : $httpClient ,
baseUrl : $server_url ,
2026-01-27 19:23:42 +01:00
serverSecret : $server_secret ,
2026-01-25 19:39:12 +01:00
);
}
/**
* Get current domain for license validation
*
* @ return string
*/
private function get_current_domain () : string {
return wp_parse_url ( home_url (), PHP_URL_HOST );
}
/**
* Output the settings
*/
public function output () {
global $current_section ;
// Register custom field type for license status display
add_action ( 'woocommerce_admin_field_wc_tpp_license_status' , array ( $this , 'output_license_status_field' ));
parent :: output ();
// Add JavaScript for license section
if ( 'license' === $current_section ) {
$this -> output_license_scripts ();
}
}
/**
* Output license status custom field
*
* @ param array $value Field configuration .
*/
public function output_license_status_field ( $value ) {
$status = $this -> get_cached_license_status ();
?>
< tr valign = " top " >
< th scope = " row " class = " titledesc " >
< label >< ? php esc_html_e ( 'License Status' , 'wc-tier-package-prices' ); ?> </label>
</ th >
< td class = " forminp " >
< div id = " wc-tpp-license-status-container " class = " <?php echo !empty( $status['valid'] ) ? 'valid' : 'invalid'; ?> " >
< ? php $this -> render_license_status_html ( $status ); ?>
</ div >
< p class = " description " style = " margin-top: 10px; " >
< button type = " button " class = " button " id = " wc-tpp-validate-license " >
< ? php esc_html_e ( 'Validate License' , 'wc-tier-package-prices' ); ?>
</ button >
< button type = " button " class = " button " id = " wc-tpp-activate-license " >
< ? php esc_html_e ( 'Activate License' , 'wc-tier-package-prices' ); ?>
</ button >
< span class = " spinner " id = " wc-tpp-license-spinner " ></ span >
</ p >
</ td >
</ tr >
< ? php
}
/**
* Render license status HTML
*
* @ param array | false $status License status data .
*/
private function render_license_status_html ( $status ) {
if ( empty ( $status )) {
echo '<span class="wc-tpp-license-inactive">' . esc_html__ ( 'No license activated' , 'wc-tier-package-prices' ) . '</span>' ;
return ;
}
if ( ! empty ( $status [ 'valid' ])) {
echo '<span class="wc-tpp-license-active">' . esc_html__ ( 'License Active' , 'wc-tier-package-prices' ) . '</span>' ;
if ( ! empty ( $status [ 'expires_at' ]) && empty ( $status [ 'is_lifetime' ])) {
echo '<br><small>' . sprintf (
/* translators: %s: Expiration date */
esc_html__ ( 'Expires: %s' , 'wc-tier-package-prices' ),
esc_html ( $status [ 'expires_at' ])
) . '</small>' ;
} elseif ( ! empty ( $status [ 'is_lifetime' ])) {
echo '<br><small>' . esc_html__ ( 'Lifetime License' , 'wc-tier-package-prices' ) . '</small>' ;
}
if ( ! empty ( $status [ 'checked_at' ])) {
echo '<br><small>' . sprintf (
/* translators: %s: Last check timestamp */
esc_html__ ( 'Last checked: %s' , 'wc-tier-package-prices' ),
esc_html ( $status [ 'checked_at' ])
) . '</small>' ;
}
} else {
echo '<span class="wc-tpp-license-inactive">' . esc_html__ ( 'License Invalid' , 'wc-tier-package-prices' ) . '</span>' ;
}
}
/**
* Output JavaScript for license management
*/
private function output_license_scripts () {
$nonce = wp_create_nonce ( 'wc_tpp_license_nonce' );
?>
< script type = " text/javascript " >
jQuery ( function ( $ ) {
var $validateBtn = $ ( '#wc-tpp-validate-license' );
var $activateBtn = $ ( '#wc-tpp-activate-license' );
var $spinner = $ ( '#wc-tpp-license-spinner' );
function getLicenseData () {
return {
license_key : $ ( '#wc_tpp_license_key' ) . val (),
server_url : $ ( '#wc_tpp_license_server_url' ) . val (),
2026-01-27 19:23:42 +01:00
server_secret : $ ( '#wc_tpp_license_server_secret' ) . val (),
2026-01-25 19:39:12 +01:00
nonce : '<?php echo esc_js($nonce); ?>'
};
}
function showSpinner () {
$spinner . addClass ( 'is-active' );
$validateBtn . prop ( 'disabled' , true );
$activateBtn . prop ( 'disabled' , true );
}
function hideSpinner () {
$spinner . removeClass ( 'is-active' );
$validateBtn . prop ( 'disabled' , false );
$activateBtn . prop ( 'disabled' , false );
}
$validateBtn . on ( 'click' , function () {
var data = getLicenseData ();
2026-01-27 19:23:42 +01:00
if ( ! data . license_key || ! data . server_url || ! data . server_secret ) {
alert ( '<?php echo esc_js(__(' Please enter license server URL , license key , and server secret . ', ' wc - tier - package - prices ')); ?>' );
2026-01-25 19:39:12 +01:00
return ;
}
showSpinner ();
$ . post ( ajaxurl , $ . extend ({ action : 'wc_tpp_validate_license' }, data ))
. done ( function ( response ) {
if ( response . success ) {
alert ( response . data . message );
location . reload ();
} else {
alert ( response . data . message || '<?php echo esc_js(__(' Validation failed . ', ' wc - tier - package - prices ')); ?>' );
}
})
. fail ( function () {
alert ( '<?php echo esc_js(__(' Request failed . Please try again . ', ' wc - tier - package - prices ')); ?>' );
})
. always ( hideSpinner );
});
$activateBtn . on ( 'click' , function () {
var data = getLicenseData ();
2026-01-27 19:23:42 +01:00
if ( ! data . license_key || ! data . server_url || ! data . server_secret ) {
alert ( '<?php echo esc_js(__(' Please enter license server URL , license key , and server secret . ', ' wc - tier - package - prices ')); ?>' );
2026-01-25 19:39:12 +01:00
return ;
}
showSpinner ();
$ . post ( ajaxurl , $ . extend ({ action : 'wc_tpp_activate_license' }, data ))
. done ( function ( response ) {
if ( response . success ) {
alert ( response . data . message );
location . reload ();
} else {
alert ( response . data . message || '<?php echo esc_js(__(' Activation failed . ', ' wc - tier - package - prices ')); ?>' );
}
})
. fail ( function () {
alert ( '<?php echo esc_js(__(' Request failed . Please try again . ', ' wc - tier - package - prices ')); ?>' );
})
. always ( hideSpinner );
});
});
</ script >
< ? php
}
2025-12-21 05:14:19 +01:00
}
}