Plugin Directory

Changeset 3375574


Ignore:
Timestamp:
10/09/2025 09:25:49 AM (6 months ago)
Author:
synoveo
Message:

Deploy synoveo v1.0.7

Location:
synoveo/trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • synoveo/trunk/assets/js/capability-card-manager.js

    r3375269 r3375574  
    6262     */
    6363    refreshAllCards() {
    64         if (!window.synoveo_ajax) return;
     64        if (!window.synoveo_ajax) {
     65            console.warn('synoveo_ajax not available for card refresh');
     66            return Promise.reject(new Error('AJAX not available'));
     67        }
     68       
     69        console.log('🔄 Refreshing all cards...');
    6570       
    6671        return fetch(synoveo_ajax.ajax_url, {
     
    7479            })
    7580        })
    76         .then(response => response.json())
     81        .then(response => {
     82            if (!response.ok) {
     83                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
     84            }
     85            return response.json();
     86        })
    7787        .then(data => {
    78             if (data.success && data.data.detected_plugins) {
     88            if (data.success && data.data) {
     89                console.log('✅ Card data fetched successfully');
    7990                this.updateCardsFromDetection(data.data);
    8091                return data.data;
    8192            }
    82             throw new Error('Failed to fetch card data');
    83         });
     93            throw new Error('Invalid response data: ' + JSON.stringify(data));
     94        })
     95        .catch(error => {
     96            console.error('❌ Card refresh failed:', error);
     97            // Fallback: try to refresh individual cards
     98            this.fallbackCardRefresh();
     99            throw error;
     100        });
     101    }
     102   
     103    /**
     104     * Fallback card refresh when full refresh fails
     105     */
     106    fallbackCardRefresh() {
     107        console.log('🔄 Attempting fallback card refresh...');
     108        // Force re-initialization of cards
     109        this.initializeCards();
     110       
     111        // Show notification to user
     112        this.showNotification('Dashboard updated. If you don\'t see changes, please refresh the page.', 'info');
    84113    }
    85114   
  • synoveo/trunk/assets/js/dashboard-capabilities.js

    r3375534 r3375574  
    129129        }
    130130        showError('Network error loading capabilities');
     131        // Return rejected promise to allow calling code to handle the error
     132        return Promise.reject(error);
    131133    });
    132134}
  • synoveo/trunk/assets/js/gbp-compare.js

    r3375504 r3375574  
    33  let currentSection = 'info';
    44  function $(sel){ return document.querySelector(sel); }
     5 
     6  // WordPress security compliant helper function
     7  function safeSetContent(element, content, isHTML = false) {
     8    if (isHTML) {
     9      // Only use innerHTML for trusted content (no user input)
     10      element.innerHTML = content;
     11    } else {
     12      // Use textContent for user input to prevent XSS
     13      element.textContent = content;
     14    }
     15  }
    516
    617  async function wpAjax(action, data={}){
     
    2233    if(!json || json.success !== true) {
    2334      // Handle both old and new error formats
    24       let msg = `HTTP ${res.status}`;
     35      let msg = `Failed to load data: HTTP ${res.status}`;
    2536      if (json) {
    2637        if (json.data && json.data.message) {
     
    2839        } else if (json.error) {
    2940          msg = typeof json.error === 'string' ? json.error : (json.error.message || JSON.stringify(json.error));
    30         }
    31       }
     41        } else if (json.data && typeof json.data === 'string') {
     42          msg = json.data;
     43        }
     44      }
     45     
     46      // Add helpful context for common errors
     47      if (msg.includes('HTTP 200') || msg.includes('Failed to load data')) {
     48        msg += '\n\nEnsure your Synoveo API key is valid and Google connection is active.';
     49      }
     50     
    3251      throw new Error(msg);
    3352    }
     
    875894    currentSection = section || currentSection || 'info';
    876895    const body = $('#'+modalId+' #synoveo-gbp-compare-body');
    877     body.innerHTML = '<div style="padding:16px; text-align:center; color:#64748b;">Loading…</div>';
     896    // Create loading element using DOM methods (WordPress security compliant)
     897    const loadingDiv = document.createElement('div');
     898    loadingDiv.style.cssText = 'padding:16px; text-align:center; color:#64748b;';
     899    loadingDiv.textContent = 'Loading…';
     900    body.innerHTML = '';
     901    body.appendChild(loadingDiv);
    878902    try{
    879903      const [wpSnap, gbp] = await Promise.all([
     
    12841308      }
    12851309    }catch(e){
    1286       body.innerHTML = `<div style="padding:16px;color:#ef4444;">Failed to load data: ${escapeHtml(e.message)}<br/><br/>Ensure your Synoveo API key is valid and Google connection is active.</div>`;
     1310      console.error('❌ GBP Compare load error:', e);
     1311      console.error('❌ Error details:', {
     1312        message: e.message,
     1313        stack: e.stack,
     1314        section: currentSection
     1315      });
     1316     
     1317      // Show user-friendly error message
     1318      let errorMessage = escapeHtml(e.message);
     1319      if (errorMessage.includes('HTTP 200')) {
     1320        errorMessage = 'Failed to load Google Business Profile data. This usually means the API call succeeded but returned an error response.';
     1321      }
     1322     
     1323      // Create error container using DOM methods (WordPress security compliant)
     1324      const errorContainer = document.createElement('div');
     1325      errorContainer.style.cssText = 'padding:16px;color:#ef4444;';
     1326     
     1327      // Create heading
     1328      const heading = document.createElement('h3');
     1329      heading.style.cssText = 'margin:0 0 8px 0;color:#dc2626;';
     1330      heading.textContent = '⚠️ Unable to Load Data';
     1331      errorContainer.appendChild(heading);
     1332     
     1333      // Create error message
     1334      const errorPara = document.createElement('p');
     1335      errorPara.style.cssText = 'margin:0 0 12px 0;';
     1336      errorPara.textContent = errorMessage;
     1337      errorContainer.appendChild(errorPara);
     1338     
     1339      // Create troubleshooting box
     1340      const troubleshootingBox = document.createElement('div');
     1341      troubleshootingBox.style.cssText = 'background:#fef2f2;border:1px solid #fecaca;border-radius:6px;padding:12px;margin:12px 0;';
     1342     
     1343      const troubleshootingTitle = document.createElement('strong');
     1344      troubleshootingTitle.textContent = 'Troubleshooting:';
     1345      troubleshootingBox.appendChild(troubleshootingTitle);
     1346     
     1347      const troubleshootingList = document.createElement('ul');
     1348      troubleshootingList.style.cssText = 'margin:8px 0 0 0;padding-left:20px;';
     1349     
     1350      const troubleshootingItems = [
     1351        'Ensure your Synoveo API key is valid',
     1352        'Verify Google Business Profile connection is active',
     1353        'Check that your business has a valid Google Business Profile',
     1354        'Try refreshing the page and opening the modal again'
     1355      ];
     1356     
     1357      troubleshootingItems.forEach(itemText => {
     1358        const listItem = document.createElement('li');
     1359        listItem.textContent = itemText;
     1360        troubleshootingList.appendChild(listItem);
     1361      });
     1362     
     1363      troubleshootingBox.appendChild(troubleshootingList);
     1364      errorContainer.appendChild(troubleshootingBox);
     1365     
     1366      // Create close button
     1367      const closeButton = document.createElement('button');
     1368      closeButton.style.cssText = 'background:#ef4444;color:white;border:none;padding:8px 16px;border-radius:4px;cursor:pointer;';
     1369      closeButton.textContent = 'Close';
     1370      closeButton.addEventListener('click', () => {
     1371        if (window.SynoveoGbpCompare && typeof window.SynoveoGbpCompare.close === 'function') {
     1372          window.SynoveoGbpCompare.close();
     1373        }
     1374      });
     1375      errorContainer.appendChild(closeButton);
     1376     
     1377      // Clear body and append error container
     1378      body.innerHTML = '';
     1379      body.appendChild(errorContainer);
    12871380    }
    12881381  }
     
    14141507          }
    14151508         
    1416           // Refresh dashboard to update quota
     1509          // Refresh dashboard to update quota with proper error handling
    14171510          if (typeof loadCapabilities === 'function') {
    1418             loadCapabilities();
     1511            console.log('🔄 Refreshing dashboard after sync...');
     1512            loadCapabilities()
     1513              .then(() => {
     1514                console.log('✅ Dashboard refreshed successfully');
     1515                // Force re-render of cards if card manager is available
     1516                if (window.synoveoCardManager && typeof window.synoveoCardManager.refreshAllCards === 'function') {
     1517                  window.synoveoCardManager.refreshAllCards()
     1518                    .then(() => {
     1519                      console.log('✅ Cards refreshed successfully');
     1520                    })
     1521                    .catch(err => {
     1522                      console.warn('⚠️ Card refresh failed:', err);
     1523                    });
     1524                }
     1525              })
     1526              .catch(error => {
     1527                console.error('❌ Dashboard refresh failed:', error);
     1528                // Show user-friendly error message
     1529                if (window.synoveoCardManager) {
     1530                  window.synoveoCardManager.showNotification('Sync completed but dashboard refresh failed. Please refresh the page to see updates.', 'info');
     1531                }
     1532              });
    14191533          }
    14201534        }, 4000);
  • synoveo/trunk/includes/admin/class-synoveo-admin-controller.php

    r3375269 r3375574  
    14871487
    14881488            if ( ! $business_id ) {
     1489                SYNOVEO_Logger::debug( 'GBP Profile: No business ID found', 'Admin' );
    14891490                wp_send_json_error( array( 'message' => __( 'Failed to initialize business. Please check API connection.', 'synoveo' ) ) );
    14901491                return;
    14911492            }
    14921493
     1494            SYNOVEO_Logger::debug( "GBP Profile: Fetching profile for business ID: {$business_id}", 'Admin' );
    14931495            $api_response = $this->api_service->call_api( 'google-business/profile', array( 'businessId' => $business_id ) );
     1496            SYNOVEO_Logger::debug( 'GBP Profile API response: ' . wp_json_encode( $api_response ), 'Admin' );
    14941497
    14951498            if ( $api_response['success'] ) {
  • synoveo/trunk/includes/class-synoveo-rate-limiter.php

    r3375269 r3375574  
    1919    private const PER_100_SECONDS_LIMIT = 200;   // vs Google's 250
    2020    private const PER_USER_LIMIT        = 20;           // vs Google's 25
    21     private const BURST_LIMIT           = 10;              // Max burst requests
     21    private const BURST_LIMIT           = 20;              // Max burst requests
    2222
    2323    // Cache keys
  • synoveo/trunk/readme.txt

    r3375534 r3375574  
    55Tested up to: 6.8
    66Requires PHP: 7.4
    7 Stable tag: 1.0.6a
     7Stable tag: 1.0.7
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    253253
    254254== Changelog ==
     255
     256= 1.0.7 =
     257* **ENHANCEMENT:** Improved error handling in capability card manager with clearer AJAX failure feedback
     258* **ENHANCEMENT:** Added fallback mechanism for card refresh when primary refresh fails
     259* **ENHANCEMENT:** Enhanced user notifications in dashboard capabilities for graceful network error handling
     260* **SECURITY:** Introduced security-compliant content setting function in GBP compare to prevent XSS vulnerabilities
     261* **BUGFIX:** Fixed "Too many requests in burst" error when opening GBP Compare after connection
     262* **ENHANCEMENT:** Increased burst limit from 10 to 20 requests for better user workflow support
     263* **UX:** Users can now immediately use GBP Compare after connecting to Google Business Profile
    255264
    256265= 1.0.6a =
  • synoveo/trunk/synoveo.php

    r3375534 r3375574  
    44 * Plugin URI: https://www.synoveo.com
    55 * Description: Grow revenue by improving your online business presence. Synoveo keeps your Google Business Profile accurate and up-to-date, driving more calls, bookings, visits, and sales.
    6  * Version: 1.0.6a
     6 * Version: 1.0.7
    77 * Author: Synoveo (CODE75)
    88 * Author URI: https://www.synoveo.com
     
    2424// Plugin constants
    2525// Single source of truth for version number
    26 $base_version = '1.0.5'; // ← Change only this when bumping version
     26$base_version = '1.0.7'; // ← Change only this when bumping version
    2727define( 'SYNOVEO_VERSION', defined( 'WP_DEBUG' ) && WP_DEBUG ? $base_version . '-dev-' . time() : $base_version );
    2828define( 'SYNOVEO_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
Note: See TracChangeset for help on using the changeset viewer.