Enhance Subscriptions, Affiliates, and Software Distribution modules
This commit is contained in:
@@ -220,6 +220,7 @@ class ProductsController
|
||||
$category = $request->get_param('category');
|
||||
$type = $request->get_param('type');
|
||||
$stock_status = $request->get_param('stock_status');
|
||||
$software_enabled = $request->get_param('software_enabled');
|
||||
$orderby = $request->get_param('orderby') ?: 'date';
|
||||
$order = $request->get_param('order') ?: 'DESC';
|
||||
|
||||
@@ -266,11 +267,19 @@ class ProductsController
|
||||
|
||||
// Stock status filter
|
||||
if ($stock_status) {
|
||||
$args['meta_query'] = [
|
||||
[
|
||||
'key' => '_stock_status',
|
||||
'value' => $stock_status,
|
||||
],
|
||||
$args['meta_query'] = $args['meta_query'] ?? [];
|
||||
$args['meta_query'][] = [
|
||||
'key' => '_stock_status',
|
||||
'value' => $stock_status,
|
||||
];
|
||||
}
|
||||
|
||||
// Software enabled filter
|
||||
if ($software_enabled === 'true' || $software_enabled === '1') {
|
||||
$args['meta_query'] = $args['meta_query'] ?? [];
|
||||
$args['meta_query'][] = [
|
||||
'key' => '_woonoow_software_enabled',
|
||||
'value' => 'yes',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -660,6 +669,26 @@ class ProductsController
|
||||
update_post_meta($product->get_id(), '_woonoow_affiliate_commission_rate', self::sanitize_number($data['affiliate_commission_rate']));
|
||||
}
|
||||
|
||||
// Software meta
|
||||
if (isset($data['software_enabled'])) {
|
||||
update_post_meta($product->get_id(), '_woonoow_software_enabled', $data['software_enabled'] ? 'yes' : 'no');
|
||||
}
|
||||
if (isset($data['software_slug'])) {
|
||||
update_post_meta($product->get_id(), '_woonoow_software_slug', sanitize_title($data['software_slug']));
|
||||
}
|
||||
if (isset($data['software_wp_enabled'])) {
|
||||
update_post_meta($product->get_id(), '_woonoow_software_wp_enabled', $data['software_wp_enabled'] ? 'yes' : 'no');
|
||||
}
|
||||
if (isset($data['software_requires_wp'])) {
|
||||
update_post_meta($product->get_id(), '_woonoow_software_requires_wp', sanitize_text_field($data['software_requires_wp']));
|
||||
}
|
||||
if (isset($data['software_tested_wp'])) {
|
||||
update_post_meta($product->get_id(), '_woonoow_software_tested_wp', sanitize_text_field($data['software_tested_wp']));
|
||||
}
|
||||
if (isset($data['software_requires_php'])) {
|
||||
update_post_meta($product->get_id(), '_woonoow_software_requires_php', sanitize_text_field($data['software_requires_php']));
|
||||
}
|
||||
|
||||
// Allow plugins to perform additional updates (Level 1 compatibility)
|
||||
do_action('woonoow/product_updated', $product, $data, $request);
|
||||
|
||||
@@ -819,6 +848,10 @@ class ProductsController
|
||||
'permalink' => get_permalink($product->get_id()),
|
||||
'date_created' => $product->get_date_created() ? $product->get_date_created()->date('Y-m-d H:i:s') : '',
|
||||
'date_modified' => $product->get_date_modified() ? $product->get_date_modified()->date('Y-m-d H:i:s') : '',
|
||||
'software_enabled' => get_post_meta($product->get_id(), '_woonoow_software_enabled', true) === 'yes',
|
||||
'software_slug' => get_post_meta($product->get_id(), '_woonoow_software_slug', true),
|
||||
'software_current_version' => get_post_meta($product->get_id(), '_woonoow_software_current_version', true),
|
||||
'software_wp_enabled' => get_post_meta($product->get_id(), '_woonoow_software_wp_enabled', true) === 'yes',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -877,6 +910,14 @@ class ProductsController
|
||||
$data['affiliate_enabled'] = get_post_meta($product->get_id(), '_woonoow_affiliate_enabled', true) === 'yes';
|
||||
$data['affiliate_commission_rate'] = get_post_meta($product->get_id(), '_woonoow_affiliate_commission_rate', true) ?: '';
|
||||
|
||||
// Software fields
|
||||
$data['software_enabled'] = get_post_meta($product->get_id(), '_woonoow_software_enabled', true) === 'yes';
|
||||
$data['software_slug'] = get_post_meta($product->get_id(), '_woonoow_software_slug', true) ?: '';
|
||||
$data['software_wp_enabled'] = get_post_meta($product->get_id(), '_woonoow_software_wp_enabled', true) === 'yes';
|
||||
$data['software_requires_wp'] = get_post_meta($product->get_id(), '_woonoow_software_requires_wp', true) ?: '';
|
||||
$data['software_tested_wp'] = get_post_meta($product->get_id(), '_woonoow_software_tested_wp', true) ?: '';
|
||||
$data['software_requires_php'] = get_post_meta($product->get_id(), '_woonoow_software_requires_php', true) ?: '';
|
||||
|
||||
// Images array (URLs) for frontend - featured + gallery
|
||||
$images = [];
|
||||
$featured_image_id = $product->get_image_id();
|
||||
@@ -1078,6 +1119,10 @@ class ProductsController
|
||||
'image_url' => $image_url,
|
||||
'image' => $image_url, // For form compatibility
|
||||
'license_duration_days' => get_post_meta($variation->get_id(), '_license_duration_days', true) ?: '',
|
||||
'subscription_signup_fee' => get_post_meta($variation->get_id(), '_woonoow_subscription_signup_fee', true) ?: '',
|
||||
'subscription_trial_days' => get_post_meta($variation->get_id(), '_woonoow_subscription_trial_days', true) ?: '',
|
||||
'subscription_period' => get_post_meta($variation->get_id(), '_woonoow_subscription_period', true) ?: '',
|
||||
'subscription_interval' => get_post_meta($variation->get_id(), '_woonoow_subscription_interval', true) ?: '',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1214,6 +1259,20 @@ class ProductsController
|
||||
update_post_meta($saved_id, '_license_duration_days', self::sanitize_number($var_data['license_duration_days']));
|
||||
}
|
||||
|
||||
// Save variation-level subscription fields
|
||||
if (isset($var_data['subscription_signup_fee'])) {
|
||||
update_post_meta($saved_id, '_woonoow_subscription_signup_fee', self::sanitize_number($var_data['subscription_signup_fee']));
|
||||
}
|
||||
if (isset($var_data['subscription_trial_days'])) {
|
||||
update_post_meta($saved_id, '_woonoow_subscription_trial_days', absint($var_data['subscription_trial_days']));
|
||||
}
|
||||
if (isset($var_data['subscription_period'])) {
|
||||
update_post_meta($saved_id, '_woonoow_subscription_period', sanitize_key($var_data['subscription_period']));
|
||||
}
|
||||
if (isset($var_data['subscription_interval'])) {
|
||||
update_post_meta($saved_id, '_woonoow_subscription_interval', absint($var_data['subscription_interval']));
|
||||
}
|
||||
|
||||
// Manually save attributes using direct database insert
|
||||
if (!empty($wc_attributes)) {
|
||||
global $wpdb;
|
||||
|
||||
@@ -90,6 +90,15 @@ class SoftwareController
|
||||
return current_user_can('manage_woocommerce');
|
||||
},
|
||||
]);
|
||||
|
||||
// Edit version
|
||||
register_rest_route($namespace, '/software/products/(?P<product_id>\d+)/versions/(?P<version_id>\d+)', [
|
||||
'methods' => 'PUT',
|
||||
'callback' => [__CLASS__, 'edit_version'],
|
||||
'permission_callback' => function () {
|
||||
return current_user_can('manage_woocommerce');
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,7 +136,7 @@ class SoftwareController
|
||||
// Log the check (optional - for analytics)
|
||||
do_action('woonoow/software/update_check', $slug, $current_version, $site_url, $license_key);
|
||||
|
||||
$result = SoftwareManager::check_update($license_key, $slug, $current_version);
|
||||
$result = SoftwareManager::check_update($license_key, $slug, $current_version, $site_url);
|
||||
|
||||
$status_code = isset($result['success']) && $result['success'] === false ? 400 : 200;
|
||||
|
||||
@@ -242,7 +251,7 @@ class SoftwareController
|
||||
return [
|
||||
'version' => $v['version'],
|
||||
'release_date' => $v['release_date'],
|
||||
'changelog' => $v['changelog'],
|
||||
'changelog' => is_string($v['changelog']) && strpos(trim($v['changelog']), '{') === 0 ? json_decode($v['changelog'], true) : $v['changelog'],
|
||||
'download_count' => (int) $v['download_count'],
|
||||
];
|
||||
}, $versions),
|
||||
@@ -283,8 +292,29 @@ class SoftwareController
|
||||
$params = $request->get_json_params();
|
||||
|
||||
$version = sanitize_text_field($params['version'] ?? '');
|
||||
$changelog = wp_kses_post($params['changelog'] ?? '');
|
||||
$set_current = (bool) ($params['set_current'] ?? true);
|
||||
|
||||
$raw_changelog = $params['changelog'] ?? [];
|
||||
$changelog_data = [];
|
||||
if (is_array($raw_changelog)) {
|
||||
$changelog_data = [
|
||||
'narrative' => wp_kses_post($raw_changelog['narrative'] ?? ''),
|
||||
'points' => []
|
||||
];
|
||||
if (isset($raw_changelog['points']) && is_array($raw_changelog['points'])) {
|
||||
foreach ($raw_changelog['points'] as $pt) {
|
||||
if (isset($pt['type']) && isset($pt['text'])) {
|
||||
$changelog_data['points'][] = [
|
||||
'type' => sanitize_text_field($pt['type']),
|
||||
'text' => sanitize_text_field($pt['text']),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$changelog_data = ['narrative' => sanitize_textarea_field($raw_changelog), 'points' => []];
|
||||
}
|
||||
$changelog = wp_json_encode($changelog_data);
|
||||
|
||||
if (empty($version)) {
|
||||
return new WP_REST_Response([
|
||||
@@ -318,4 +348,62 @@ class SoftwareController
|
||||
'message' => __('Version added successfully', 'woonoow'),
|
||||
], 201);
|
||||
}
|
||||
/**
|
||||
* Edit an existing version
|
||||
*/
|
||||
public static function edit_version(WP_REST_Request $request)
|
||||
{
|
||||
$product_id = $request->get_param('product_id');
|
||||
$version_id = $request->get_param('version_id');
|
||||
$version = sanitize_text_field($request->get_param('version'));
|
||||
$changelog = $request->get_param('changelog');
|
||||
$set_current = filter_var($request->get_param('set_current'), FILTER_VALIDATE_BOOLEAN);
|
||||
|
||||
// If changelog is an array/object, encode it to JSON
|
||||
if (is_array($changelog) || is_object($changelog)) {
|
||||
if (isset($changelog['narrative'])) {
|
||||
$changelog['narrative'] = sanitize_textarea_field($changelog['narrative']);
|
||||
}
|
||||
if (isset($changelog['points']) && is_array($changelog['points'])) {
|
||||
foreach ($changelog['points'] as &$point) {
|
||||
$point['type'] = sanitize_text_field($point['type'] ?? '');
|
||||
$point['text'] = sanitize_text_field($point['text'] ?? '');
|
||||
}
|
||||
}
|
||||
$changelog = wp_json_encode($changelog);
|
||||
} else {
|
||||
$changelog = wp_kses_post($changelog);
|
||||
}
|
||||
|
||||
if (empty($version)) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'error' => 'missing_version',
|
||||
'message' => __('Version number is required', 'woonoow'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
$product = wc_get_product($product_id);
|
||||
if (!$product) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'error' => 'product_not_found',
|
||||
], 404);
|
||||
}
|
||||
|
||||
$result = SoftwareManager::update_version($version_id, $product_id, $version, $changelog, $set_current);
|
||||
|
||||
if (is_wp_error($result)) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'error' => $result->get_error_code(),
|
||||
'message' => $result->get_error_message(),
|
||||
], 400);
|
||||
}
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('Version updated successfully', 'woonoow'),
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,7 +608,7 @@ class LicenseManager
|
||||
/**
|
||||
* Validate license (check if valid without activating)
|
||||
*/
|
||||
public static function validate($license_key)
|
||||
public static function validate($license_key, $domain = null)
|
||||
{
|
||||
$license = self::get_license_by_key($license_key);
|
||||
|
||||
@@ -626,8 +626,31 @@ class LicenseManager
|
||||
$subscription_status = self::get_order_subscription_status($license['order_id']);
|
||||
$is_subscription_valid = $subscription_status === null || in_array($subscription_status, ['active', 'pending-cancel']);
|
||||
|
||||
// Check domain activation if domain is provided
|
||||
$is_domain_active = true;
|
||||
if ($domain) {
|
||||
global $wpdb;
|
||||
$table = $wpdb->prefix . self::$activations_table;
|
||||
$activation = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT id FROM $table WHERE license_id = %d AND domain = %s AND status = 'active' LIMIT 1",
|
||||
$license['id'],
|
||||
$domain
|
||||
));
|
||||
if (!$activation) {
|
||||
$is_domain_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($domain && !$is_domain_active) {
|
||||
return [
|
||||
'valid' => false,
|
||||
'error' => 'domain_not_activated',
|
||||
'message' => __('License is not activated for this domain', 'woonoow'),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'valid' => $license['status'] === 'active' && !$is_expired && $is_subscription_valid,
|
||||
'valid' => $license['status'] === 'active' && !$is_expired && $is_subscription_valid && $is_domain_active,
|
||||
'license_key' => $license['license_key'],
|
||||
'status' => $license['status'],
|
||||
'activation_limit' => (int) $license['activation_limit'],
|
||||
@@ -639,6 +662,7 @@ class LicenseManager
|
||||
'is_expired' => $is_expired,
|
||||
'subscription_status' => $subscription_status,
|
||||
'subscription_active' => $is_subscription_valid,
|
||||
'domain_active' => $is_domain_active,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -127,10 +127,10 @@ class SoftwareManager
|
||||
/**
|
||||
* Check for updates
|
||||
*/
|
||||
public static function check_update($license_key, $slug, $current_version)
|
||||
public static function check_update($license_key, $slug, $current_version, $site_url = null)
|
||||
{
|
||||
// Validate license
|
||||
$license_validation = LicenseManager::validate($license_key);
|
||||
$license_validation = LicenseManager::validate($license_key, $site_url);
|
||||
|
||||
if (!$license_validation['valid']) {
|
||||
return [
|
||||
@@ -255,10 +255,21 @@ class SoftwareManager
|
||||
global $wpdb;
|
||||
$table = $wpdb->prefix . self::$versions_table;
|
||||
|
||||
return $wpdb->get_results($wpdb->prepare(
|
||||
$results = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT * FROM $table WHERE product_id = %d ORDER BY release_date DESC",
|
||||
$product_id
|
||||
), ARRAY_A);
|
||||
|
||||
if ($results) {
|
||||
foreach ($results as &$row) {
|
||||
$decoded_changelog = json_decode($row['changelog'], true);
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
$row['changelog'] = $decoded_changelog;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -308,6 +319,39 @@ class SoftwareManager
|
||||
return $wpdb->insert_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a version
|
||||
*/
|
||||
public static function update_version($version_id, $product_id, $version, $changelog = '', $set_current = false)
|
||||
{
|
||||
global $wpdb;
|
||||
$table = $wpdb->prefix . self::$versions_table;
|
||||
|
||||
// Reset other current versions if this one is set to current
|
||||
if ($set_current) {
|
||||
$wpdb->update($table, ['is_current' => 0], ['product_id' => $product_id]);
|
||||
}
|
||||
|
||||
// Update version
|
||||
$wpdb->update($table, [
|
||||
'version' => $version,
|
||||
'changelog' => $changelog,
|
||||
'is_current' => $set_current ? 1 : 0,
|
||||
], [
|
||||
'id' => $version_id,
|
||||
'product_id' => $product_id
|
||||
]);
|
||||
|
||||
// Update product meta
|
||||
if ($set_current) {
|
||||
update_post_meta($product_id, '_woonoow_software_current_version', $version);
|
||||
}
|
||||
|
||||
do_action('woonoow/software/version_updated', $version_id, $product_id, $version);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate secure download token
|
||||
*/
|
||||
|
||||
@@ -48,6 +48,9 @@ class SubscriptionModule
|
||||
add_action('deleted_post', [__CLASS__, 'on_post_deleted']);
|
||||
add_action('delete_user', [__CLASS__, 'on_user_deleted']);
|
||||
|
||||
// Prevent guest checkout for subscriptions
|
||||
add_filter('woocommerce_add_to_cart_validation', [__CLASS__, 'validate_subscription_add_to_cart'], 10, 3);
|
||||
|
||||
// Modify add to cart button text for subscription products
|
||||
add_filter('woocommerce_product_single_add_to_cart_text', [__CLASS__, 'subscription_add_to_cart_text'], 10, 2);
|
||||
add_filter('woocommerce_product_add_to_cart_text', [__CLASS__, 'subscription_add_to_cart_text'], 10, 2);
|
||||
@@ -271,6 +274,24 @@ class SubscriptionModule
|
||||
$order->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent guest checkout for subscriptions
|
||||
*/
|
||||
public static function validate_subscription_add_to_cart($passed, $product_id, $quantity) {
|
||||
if (!ModuleRegistry::is_enabled('subscription')) {
|
||||
return $passed;
|
||||
}
|
||||
|
||||
if (get_post_meta($product_id, '_woonoow_subscription_enabled', true) === 'yes') {
|
||||
if (!is_user_logged_in()) {
|
||||
wc_add_notice(__('You must be logged in to purchase a subscription.', 'woonoow'), 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $passed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify add to cart button text for subscription products
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user