Changeset 3431889
- Timestamp:
- 01/03/2026 11:45:37 PM (3 months ago)
- Location:
- technodrome-ai-content-assistant/trunk
- Files:
-
- 1 added
- 12 edited
-
changelog.txt (modified) (1 diff)
-
dashboard/modules/content-rules-tab/content-rules.php (modified) (1 diff)
-
dashboard/modules/footer/footer.css (modified) (1 diff)
-
dashboard/modules/footer/footer.php (modified) (2 diffs)
-
dashboard/modules/layout-templates-tab/layout-templates.php (modified) (1 diff)
-
features/footer/credit-toggle.js (added)
-
features/header/add-licence.js (modified) (3 diffs)
-
includes/class-ajax-handler.php (modified) (5 diffs)
-
includes/class-content-generator.php (modified) (2 diffs)
-
includes/class-license-manager.php (modified) (4 diffs)
-
includes/class-settings.php (modified) (1 diff)
-
readme.txt (modified) (2 diffs)
-
technodrome-ai-content-assistant.php (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
technodrome-ai-content-assistant/trunk/changelog.txt
r3430309 r3431889 1 1 # Changelog 2 3 # 3.5.4 - 2026-01-04 - Credit Toggle & Auto-Reset on Empty/Invalid License 4 5 * **NEW FEATURE: Credit Toggle (v3.8.0)** 6 - PRO/PREMIUM users can optionally hide Technodrome credit footer from generated articles 7 - Free users: Credit footer remains mandatory (toggle disabled) 8 - Pro/Premium users: Can toggle credit footer YES/NO via new footer control 9 - Storage: Global user_meta setting (`taics_show_credits`) 10 - Default: YES (credit shown) 11 - Files Modified: 12 * features/footer/credit-toggle.js (NEW) 13 * dashboard/modules/footer/footer.php 14 * includes/class-settings.php 15 * includes/class-ajax-handler.php 16 * includes/class-content-generator.php 17 * technodrome-ai-content-assistant.php 18 * includes/class-license-manager.php 19 * dashboard/modules/footer/footer.css 20 21 * **NEW FEATURE: Auto-Reset on Empty/Invalid License Key** 22 - Automatically resets to FREE tier when: 23 * License key field is emptied and "Save License" clicked 24 * License key is invalid and validation fails 25 * Any license validation error occurs 26 - Prevents users from keeping premium features with invalid/empty keys 27 - Better user experience for license management 28 29 * **SECURITY:** All changes follow WordPress security standards 30 - Nonce validation on all AJAX endpoints 31 - Capability checks for user permissions 32 - Input sanitization and output escaping 33 - License enforcement on backend 2 34 3 35 # 3.5.3 - 2025-12-28 - License Expiration Auto-Reset -
technodrome-ai-content-assistant/trunk/dashboard/modules/content-rules-tab/content-rules.php
r3429316 r3431889 1 <?php1 <?php 2 2 /** 3 3 * Content Rules Tab - Prevent direct access -
technodrome-ai-content-assistant/trunk/dashboard/modules/footer/footer.css
r3423160 r3431889 1064 1064 } 1065 1065 } 1066 1066 1067 /* ===== CREDIT TOGGLE CONTROL (v3.8.0) ===== */ 1068 .taics-credit-control { 1069 display: flex; 1070 align-items: center; 1071 gap: 6px; 1072 font-size: 10px; 1073 font-weight: 600; 1074 color: var(--taics-text-primary); 1075 } 1076 1077 .taics-credit-control .taics-toggle-label { 1078 white-space: nowrap; 1079 } 1080 1081 /* Credit Toggle - Disabled State (FREE users) */ 1082 .taics-toggle-switch.taics-toggle-disabled { 1083 opacity: 0.6; 1084 cursor: not-allowed !important; 1085 } 1086 1087 .taics-toggle-switch.taics-toggle-disabled:hover { 1088 transform: none; 1089 box-shadow: none; 1090 } 1091 1092 .taics-toggle-disabled + .taics-toggle-container .taics-toggle-status { 1093 opacity: 0.5; 1094 } 1095 -
technodrome-ai-content-assistant/trunk/dashboard/modules/footer/footer.php
r3423160 r3431889 51 51 $taics_is_dark_mode = get_user_meta($taics_user_id, 'taics_dark_mode', true) === '1'; 52 52 $taics_auto_publish = get_user_meta($taics_user_id, 'taics_auto_publish', true) !== '0'; // Default YES 53 $taics_show_credits = get_user_meta($taics_user_id, 'taics_show_credits', true) !== '0'; // Default YES 53 54 $taics_stored_api_status = get_user_meta($taics_user_id, 'taics_api_status', true); 54 55 $taics_api_status = !empty($taics_stored_api_status) ? $taics_stored_api_status : 'ready'; … … 167 168 </div> 168 169 </div> 170 171 <!-- Credit Toggle --> 172 <div class="taics-credit-control"> 173 <label for="taics-credit-toggle" class="taics-toggle-label"> 174 <?php esc_html_e('Credit:', 'technodrome-ai-content-assistant'); ?> 175 </label> 176 <div class="taics-toggle-container"> 177 <button 178 class="taics-toggle-switch <?php echo $taics_show_credits ? 'taics-toggle-on' : 'taics-toggle-off'; ?> <?php echo ($taics_user_plan === 'free') ? 'taics-toggle-disabled' : ''; ?>" 179 id="taics-credit-toggle" 180 data-state="<?php echo $taics_show_credits ? 'on' : 'off'; ?>" 181 data-user-plan="<?php echo esc_attr($taics_user_plan); ?>" 182 <?php echo ($taics_user_plan === 'free') ? 'disabled' : ''; ?> 183 title="<?php 184 if ($taics_user_plan === 'free') { 185 esc_attr_e('Upgrade to PRO to remove credits', 'technodrome-ai-content-assistant'); 186 } else { 187 esc_attr_e('Show Technodrome credits in articles', 'technodrome-ai-content-assistant'); 188 } 189 ?>"> 190 <div class="taics-toggle-slider"></div> 191 </button> 192 <span class="taics-toggle-status"> 193 <?php echo $taics_show_credits ? esc_html__('YES', 'technodrome-ai-content-assistant') : esc_html__('NO', 'technodrome-ai-content-assistant'); ?> 194 </span> 195 </div> 196 </div> 169 197 </div> 170 198 -
technodrome-ai-content-assistant/trunk/dashboard/modules/layout-templates-tab/layout-templates.php
r3429316 r3431889 1 <?php1 <?php 2 2 /** 3 3 * Layout Templates Tab - Prevent direct access -
technodrome-ai-content-assistant/trunk/features/header/add-licence.js
r3368919 r3431889 40 40 const siteUrl = $siteInput.val().trim(); 41 41 42 // Validation 42 // Validation - Empty key resets to FREE 43 43 if (!licenseKey) { 44 this.showNotification(window.taics_license.messages.empty_key, 'error'); 45 $licenseInput.focus(); 44 this.resetToFree(); 46 45 return; 47 46 } … … 107 106 handleValidationError: function(xhr, status, error) { 108 107 console.error('License validation AJAX error:', {xhr, status, error}); 109 108 110 109 let errorMessage = window.taics_license.messages.error; 111 110 112 111 if (status === 'timeout') { 113 112 errorMessage = 'Validation timeout. Please check your connection.'; … … 117 116 errorMessage = 'Server error. Please try again later.'; 118 117 } 119 118 120 119 this.showNotification(errorMessage, 'error'); 120 121 // Reset to FREE on validation error (invalid key) 122 this.resetToFree(); 123 }, 124 125 resetToFree: function() { 126 // v3.5.4: Auto-reset to FREE when license key is empty or invalid 127 console.log('Resetting license to FREE tier...'); 128 129 const $licenseInput = $('#taics-license-key'); 130 const $validateBtn = $('#taics-validate-license-btn'); 131 132 // Show loading state 133 this.setLoadingState($validateBtn, true); 134 this.showNotification('Resetting to FREE tier...', 'info'); 135 136 // AJAX request to reset license (v3.5.4) - Use taicsData for correct nonce 137 $.ajax({ 138 url: window.taicsData?.ajax_url || window.taics_license.ajax_url, 139 type: 'POST', 140 data: { 141 action: 'taics_reset_license_to_free', 142 nonce: window.taicsData?.nonce || window.taics_license.nonce 143 }, 144 timeout: 10000, 145 success: (response) => { 146 if (response.success) { 147 // Clear license input field 148 $licenseInput.val(''); 149 150 this.showNotification('Successfully reset to FREE tier. Please reload page.', 'success'); 151 152 // Update UI 153 const $planBadge = $('.taics-header-version'); 154 if ($planBadge.length) { 155 $planBadge.removeClass('taics-plan-free taics-plan-pro taics-plan-premium'); 156 $planBadge.addClass('taics-plan-free'); 157 $planBadge.text('FREE'); 158 } 159 160 // Refresh dashboard restrictions 161 if (window.TAICS_Dashboard && typeof window.TAICS_Dashboard.refreshLicenseRestrictions === 'function') { 162 setTimeout(() => { 163 window.TAICS_Dashboard.refreshLicenseRestrictions(); 164 }, 500); 165 } 166 167 // Optional reload after delay 168 setTimeout(() => { 169 if (confirm('Reset to FREE successful! Reload page to apply changes?')) { 170 window.location.reload(); 171 } 172 }, 1500); 173 } else { 174 this.showNotification(response.data || 'Failed to reset license', 'error'); 175 } 176 }, 177 error: (xhr, status, error) => { 178 console.error('Reset license AJAX error:', {xhr, status, error}); 179 this.showNotification('Failed to reset license. Please try again.', 'error'); 180 }, 181 complete: () => { 182 this.setLoadingState($validateBtn, false); 183 } 184 }); 121 185 }, 122 186 -
technodrome-ai-content-assistant/trunk/includes/class-ajax-handler.php
r3423160 r3431889 28 28 add_action('wp_ajax_taics_save_auto_publish', [__CLASS__, 'handle_save_auto_publish']); 29 29 add_action('wp_ajax_taics_save_dark_mode', [__CLASS__, 'handle_save_dark_mode']); 30 add_action('wp_ajax_taics_save_show_credits', [__CLASS__, 'handle_save_show_credits']); 30 31 add_action('wp_ajax_taics_save_profile_simple', [__CLASS__, 'ajax_save_profile_simple']); 31 32 add_action('wp_ajax_taics_load_profile_simple', [__CLASS__, 'ajax_load_profile_simple']); … … 44 45 add_action('wp_ajax_taics_get_available_models', [__CLASS__, 'handle_get_available_models']); 45 46 add_action('wp_ajax_taics_clear_model_cache', [__CLASS__, 'handle_clear_model_cache']); 47 add_action('wp_ajax_taics_reset_license_to_free', [__CLASS__, 'handle_reset_license_to_free']); 46 48 } 47 49 … … 614 616 exit; 615 617 } 616 618 617 619 $dark_mode = filter_var(wp_unslash($_POST['dark_mode']), FILTER_VALIDATE_BOOLEAN); 618 620 … … 630 632 } catch (Exception $e) { 631 633 wp_send_json_error(esc_html__('Failed to save dark mode setting', 'technodrome-ai-content-assistant')); 634 } 635 } 636 637 /** 638 * Handle save show credits AJAX request (v3.8.0) 639 */ 640 public static function handle_save_show_credits() { 641 check_ajax_referer('taics_ajax_nonce', 'nonce'); 642 643 if (!current_user_can('edit_posts')) { 644 wp_send_json_error(esc_html__('Insufficient permissions', 'technodrome-ai-content-assistant')); 645 exit; 646 } 647 648 try { 649 if (!isset($_POST['show_credits'])) { 650 wp_send_json_error(esc_html__('Credit value missing', 'technodrome-ai-content-assistant')); 651 exit; 652 } 653 654 $show_credits = filter_var(wp_unslash($_POST['show_credits']), FILTER_VALIDATE_BOOLEAN); 655 656 // License check: FREE users cannot disable credits 657 require_once plugin_dir_path(__FILE__) . 'class-license-manager.php'; 658 $license_manager = TAICS_License_Manager::get_instance(); 659 $license_data = $license_manager->get_license_data(); 660 $user_plan = $license_data['plan'] ?? 'free'; 661 662 if (!$show_credits && $user_plan === 'free') { 663 wp_send_json_error(esc_html__('Removing credits requires PRO or PREMIUM plan', 'technodrome-ai-content-assistant')); 664 exit; 665 } 666 667 $settings_manager = new TAICS_Settings(); 668 $result = $settings_manager->set_show_credits(get_current_user_id(), $show_credits); 669 670 if ($result) { 671 wp_send_json_success([ 672 'message' => esc_html__('Credit setting saved successfully', 'technodrome-ai-content-assistant'), 673 'show_credits' => $show_credits 674 ]); 675 } else { 676 wp_send_json_error(esc_html__('Failed to save credit setting', 'technodrome-ai-content-assistant')); 677 } 678 } catch (Exception $e) { 679 wp_send_json_error(esc_html__('Failed to save credit setting', 'technodrome-ai-content-assistant')); 632 680 } 633 681 } … … 1224 1272 } 1225 1273 } 1274 1275 /** 1276 * Handle reset license to FREE AJAX request (v3.5.4) 1277 */ 1278 public static function handle_reset_license_to_free() { 1279 check_ajax_referer('taics_ajax_nonce', 'nonce'); 1280 1281 if (!current_user_can('manage_options')) { 1282 wp_send_json_error(esc_html__('Insufficient permissions', 'technodrome-ai-content-assistant')); 1283 exit; 1284 } 1285 1286 try { 1287 $user_id = get_current_user_id(); 1288 if (!$user_id) { 1289 wp_send_json_error(esc_html__('User not found', 'technodrome-ai-content-assistant')); 1290 exit; 1291 } 1292 1293 // Load license manager 1294 require_once plugin_dir_path(__FILE__) . 'class-license-manager.php'; 1295 $license_manager = TAICS_License_Manager::get_instance(); 1296 1297 // Reset to free settings 1298 $result = $license_manager->reset_to_free_settings(); 1299 1300 if ($result) { 1301 wp_send_json_success([ 1302 'message' => esc_html__('License reset to FREE successfully', 'technodrome-ai-content-assistant'), 1303 'plan' => 'free' 1304 ]); 1305 } else { 1306 wp_send_json_error(esc_html__('Failed to reset license', 'technodrome-ai-content-assistant')); 1307 } 1308 } catch (Exception $e) { 1309 if (defined('WP_DEBUG') && WP_DEBUG) { 1310 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 1311 error_log('TAICS: Error resetting license: ' . esc_html($e->getMessage())); 1312 } 1313 1314 wp_send_json_error(array( 1315 'message' => 'Failed to reset license: ' . esc_html($e->getMessage()) 1316 )); 1317 } 1318 } 1226 1319 } -
technodrome-ai-content-assistant/trunk/includes/class-content-generator.php
r3423160 r3431889 104 104 $content = self::insert_images_into_content($content, $args); // Insert images 105 105 $content = self::insert_videos_into_content($content, $args); // Insert videos - THIS WAS MISSING! 106 $content .= self::get_demo_notice(); 106 107 // v3.8.0: Conditional demo notice based on user preference 108 $show_credits = get_user_meta(get_current_user_id(), 'taics_show_credits', true) !== '0'; 109 if ($show_credits) { 110 $content .= self::get_demo_notice(); 111 } 107 112 108 113 $title = ucfirst(trim($topic)); … … 538 543 $provider_name = esc_html(ucfirst($ai_provider)); 539 544 $current_date = esc_html(current_time('F j, Y')); 540 // v3.4.2: Add link to Technodrome website 541 $content .= "\n\n<hr><p><em><small>🤖 Generated with <a href=\"https://technodrome.nasrpskom.com\" target=\"_blank\" rel=\"noopener noreferrer\">Technodrome</a> AI Content Assistant using " . $provider_name . " on " . $current_date . "</small></em></p>"; 545 546 // v3.8.0: Conditional credit footer based on user preference 547 $show_credits = get_user_meta(get_current_user_id(), 'taics_show_credits', true) !== '0'; 548 549 if ($show_credits) { 550 // v3.4.2: Add link to Technodrome website 551 $content .= "\n\n<hr><p><em><small>🤖 Generated with <a href=\"https://technodrome.nasrpskom.com\" target=\"_blank\" rel=\"noopener noreferrer\">Technodrome</a> AI Content Assistant using " . $provider_name . " on " . $current_date . "</small></em></p>"; 552 } 542 553 543 554 $title = ucfirst(trim($args['topic'])); -
technodrome-ai-content-assistant/trunk/includes/class-license-manager.php
r3430309 r3431889 281 281 * Validate component-format license by checksum (offline fallback) 282 282 * Component keys: XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX 283 * 284 * SECURITY FIX v2.5.3: Properly validate checksum to prevent bypass 285 * - Rejects empty/invalid license keys early 286 * - Requires minimum sum >= 1000 AND modulo 11 === 0 287 * - Prevents empty strings and weak keys from passing 283 288 */ 284 289 private function validate_component_checksum($license_key) { 290 // CRITICAL: Reject empty or invalid license keys FIRST 291 if (empty($license_key) || !is_string($license_key)) { 292 return false; 293 } 294 285 295 $key_chars = str_replace('-', '', strtoupper($license_key)); 286 296 … … 296 306 297 307 // Checksum validation for component keys 308 // Valid checksum requires specific mathematical properties 309 // The sum must be >= 1000 AND divisible by 11 to be valid 310 // This prevents empty strings and weak keys from passing 298 311 $sum = 0; 299 312 for ($i = 0; $i < strlen($key_chars); $i++) { … … 303 316 } 304 317 305 // Valid if sum modulo 11 equals 0306 if ($sum % 11 === 0) {318 // Valid if sum >= 1000 AND modulo 11 equals 0 319 if ($sum >= 1000 && $sum % 11 === 0) { 307 320 // Assume pro plan for valid component keys 308 321 $plan = 'pro'; … … 818 831 // Reset user plan to free 819 832 $settings->set_user_plan($user_id, 'free'); 820 833 834 // v3.8.0: Reset credits to YES (FREE users must show credits) 835 $settings->set_show_credits($user_id, true); 836 821 837 // Clear license data 822 838 $this->deactivate(); 823 824 // Log the reset (for debugging in development) 825 if (defined('WP_DEBUG') && WP_DEBUG) { 826 error_log('TAICS: License expired, settings reset to free/default (Profile 1)'); 827 } 828 839 829 840 return true; 830 841 } -
technodrome-ai-content-assistant/trunk/includes/class-settings.php
r3369993 r3431889 309 309 return update_user_meta($user_id, 'taics_auto_publish', $enabled ? '1' : '0'); 310 310 } 311 311 312 /** 313 * Check if credits are enabled for user (v3.8.0) 314 * 315 * @param int $user_id 316 * @return bool 317 */ 318 public function is_show_credits_enabled($user_id) { 319 $value = get_user_meta($user_id, 'taics_show_credits', true); 320 // Default YES if not set 321 return $value !== '0'; 322 } 323 324 /** 325 * Set show credits for user (v3.8.0) 326 * 327 * @param int $user_id 328 * @param bool $enabled 329 * @return bool 330 */ 331 public function set_show_credits($user_id, $enabled) { 332 return update_user_meta($user_id, 'taics_show_credits', $enabled ? '1' : '0'); 333 } 334 312 335 /** 313 336 * Get API connection status for user -
technodrome-ai-content-assistant/trunk/readme.txt
r3430309 r3431889 5 5 Tested up to: 6.9 6 6 Requires PHP: 8.0 7 Stable tag: 3.5. 37 Stable tag: 3.5.4 8 8 License: GPL v2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 136 136 137 137 == Changelog == 138 139 = 3.5.4 - 2026-01-04 - Credit Toggle & Auto-Reset on Empty/Invalid License 140 * **NEW FEATURE: Credit Toggle** - PRO/PREMIUM users can optionally hide Technodrome credit footer from generated articles 141 * **Free users:** Credit footer remains mandatory (toggle disabled) 142 * **Pro/Premium users:** Can toggle credit footer YES/NO via new footer control 143 * **NEW FEATURE: Auto-Reset on Empty/Invalid License Key** - Automatically resets to FREE tier when: 144 * License key field is emptied and saved 145 * License key is invalid and Save License is clicked 146 * License validation fails for any reason 147 * **IMPROVEMENT:** Better user experience for license management - no more stuck premium state 148 * **SECURITY:** Prevents users from keeping premium features with invalid/empty keys 138 149 139 150 = 3.5.3 - 2025-12-28 - License Expiration Auto-Reset -
technodrome-ai-content-assistant/trunk/technodrome-ai-content-assistant.php
r3430309 r3431889 4 4 * Plugin URI: https://technodrome.org/ai-content-assistant 5 5 * Description: Advanced AI content generation plugin with multiple AI providers, profile system, layout templates, and content rules for WordPress. 6 * Version: 3.5. 36 * Version: 3.5.4 7 7 * Author: Technodrome Team 8 8 * Author URI: https://technodrome.org … … 30 30 31 31 // Plugin constants 32 define('TAICS_VERSION', '3.5. 3'); // License validation fix, Tested up to 6.932 define('TAICS_VERSION', '3.5.4'); // Add Credit Toggle, Auto-reset on empty/invalid license key 33 33 define('TAICS_PLUGIN_FILE', __FILE__); 34 34 define('TAICS_PLUGIN_DIR', plugin_dir_path(__FILE__)); … … 314 314 'dark-mode-toggle' => 'footer/dark-mode-toggle.js', 315 315 'publish-toggle' => 'footer/publish-toggle.js', 316 'credit-toggle' => 'footer/credit-toggle.js', 316 317 'save-button' => 'footer/save-button.js', 317 318 'profile-buttons' => 'footer/profile-buttons.js', … … 368 369 'taics-api-status', 369 370 'taics-publish-toggle', 371 'taics-credit-toggle', 370 372 'taics-save-button', 371 373 'taics-profile-buttons',
Note: See TracChangeset
for help on using the changeset viewer.