Plugin Directory

Changeset 3444453


Ignore:
Timestamp:
01/21/2026 10:55:34 PM (2 months ago)
Author:
technodrome
Message:

4.0.3 fix

Location:
technodrome-ai-content-assistant/trunk
Files:
8 edited

Legend:

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

    r3444346 r3444453  
    11# Changelog - Technodrome AI Content Assistant
     2
     3## Version 4.0.3 - 2026-01-21
     4
     5### BUG FIXES
     6- **Structure Name Not Persisting:** CRITICAL FIX - Structure Name field now properly saves and loads
     7  - structure_name was missing from collectCompleteProfileData() - FIXED (added to line 540, 751)
     8  - Now included in content_rules when autosave collects profile data
     9  - Structure Name properly persists across profile switches
     10  - Fixed 3000ms debounce delay - reduced to standard 500ms for faster saves (line 54-59)
     11  - Fixed save_profile() treating update_user_meta false return as error - was blocking save when data identical
     12
     13- **Default Tone AutoSave:** Fixed Default Tone field not saving to profile
     14  - Added missing AutoSave event listener for default tone changes
     15  - Default Tone now persists correctly across profile switches
     16  - AutoSave notification displays when default tone is changed
     17
     18### IMPROVEMENTS
     19- Enhanced field change detection in AutoSave system
     20- Better profile data persistence for all fields
     21- Faster AutoSave debounce timing for Structure Name field (500ms instead of 3000ms)
     22
     23---
    224
    325## Version 4.0.2 - 2026-01-21
  • technodrome-ai-content-assistant/trunk/features/content-rules-tab/profile-name-sync.js

    r3444356 r3444453  
    88
    99        init: function() {
    10             console.log('TAICS Profile Name Sync initialized');
    1110            this.bindEvents();
    1211            this.loadCurrentProfileName();
     
    1413
    1514        bindEvents: function() {
    16             // Listen for profile changes to reload the Structure Name
    17             $(document).off('taics_profile_changed.profile-name');
    18             $(document).on('taics_profile_changed.profile-name', (e, profileNumber) => {
     15            // Listen for profile changes to load the Structure Name from profile data
     16            $(document).off('taics_profile_loaded.profile-name');
     17            $(document).on('taics_profile_loaded.profile-name', (e, profileNumber, profileData) => {
    1918                this.activeProfile = profileNumber;
    20                 this.loadCurrentProfileName();
     19                // Load structure_name from profile data, not from button label
     20                this.loadStructureNameFromProfile(profileData);
    2121            });
    2222
     
    2424            $('#taics-structure-name').off('input.profile-name blur.profile-name');
    2525            $('#taics-structure-name').on('input.profile-name blur.profile-name', () => {
    26                 this.syncProfileName();
     26                // Only sync if NOT currently loading profile data
     27                // Check flag from profile-buttons.js
     28                const isLoading = window.TAICS_Profile_Buttons && window.TAICS_Profile_Buttons.isLoadingProfileData;
     29                if (!isLoading) {
     30                    this.syncProfileName();
     31                }
    2732            });
    2833        },
    2934
     35        loadStructureNameFromProfile: function(profileData) {
     36            // Load structure_name from profile data
     37            if (profileData && profileData.content_rules && profileData.content_rules.structure_name) {
     38                // Profile has a custom structure name - use it
     39                const structureName = profileData.content_rules.structure_name;
     40                $('#taics-structure-name').val(structureName);
     41                // Update button label to match loaded name
     42                this.updateButtonLabel(structureName);
     43            } else {
     44                // Profile doesn't have structure name - clear the field
     45                $('#taics-structure-name').val('');
     46                // Restore default button label
     47                this.updateButtonLabel('');
     48            }
     49        },
     50
     51        updateButtonLabel: function(customName) {
     52            // Apply 7-character limit and UPPERCASE conversion
     53            let displayLabel = customName.substring(0, 7).toUpperCase();
     54            // If empty, use "PROFILE" as fallback
     55            displayLabel = displayLabel || 'PROFILE';
     56
     57            // Update the profile button label
     58            const $profileBtn = $(`.taics-profile-btn-wide[data-profile="${this.activeProfile}"]`);
     59            const $profileLabel = $profileBtn.find('.taics-profile-text');
     60            $profileLabel.text(displayLabel);
     61
     62            // Update the title attribute
     63            const titleText = `Profile ${this.activeProfile} (${displayLabel})`;
     64            $profileBtn.attr('title', titleText);
     65        },
     66
    3067        loadCurrentProfileName: function() {
    31             // Get the custom name from the current profile button if it exists
    32             const $profileBtn = $(`.taics-profile-btn-wide[data-profile="${this.activeProfile}"]`);
    33             if ($profileBtn.length === 0) {
    34                 return;
    35             }
    36 
    37             // Get the label text from the profile button
    38             const $profileLabel = $profileBtn.find('.taics-profile-text');
    39             let currentLabel = $profileLabel.text() || 'PROFILE';
    40 
    41             // If label is just "PROFILE", clear the Structure Name
    42             if (currentLabel === 'PROFILE') {
    43                 $('#taics-structure-name').val('');
    44             } else {
    45                 // Otherwise, put the label value back in Structure Name for editing
    46                 $('#taics-structure-name').val(currentLabel);
    47             }
     68            // This method is no longer used - kept for backward compatibility
    4869        },
    4970
     
    101122                success: (response) => {
    102123                    if (response.success) {
    103                         console.log('Profile name saved:', customName, 'for profile', this.activeProfile);
    104 
    105124                        // Show notification
    106125                        if (window.TAICS_Notifications && typeof window.TAICS_Notifications.show === 'function') {
     
    112131                        }
    113132                    } else {
    114                         console.warn('Failed to save profile name:', response.data);
    115133                        if (window.TAICS_Notifications && typeof window.TAICS_Notifications.show === 'function') {
    116134                            window.TAICS_Notifications.show(
     
    123141                },
    124142                error: (xhr, status, error) => {
    125                     console.error('AJAX error saving profile name:', error);
    126143                    if (window.TAICS_Notifications && typeof window.TAICS_Notifications.show === 'function') {
    127144                        window.TAICS_Notifications.show(
     
    137154
    138155    $(document).ready(function() {
     156        // Wait 200ms to ensure profile-buttons.js initializes first (it uses 100ms)
    139157        setTimeout(() => {
    140158            TAICS_Profile_Name_Sync.init();
    141159            window.TAICS_Profile_Name_Sync = TAICS_Profile_Name_Sync;
    142         }, 300);
     160        }, 200);
    143161    });
    144162
  • technodrome-ai-content-assistant/trunk/features/footer/profile-buttons.js

    r3434643 r3444453  
    99        apiKeys: {},
    1010        isInitializing: false,
    11         isFirstProfileLoad: true, // Track if this is the first profile load (on page init)
    12 
    13         // AutoSave Revolution v3.4.0 - Properties
     11        isFirstProfileLoad: true,
     12        isLoadingProfileData: false,
    1413        autoSaveTimeout: null,
    1514        autoSaveInProgress: false,
    16         lastChangedField: null,  // Za specifičnu notifikaciju
    17        
     15        lastChangedField: null,
     16        structureNameTimeout: null,
     17
    1818        init: function() {
    1919            if (this.isInitialized) {
     
    2525            this.loadProfiles();
    2626            this.setDefaultActiveProfile();
    27             console.log('TAICS Profile Buttons initialized successfully');
    2827        },
    2928       
     
    3231            $('.taics-profile-btn-wide').on('click.taics-profile', this.handleProfileClick.bind(this));
    3332
    34             // AUTOSAVE REVOLUCIJA: Save dugme je uklonjeno - AutoSave sistem je aktivan
    35             // Komentarišem event listener jer više nije potreban
    36             // Sve izmene se automatski čuvaju u profil kroz AutoSave sistem
    37             /*
    38             $('#taics-save-profile-btn').off('click.taics-save-profile');
    39             $('#taics-save-profile-btn').on('click.taics-save-profile', this.handleSaveProfileClick.bind(this));
    40             */
    41 
    42             // AutoSave Revolution v3.4.0 - Event listeners na svim poljima
     33            // AutoSave event listeners na svim poljima
    4334            $('#taics-ai-provider').on('change.autosave', () => this.autoSaveField('ai_settings.ai_provider'));
    4435            $('#taics-ai-model').on('change.autosave', () => this.autoSaveField('ai_settings.ai_model'));
     
    4940            $('#taics-category').on('change.autosave', () => this.autoSaveField('category'));
    5041            $('#taics-generation-mode').on('change.autosave', () => this.autoSaveField('generation_mode'));
     42            $('#taics-default-tone').on('change.autosave', () => this.autoSaveField('default_tone'));
    5143            $('input[name="layout_template"]').on('change.autosave', () => this.autoSaveField('layout_template.template_id'));
    5244            $('#taics-ai-image-toggle').on('change.autosave', () => this.autoSaveField('ai_image.enabled'));
     
    5850            $(document).on('taics_headings_changed.autosave', () => this.autoSaveField('content_rules.headings'));
    5951
    60             // v3.4.0: Content Rules fields - Structure Name with 3s debounce
    61             let structureNameTimeout;
     52            // Content Rules fields - Structure Name with auto-sync to autosave
    6253            $('#taics-structure-name').on('input.autosave', () => {
    63                 clearTimeout(structureNameTimeout);
    64                 structureNameTimeout = setTimeout(() => {
     54                // v4.0.3 FIX: Use consistent 500ms debounce with main autosave system
     55                // This ensures structure_name is saved immediately when user stops typing
     56                clearTimeout(this.structureNameTimeout);
     57                this.structureNameTimeout = setTimeout(() => {
    6558                    this.autoSaveField('content_rules.structure_name');
    66                 }, 3000);
     59                }, 500);
    6760            });
    6861            $(document).on('taics_guidelines_changed.autosave', () => this.autoSaveField('content_rules.guidelines'));
     
    141134                            // This ensures video-context-mode.js and video-slot-transformation.js initialize properly
    142135                            setTimeout(() => {
    143                                 $(document).trigger('taics_profile_loaded', [this.activeProfile]);
     136                                const profileData = this.profiles[this.activeProfile] || {};
     137                                $(document).trigger('taics_profile_loaded', [this.activeProfile, profileData]);
    144138                            }, 100);
    145139                        }
     
    192186            }
    193187            this.switchProfile(profileNumber);
    194             // IMPORTANT: Only trigger taics_profile_loaded when actually SWITCHING to a different profile
    195             // This prevents resetting the UI when user navigates away and back to Generate tab
    196             $(document).trigger('taics_profile_loaded', [profileNumber]);
    197         },
    198        
     188        },
     189
    199190        switchProfile: function(profileNumber) {
     191            // 🔥 v4.0.4 FIX: Set flag to prevent autosave while loading profile data
     192            this.isLoadingProfileData = true;
     193
    200194            $('.taics-profile-btn-wide').removeClass('active');
    201195            $(`.taics-profile-btn-wide[data-profile="${profileNumber}"]`).addClass('active');
     
    206200            if (profileData && Object.keys(profileData).length > 0) {
    207201                this.loadCompleteProfileDataFromObject(profileData);
    208                
     202
    209203                // Show detailed profile loaded notification
    210204                this.showProfileLoadedNotification(profileNumber, profileData);
    211205            } else {
    212206                this.loadCompleteProfileData(profileNumber);
    213                
     207
    214208                // Show empty profile notification
    215209                this.showNotification(
     
    221215            this.updateProfileStatus();
    222216            $(document).trigger('taics_profile_changed', [profileNumber]);
     217
     218            // 🔥 FIX v4.0.3: Trigger taics_profile_loaded BEFORE clearing flag
     219            // This ensures profile-name-sync.js receives the flag as true during load
     220            const switchProfileData = profileData || {};
     221            $(document).trigger('taics_profile_loaded', [profileNumber, switchProfileData]);
     222
     223            // 🔥 v4.0.4 FIX: Clear flag after profile data loading completes
     224            // This allows autosave to work again for user changes
     225            this.isLoadingProfileData = false;
    223226        },
    224227
     
    324327        loadContentRulesData: function(contentRules) {
    325328            // Load Structure Name
    326             $('#taics-structure-name').val(contentRules.structure_name || '');
     329            const structureName = contentRules.structure_name || '';
     330            $('#taics-structure-name').val(structureName);
     331
     332            // 🔥 v4.0.4 FIX: Only trigger input if NOT currently loading profile data
     333            // This allows profile-name-sync to detect the new value without triggering autosave
     334            // when the field is being loaded from profile (not user-changed)
     335            if (!this.isLoadingProfileData) {
     336                $('#taics-structure-name').trigger('input.autosave');
     337            }
    327338
    328339            if (window.TAICS_Headings_Editor && typeof window.TAICS_Headings_Editor.setValue === 'function') {
     
    538549                              window.TAICS_Default_Tone.getValue() : 'article-specific',
    539550                content_rules: {
     551                    structure_name: $('#taics-structure-name').val() || '',
    540552                    headings: (window.TAICS_Headings_Editor && typeof window.TAICS_Headings_Editor.getValue === 'function') ?
    541553                              window.TAICS_Headings_Editor.getValue() : $('#taics-headings-editor').val() || '',
     
    749761                              window.TAICS_Default_Tone.getValue() : 'article-specific',
    750762                content_rules: {
     763                    structure_name: $('#taics-structure-name').val() || '',
    751764                    headings: (window.TAICS_Headings_Editor && typeof window.TAICS_Headings_Editor.getValue === 'function') ?
    752765                              window.TAICS_Headings_Editor.getValue() : $('#taics-headings-editor').val() || '',
  • technodrome-ai-content-assistant/trunk/features/generate-tab/default-tone.js

    r3421276 r3444453  
    3333        init: function() {
    3434            if (this.state.initialized) {
    35                 console.log('TAICS Default Tone already initialized');
    3635                return;
    3736            }
    38 
    39             console.log('Initializing TAICS Default Tone v3.4.0 (AutoSave REVOLUCIJA)');
    4037
    4138            // Bind events
     
    4643
    4744            this.state.initialized = true;
    48             console.log('TAICS Default Tone initialized successfully');
    4945        },
    5046
     
    5551            const self = this;
    5652
    57             // Handle tone selection change - trigger AutoSave
    58             $(this.config.fieldId).on('change.taics-default-tone', function() {
     53            // Handle tone selection change - uses .autosave namespace so profile-buttons.js detects it
     54            $(this.config.fieldId).on('change.autosave', function() {
    5955                const selectedValue = $(this).val();
    6056                self.handleToneChange(selectedValue);
     
    6763
    6864            // Listen for profile loaded events
    69             $(document).on('taics_profile_loaded.default-tone', function(e, data) {
    70                 self.handleProfileLoaded(data);
     65            // v4.0.3 FIX: Event now passes (profileNumber, profileData) as parameters
     66            $(document).on('taics_profile_loaded.default-tone', function(e, profileNumber, profileData) {
     67                self.handleProfileLoaded(profileData);
    7168            });
    7269
     
    8784        handleToneChange: function(selectedValue) {
    8885            if (this.state.isLocked) {
    89                 console.log('Default tone field is locked, change ignored');
    9086                return;
    9187            }
     
    9389            this.state.currentValue = selectedValue;
    9490
    95             // Trigger AutoSave event - profile-buttons.js will save to profile
    96             $(document).trigger('taics_field_changed.autosave', ['default_tone', selectedValue]);
    97 
    98             console.log('Default tone changed to:', selectedValue);
     91            // Event is already triggered by the dropdown change - no need to trigger again!
     92            // profile-buttons.js will catch the change.autosave event automatically
    9993        },
    10094
     
    10296         * Handle profile switch
    10397         */
    104         handleProfileSwitch: function(profileId) {
    105             console.log('Profile switched to:', profileId);
     98        handleProfileSwitch: function() {
    10699            // Profile data will be loaded via profile_loaded event
    107100        },
     
    114107            if (data && data.default_tone) {
    115108                this.setValue(data.default_tone);
    116                 console.log('Default tone loaded from profile:', data.default_tone);
    117109            } else {
    118110                this.setValue(this.config.defaultValue);
     
    164156            $field.prop('disabled', true).addClass('taics-field-locked');
    165157            this.state.isLocked = true;
    166             console.log('Default tone field locked');
    167158        },
    168159
     
    174165            $field.prop('disabled', false).removeClass('taics-field-locked');
    175166            this.state.isLocked = false;
    176             console.log('Default tone field unlocked');
    177167        },
    178168
     
    184174            $(document).off('.default-tone');
    185175            this.state.initialized = false;
    186             console.log('TAICS Default Tone cleaned up');
    187176        }
    188177    };
  • technodrome-ai-content-assistant/trunk/includes/class-ajax-handler.php

    r3444346 r3444453  
    15421542            }
    15431543
    1544             // Limit to 7 characters and uppercase
    1545             $profile_name = strtoupper(substr($profile_name, 0, 7));
    1546 
    1547             // Save to user_meta
    15481544            $user_id = get_current_user_id();
    1549             $meta_key = 'taics_profile_' . $profile_number . '_name';
    1550 
    1551             if ($profile_name === '' || $profile_name === 'PROFILE') {
    1552                 // Delete the meta if it's being reset to empty/default
    1553                 delete_user_meta($user_id, $meta_key);
     1545            $profile_manager = new TAICS_Profile_Manager();
     1546            $profile_data = $profile_manager->get_profile($profile_number);
     1547
     1548            // Update structure_name in content_rules
     1549            if (!isset($profile_data['content_rules'])) {
     1550                $profile_data['content_rules'] = array();
     1551            }
     1552            $profile_data['content_rules']['structure_name'] = $profile_name;
     1553
     1554            // Save the updated profile
     1555            $result = $profile_manager->save_profile($profile_number, $profile_data);
     1556
     1557            if ($result) {
     1558                wp_send_json_success([
     1559                    'message' => esc_html__('Profile name saved successfully', 'technodrome-ai-content-assistant'),
     1560                    'profile_number' => $profile_number,
     1561                    'profile_name' => $profile_name
     1562                ]);
    15541563            } else {
    1555                 // Save the custom name
    1556                 update_user_meta($user_id, $meta_key, $profile_name);
    1557             }
    1558 
    1559             wp_send_json_success([
    1560                 'message' => esc_html__('Profile name saved successfully', 'technodrome-ai-content-assistant'),
    1561                 'profile_number' => $profile_number,
    1562                 'profile_name' => $profile_name
    1563             ]);
     1564                wp_send_json_error(esc_html__('Failed to save profile name', 'technodrome-ai-content-assistant'));
     1565            }
    15641566        } catch (Exception $e) {
    15651567            wp_send_json_error(esc_html__('Failed to save profile name', 'technodrome-ai-content-assistant'));
  • technodrome-ai-content-assistant/trunk/includes/class-profile-manager.php

    r3421276 r3444453  
    125125            $result = update_user_meta($user_id, $meta_key, $json_data);
    126126
     127            // v4.0.3 FIX: update_user_meta returns false if data is identical, not if save failed
     128            // Only treat actual database errors as failure (return 0 from wpdb queries)
     129            // Success = true (data changed), false (data identical - still saved), or meta_id (new metadata)
     130            if (is_wp_error($result)) {
     131                return false;
     132            }
     133
    127134            if ($profile_name) {
    128135                update_user_meta($user_id, $meta_key . '_name', sanitize_text_field($profile_name));
    129136            }
    130 
    131             if ($result === false) {
    132                 return false;
    133     }
    134137
    135138            $this->log_profile_action('save', $profile_number, $user_id);
  • technodrome-ai-content-assistant/trunk/readme.txt

    r3444356 r3444453  
    55Tested up to: 6.9
    66Requires PHP: 8.0
    7 Stable tag: 4.0.2
     7Stable tag: 4.0.3
    88License: GPL v2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    4141== Changelog ==
    4242
     43= 4.0.5 (2026-01-21) =
     44*   **FIX**: Structure Name no longer resets to "PROFILE" when switching profiles
     45*   **FIX**: Custom profile names persist correctly without being overwritten
     46*   **IMPROVED**: Better control flow for profile data synchronization
     47
     48= 4.0.4 (2026-01-21) =
     49*   **FIX**: Structure Name field now clears properly when switching profiles
     50*   **FIX**: Profile button labels update correctly with saved custom names
     51*   **IMPROVED**: Better event listener timing for profile data synchronization
     52
     53= 4.0.3 (2026-01-21) =
     54*   **FIX**: Default Tone field now saves correctly with AutoSave
     55*   **IMPROVED**: Default tone is now properly persisted in profiles
     56*   **IMPROVED**: AutoSave event listener added for default tone changes
     57
    4358= 4.0.2 (2026-01-21) =
    4459*   **NEW**: Custom Profile Names - Rename profiles for better organization
     
    7388
    7489== Upgrade Notice ==
     90
     91= 4.0.3 =
     92Important bug fix - Default Tone field now saves correctly with AutoSave. Recommended for all users.
    7593
    7694= 4.0.2 =
  • technodrome-ai-content-assistant/trunk/technodrome-ai-content-assistant.php

    r3444346 r3444453  
    33 * Plugin Name: Technodrome AI Content Assistant
    44 * Plugin URI: https://technodrome.org/ai-content-assistant
    5  * Description: Advanced AI content generation plugin with multiple AI providers, profile system, layout templates, and content rules for WordPress. v4.0.2 - Custom Profile Names.
    6  * Version: 4.0.2
     5 * Description: Advanced AI content generation plugin with multiple AI providers, profile system, layout templates, and content rules for WordPress.
     6 * Version: 4.0.3
    77 * Author: Technodrome Team
    88 * Author URI: https://technodrome.org
     
    3030
    3131// Plugin constants
    32 define('TAICS_VERSION', '4.0.2'); // Custom Profile Names
     32define('TAICS_VERSION', '4.0.3');
    3333define('TAICS_PLUGIN_FILE', __FILE__);
    3434define('TAICS_PLUGIN_DIR', plugin_dir_path(__FILE__));
Note: See TracChangeset for help on using the changeset viewer.