Plugin Directory

Changeset 3431889


Ignore:
Timestamp:
01/03/2026 11:45:37 PM (3 months ago)
Author:
technodrome
Message:

ver 3.5.4 add credit info licence option

Location:
technodrome-ai-content-assistant/trunk
Files:
1 added
12 edited

Legend:

Unmodified
Added
Removed
  • technodrome-ai-content-assistant/trunk/changelog.txt

    r3430309 r3431889  
    11# 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
    234
    335# 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 <?php
     1<?php
    22/**
    33 * Content Rules Tab - Prevent direct access
  • technodrome-ai-content-assistant/trunk/dashboard/modules/footer/footer.css

    r3423160 r3431889  
    10641064    }
    10651065}
    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  
    5151$taics_is_dark_mode = get_user_meta($taics_user_id, 'taics_dark_mode', true) === '1';
    5252$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
    5354$taics_stored_api_status = get_user_meta($taics_user_id, 'taics_api_status', true);
    5455$taics_api_status = !empty($taics_stored_api_status) ? $taics_stored_api_status : 'ready';
     
    167168</div>
    168169                </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>
    169197            </div>
    170198
  • technodrome-ai-content-assistant/trunk/dashboard/modules/layout-templates-tab/layout-templates.php

    r3429316 r3431889  
    1 <?php
     1<?php
    22/**
    33 * Layout Templates Tab - Prevent direct access
  • technodrome-ai-content-assistant/trunk/features/header/add-licence.js

    r3368919 r3431889  
    4040            const siteUrl = $siteInput.val().trim();
    4141
    42             // Validation
     42            // Validation - Empty key resets to FREE
    4343            if (!licenseKey) {
    44                 this.showNotification(window.taics_license.messages.empty_key, 'error');
    45                 $licenseInput.focus();
     44                this.resetToFree();
    4645                return;
    4746            }
     
    107106        handleValidationError: function(xhr, status, error) {
    108107            console.error('License validation AJAX error:', {xhr, status, error});
    109            
     108
    110109            let errorMessage = window.taics_license.messages.error;
    111            
     110
    112111            if (status === 'timeout') {
    113112                errorMessage = 'Validation timeout. Please check your connection.';
     
    117116                errorMessage = 'Server error. Please try again later.';
    118117            }
    119            
     118
    120119            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            });
    121185        },
    122186
  • technodrome-ai-content-assistant/trunk/includes/class-ajax-handler.php

    r3423160 r3431889  
    2828        add_action('wp_ajax_taics_save_auto_publish', [__CLASS__, 'handle_save_auto_publish']);
    2929        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']);
    3031        add_action('wp_ajax_taics_save_profile_simple', [__CLASS__, 'ajax_save_profile_simple']);
    3132        add_action('wp_ajax_taics_load_profile_simple', [__CLASS__, 'ajax_load_profile_simple']);
     
    4445        add_action('wp_ajax_taics_get_available_models', [__CLASS__, 'handle_get_available_models']);
    4546        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']);
    4648    }
    4749
     
    614616                exit;
    615617            }
    616            
     618
    617619            $dark_mode = filter_var(wp_unslash($_POST['dark_mode']), FILTER_VALIDATE_BOOLEAN);
    618620
     
    630632        } catch (Exception $e) {
    631633            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'));
    632680        }
    633681    }
     
    12241272        }
    12251273    }
     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    }
    12261319}
  • technodrome-ai-content-assistant/trunk/includes/class-content-generator.php

    r3423160 r3431889  
    104104        $content = self::insert_images_into_content($content, $args); // Insert images
    105105        $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        }
    107112
    108113        $title = ucfirst(trim($topic));
     
    538543        $provider_name = esc_html(ucfirst($ai_provider));
    539544        $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        }
    542553
    543554        $title = ucfirst(trim($args['topic']));
  • technodrome-ai-content-assistant/trunk/includes/class-license-manager.php

    r3430309 r3431889  
    281281     * Validate component-format license by checksum (offline fallback)
    282282     * 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
    283288     */
    284289    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       
    285295        $key_chars = str_replace('-', '', strtoupper($license_key));
    286296
     
    296306
    297307        // 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
    298311        $sum = 0;
    299312        for ($i = 0; $i < strlen($key_chars); $i++) {
     
    303316        }
    304317
    305         // Valid if sum modulo 11 equals 0
    306         if ($sum % 11 === 0) {
     318        // Valid if sum >= 1000 AND modulo 11 equals 0
     319        if ($sum >= 1000 && $sum % 11 === 0) {
    307320            // Assume pro plan for valid component keys
    308321            $plan = 'pro';
     
    818831        // Reset user plan to free
    819832        $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
    821837        // Clear license data
    822838        $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
    829840        return true;
    830841    }
  • technodrome-ai-content-assistant/trunk/includes/class-settings.php

    r3369993 r3431889  
    309309        return update_user_meta($user_id, 'taics_auto_publish', $enabled ? '1' : '0');
    310310    }
    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
    312335    /**
    313336     * Get API connection status for user
  • technodrome-ai-content-assistant/trunk/readme.txt

    r3430309 r3431889  
    55Tested up to: 6.9
    66Requires PHP: 8.0
    7 Stable tag: 3.5.3
     7Stable tag: 3.5.4
    88License: GPL v2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    136136
    137137== 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
    138149
    139150= 3.5.3 - 2025-12-28 - License Expiration Auto-Reset
  • technodrome-ai-content-assistant/trunk/technodrome-ai-content-assistant.php

    r3430309 r3431889  
    44 * Plugin URI: https://technodrome.org/ai-content-assistant
    55 * Description: Advanced AI content generation plugin with multiple AI providers, profile system, layout templates, and content rules for WordPress.
    6  * Version: 3.5.3
     6 * Version: 3.5.4
    77 * Author: Technodrome Team
    88 * Author URI: https://technodrome.org
     
    3030
    3131// Plugin constants
    32 define('TAICS_VERSION', '3.5.3'); // License validation fix, Tested up to 6.9
     32define('TAICS_VERSION', '3.5.4'); // Add Credit Toggle, Auto-reset on empty/invalid license key
    3333define('TAICS_PLUGIN_FILE', __FILE__);
    3434define('TAICS_PLUGIN_DIR', plugin_dir_path(__FILE__));
     
    314314            'dark-mode-toggle' => 'footer/dark-mode-toggle.js',
    315315            'publish-toggle' => 'footer/publish-toggle.js',
     316            'credit-toggle' => 'footer/credit-toggle.js',
    316317            'save-button' => 'footer/save-button.js',
    317318            'profile-buttons' => 'footer/profile-buttons.js',
     
    368369            'taics-api-status',
    369370            'taics-publish-toggle',
     371            'taics-credit-toggle',
    370372            'taics-save-button',
    371373            'taics-profile-buttons',
Note: See TracChangeset for help on using the changeset viewer.