Changeset 3257427
- Timestamp:
- 03/17/2025 11:51:42 PM (11 months ago)
- Location:
- seo-ai-audit-tool
- Files:
-
- 14 edited
- 1 copied
-
tags/1.0.9 (copied) (copied from seo-ai-audit-tool/trunk)
-
tags/1.0.9/assets/js/seoaudp-backlinks-analyzer.js (modified) (8 diffs)
-
tags/1.0.9/changelog.txt (modified) (1 diff)
-
tags/1.0.9/includes/class-seo-audit-data-import.php (modified) (2 diffs)
-
tags/1.0.9/includes/class-seo-audit-db.php (modified) (1 diff)
-
tags/1.0.9/includes/views/partials/footer-partial.php (modified) (1 diff)
-
tags/1.0.9/readme.md (modified) (1 diff)
-
tags/1.0.9/seo-ai-audit-tool.php (modified) (3 diffs)
-
trunk/assets/js/seoaudp-backlinks-analyzer.js (modified) (8 diffs)
-
trunk/changelog.txt (modified) (1 diff)
-
trunk/includes/class-seo-audit-data-import.php (modified) (2 diffs)
-
trunk/includes/class-seo-audit-db.php (modified) (1 diff)
-
trunk/includes/views/partials/footer-partial.php (modified) (1 diff)
-
trunk/readme.md (modified) (1 diff)
-
trunk/seo-ai-audit-tool.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
seo-ai-audit-tool/tags/1.0.9/assets/js/seoaudp-backlinks-analyzer.js
r3252394 r3257427 1686 1686 } 1687 1687 1688 // Get branded keywords for display 1689 let brandedKeywords = []; 1690 try { 1691 const storedBrandedKeywords = localStorage.getItem('seoaudp_branded_keywords'); 1692 if (storedBrandedKeywords) { 1693 brandedKeywords = JSON.parse(storedBrandedKeywords); 1694 } 1695 } catch (error) { 1696 console.error('Error parsing branded keywords:', error); 1697 } 1698 1699 // Branded keywords label 1700 const brandedKeywordsLabel = Array.isArray(brandedKeywords) && brandedKeywords.length > 0 1701 ? `Branded KWs (${brandedKeywords.join(', ')})` 1702 : 'Branded KWs'; 1703 1688 1704 // First, ensure all orders have page IDs 1689 1705 const ordersWithPageIds = orders.map(async order => { … … 1760 1776 const brandedKwLinks = brandedKwKeyword ? (brandedKwKeyword.desiredLinks || 1) : ''; 1761 1777 1778 // Get the current branded keywords from localStorage 1779 let brandedKeywordsLabel = 'Branded KWs'; 1780 try { 1781 const storedBrandedKeywords = localStorage.getItem('seoaudp_branded_keywords'); 1782 if (storedBrandedKeywords) { 1783 const brandedKeywords = JSON.parse(storedBrandedKeywords); 1784 if (Array.isArray(brandedKeywords) && brandedKeywords.length > 0) { 1785 brandedKeywordsLabel = `Branded KWs (${brandedKeywords.join(', ')})`; 1786 } 1787 } 1788 } catch (error) { 1789 console.error('Error parsing branded keywords:', error); 1790 } 1791 1762 1792 // Add first row with URL, Naked URL keyword and delete button (with top border for group) 1763 1793 html += ` … … 1782 1812 <td></td> 1783 1813 <td></td> 1784 <td class="seoaudp-keyword-cell"> Branded KWs</td>1814 <td class="seoaudp-keyword-cell">${brandedKeywordsLabel}</td> 1785 1815 <td>${brandedKwLinks}</td> 1786 1816 <td class="seoaudp-order-actions"> … … 2026 2056 // Update the showKeywordEditor method to handle multiple keywords 2027 2057 async showKeywordEditor(cell, orderId, pageUrl) { 2058 // First create a loading indicator 2059 cell.innerHTML = `<span class="seoaudp-loading-spinner">Loading...</span>`; 2060 2028 2061 try { 2029 // Store the original content 2030 const originalContent = cell.innerHTML; 2031 cell.setAttribute('data-original-content', originalContent); 2032 2033 // Get the row 2034 const row = cell.closest('tr'); 2035 2036 // Try to get page ID directly from the row 2037 let pageId = row.getAttribute('data-page-id'); 2038 2039 // If not found, try to get it from the hidden input 2062 // Get page ID from URL 2063 let pageId = await this.getPageIdFromUrl(pageUrl); 2064 2040 2065 if (!pageId) { 2041 const hiddenInput = row.querySelector('.seoaudp-page-id-hidden'); 2042 if (hiddenInput) { 2043 pageId = hiddenInput.value; 2044 } 2045 } 2046 2047 // If still not found, try to get it from the URL 2048 if (!pageId) { 2049 // Make sure we have a valid URL 2050 if (!pageUrl) { 2051 const anchor = row.querySelector('a'); 2052 if (anchor) { 2053 pageUrl = anchor.href; 2054 } else { 2055 // Try to get URL from data attribute 2056 pageUrl = row.getAttribute('data-page-url'); 2057 if (!pageUrl) { 2058 // Try to get URL from a sibling row that has an anchor 2059 const siblingWithAnchor = row.parentElement.querySelector('tr[data-page-url] a'); 2060 if (siblingWithAnchor) { 2061 pageUrl = siblingWithAnchor.href; 2062 } else { 2063 console.error('Could not determine page URL'); 2064 alert('Could not determine page URL for this row'); 2065 return; 2066 } 2067 } 2066 throw new Error('Could not determine page ID'); 2067 } 2068 2069 // Get all keywords for this page 2070 const keywordsData = await this.getKeywordsForPage(pageId); 2071 2072 // Get current keywords in the row 2073 const currentKeywords = this.getCurrentKeywords(cell); 2074 2075 // Get branded keywords label with parentheses if available 2076 let brandedKeywordsLabel = 'Branded KWs'; 2077 try { 2078 const storedBrandedKeywords = localStorage.getItem('seoaudp_branded_keywords'); 2079 if (storedBrandedKeywords) { 2080 const brandedKeywords = JSON.parse(storedBrandedKeywords); 2081 if (Array.isArray(brandedKeywords) && brandedKeywords.length > 0) { 2082 brandedKeywordsLabel = `Branded KWs (${brandedKeywords.join(', ')})`; 2068 2083 } 2069 2084 } 2070 2071 // Get page ID from URL 2072 pageId = await this.getPageIdFromUrl(pageUrl); 2073 } 2074 2075 if (!pageId) { 2076 console.error('Could not determine page ID'); 2077 alert('Could not determine page ID for this row'); 2078 return; 2079 } 2080 2081 // Get keywords for this page 2082 const keywordsData = await this.getKeywordsForPage(pageId); 2083 if (!keywordsData) { 2084 alert('No keywords found for this page'); 2085 return; 2086 } 2087 2088 // Get all currently selected keywords for this order 2089 const currentKeywords = this.getCurrentKeywords(cell); 2090 2091 // Create the editor HTML 2085 } catch (error) { 2086 console.error('Error parsing branded keywords:', error); 2087 } 2088 2089 // Create editor HTML 2092 2090 const editorHtml = this.createKeywordEditorHtml(keywordsData, currentKeywords, orderId); 2093 2091 2094 // Replace the cell content with theeditor2092 // Replace loading indicator with editor 2095 2093 cell.innerHTML = editorHtml; 2096 2094 2097 // Don't show the save button initially - it will appear when changes are made 2095 // Replace "Branded KWs" text with the label that includes keywords in parentheses 2096 const brandedOptions = cell.querySelectorAll('option'); 2097 brandedOptions.forEach(option => { 2098 if (option.textContent === 'Branded KWs') { 2099 option.textContent = brandedKeywordsLabel; 2100 } 2101 }); 2102 2103 // Set up the editor 2104 const editor = cell.querySelector('.seoaudp-keyword-editor'); 2105 const saveButton = cell.querySelector('.seoaudp-save-keywords'); 2106 const cancelButton = cell.querySelector('.seoaudp-cancel-edit'); 2098 2107 } catch (error) { 2099 2108 console.error('Error showing keyword editor:', error); … … 2318 2327 // Method to create the keyword editor HTML 2319 2328 createKeywordEditorHtml(keywordsData, currentKeywords, orderId) { 2329 // Get branded keywords label with parentheses if available 2330 let brandedKeywordsLabel = 'Branded KWs'; 2320 2331 try { 2321 // Convert keywords string to array of objects 2322 const keywordArray = keywordsData.split('|') 2323 .filter(item => item) // Remove empty items 2324 .map(item => { 2325 const [keyword, volume, traffic] = item.split(':'); 2326 return { 2327 keyword: keyword || '', 2328 volume: parseInt(volume) || 0, 2329 traffic: parseInt(traffic) || 0 2330 }; 2331 }); 2332 2333 // If no keywords after processing, show message 2334 if (!keywordArray.length) { 2335 return '<div class="seoaudp-no-keywords">No keywords found for this URL</div>'; 2336 } 2337 2338 // Create table with data and checkboxes 2339 return ` 2340 <div class="seoaudp-keywords-editor" data-order-id="${orderId}"> 2341 <div class="seoaudp-keywords-editor-header"> 2342 <h4>Select Keywords</h4> 2343 <button type="button" class="seoaudp-close-keyword-editor"> 2344 <span class="dashicons dashicons-no-alt"></span> 2345 </button> 2346 </div> 2347 <table class="seoaudp-keywords-table"> 2348 <thead> 2349 <tr> 2350 <th>Keyword</th> 2351 <th>Volume</th> 2352 <th>Select</th> 2353 </tr> 2354 </thead> 2355 <tbody> 2356 ${keywordArray.map(kw => ` 2357 <tr> 2358 <td>${kw.keyword}</td> 2359 <td>${kw.volume}</td> 2360 <td> 2361 <input type="checkbox" 2362 class="seoaudp-keyword-selector" 2363 data-keyword="${kw.keyword}" 2364 data-original-state="${currentKeywords.includes(kw.keyword)}" 2365 ${currentKeywords.includes(kw.keyword) ? 'checked' : ''} /> 2366 </td> 2367 </tr> 2368 `).join('')} 2369 </tbody> 2370 </table> 2332 const storedBrandedKeywords = localStorage.getItem('seoaudp_branded_keywords'); 2333 if (storedBrandedKeywords) { 2334 const brandedKeywords = JSON.parse(storedBrandedKeywords); 2335 if (Array.isArray(brandedKeywords) && brandedKeywords.length > 0) { 2336 brandedKeywordsLabel = `Branded KWs (${brandedKeywords.join(', ')})`; 2337 } 2338 } 2339 } catch (error) { 2340 console.error('Error parsing branded keywords:', error); 2341 } 2342 2343 let html = ` 2344 <div class="seoaudp-keyword-editor-container"> 2345 <select class="seoaudp-keyword-editor" multiple> 2346 <option value="Naked URL" ${currentKeywords.includes('Naked URL') ? 'selected' : ''}>Naked URL</option> 2347 <option value="Branded KWs" ${currentKeywords.includes('Branded KWs') ? 'selected' : ''}>${brandedKeywordsLabel}</option> 2348 <option value="Keyword" ${currentKeywords.includes('Keyword') ? 'selected' : ''}>Keyword</option> 2349 </select> 2350 </div> 2351 `; 2352 2353 // Add checkboxes for individual keywords 2354 keywordsData.forEach(keyword => { 2355 html += ` 2356 <div class="seoaudp-keyword-selector-container"> 2357 <input type="checkbox" class="seoaudp-keyword-selector" data-keyword="${keyword}" data-original-state="${currentKeywords.includes(keyword)}"> 2358 <span class="seoaudp-keyword-label">${keyword}</span> 2371 2359 </div> 2372 2360 `; 2373 } catch (error) { 2374 console.error('Error creating keyword editor:', error); 2375 return '<div class="seoaudp-no-keywords">Error creating keyword editor</div>'; 2376 } 2361 }); 2362 2363 return html; 2377 2364 } 2378 2365 … … 2629 2616 // Helper method to set domain-based keywords 2630 2617 useDomainKeywords() { 2631 // Generar keywords basadas en el dominio2632 2618 const domainKeywords = this.getDomainBrandedKeywords(); 2633 console.log("Generated domain keywords:", domainKeywords);2634 2619 2635 2620 if (domainKeywords.length > 0 && this.tomSelect) { 2636 // Limpiar cualquier keyword existente2621 // Clear any existing keywords 2637 2622 this.tomSelect.clear(); 2638 2623 2639 // A gregar las nuevas keywords basadas en el dominio2624 // Add new keywords based on domain 2640 2625 domainKeywords.forEach(keyword => { 2641 2626 this.tomSelect.addOption({value: keyword, text: keyword}); … … 2643 2628 }); 2644 2629 2645 // Habilitar el botón de guardar2630 // Enable save button 2646 2631 const saveBtn = document.getElementById('save-branded-keywords-btn'); 2647 2632 if (saveBtn) { … … 2649 2634 } 2650 2635 2651 // Guardar automáticamente las keywords basadas en dominio2636 // Automatically save domain-based keywords 2652 2637 this.saveBrandedKeywords(); 2653 2654 console.log("Domain-based keywords set and saved");2655 2638 } else { 2656 2639 console.warn("No domain keywords generated or TomSelect not initialized"); -
seo-ai-audit-tool/tags/1.0.9/changelog.txt
r3253527 r3257427 1 = 1.0.9 2025-03-17 2 3 Improved: Added branded keywords to backlinks order CSV export 4 Updated: Footer GUI update 5 Fixed: Security improvements 6 1 7 = 1.0.8 2025-03-10 2 8 -
seo-ai-audit-tool/tags/1.0.9/includes/class-seo-audit-data-import.php
r3250723 r3257427 582 582 } 583 583 584 // Rest of the existing code...585 584 $content = mb_convert_encoding($content, 'UTF-8', mb_detect_encoding($content, 'UTF-8, ISO-8859-1', true)); 586 585 … … 588 587 $bom = pack('H*','EFBBBF'); 589 588 $content = preg_replace("/^$bom/", '', $content); 590 591 // Continue with existing CSV processing...592 589 593 590 $csv_data = array_map('str_getcsv', explode("\n", $content)); -
seo-ai-audit-tool/tags/1.0.9/includes/class-seo-audit-db.php
r3250723 r3257427 1173 1173 1174 1174 public function seoaudp_handle_ahrefs_backlinks_csv_upload() { 1175 // ... existing validation code ...1176 1175 1177 1176 // Define column mappings -
seo-ai-audit-tool/tags/1.0.9/includes/views/partials/footer-partial.php
r3216569 r3257427 40 40 <img src="<?php echo esc_url(SEOAUDP_PLUGIN_URL . 'assets/images/stb-logo.png'); ?>" alt="Smart Table Builder" title="Smart Table Builder"> 41 41 </a> 42 <a href=" #" target="_blank" class="seoaudp-footer-plugin-logos">43 <img src="<?php echo esc_url(SEOAUDP_PLUGIN_URL . 'assets/images/ hdh-logo.png'); ?>" alt="Help Desk Hero" title="Help Desk Hero">42 <a href="https://seo-ai-audit-tool.designful.ca/" target="_blank" class="seoaudp-footer-plugin-logos"> 43 <img src="<?php echo esc_url(SEOAUDP_PLUGIN_URL . 'assets/images/saat-logo.png'); ?>" alt="SEO Audit Tool" title="SEO Audit Tool"> 44 44 </a> 45 45 </div> -
seo-ai-audit-tool/tags/1.0.9/readme.md
r3253527 r3257427 2 2 Contributors: Designful 3 3 Plugin URL: https://seo-ai-audit-tool.designful.ca/ 4 Version: 1.0. 84 Version: 1.0.9 5 5 Tags: seo audit, ai seo, conversion optimization, content analysis, search intent 6 6 Requires at least: 4.0 7 7 Tested up to: 6.7 8 Stable tag: 1.0. 88 Stable tag: 1.0.9 9 9 Requires PHP: 7.4 10 10 License: GPLv2 or later -
seo-ai-audit-tool/tags/1.0.9/seo-ai-audit-tool.php
r3253527 r3257427 4 4 * Plugin URI: https://designful.ca/apps/seo-ai-audit-tool/ 5 5 * Description: A WordPress plugin to audit SEO elements of pages and perform AI-powered content analysis 6 * Version: 1.0. 86 * Version: 1.0.9 7 7 * Author: Designful 8 8 * License: GPL2 … … 20 20 define('SEOAUDP_PLUGIN_DIR', plugin_dir_path(__FILE__)); 21 21 define('SEOAUDP_PLUGIN_URL', plugin_dir_url(__FILE__)); 22 define('SEOAUDP_PLUGIN_VERSION', '1.0. 8');22 define('SEOAUDP_PLUGIN_VERSION', '1.0.9'); 23 23 define('SEOAUDP_PLUGIN_BETA_VERSION', false); 24 24 define('SEOAUDP_DB_VERSION', '1.6'); … … 434 434 seoaudp_debug_log($_POST); 435 435 436 try { 437 // ... existing code ... 438 } catch (Exception $e) { 439 seoaudp_debug_log('Error: ' . $e->getMessage()); 440 // ... existing error handling ... 441 } 442 } 436 } -
seo-ai-audit-tool/trunk/assets/js/seoaudp-backlinks-analyzer.js
r3252394 r3257427 1686 1686 } 1687 1687 1688 // Get branded keywords for display 1689 let brandedKeywords = []; 1690 try { 1691 const storedBrandedKeywords = localStorage.getItem('seoaudp_branded_keywords'); 1692 if (storedBrandedKeywords) { 1693 brandedKeywords = JSON.parse(storedBrandedKeywords); 1694 } 1695 } catch (error) { 1696 console.error('Error parsing branded keywords:', error); 1697 } 1698 1699 // Branded keywords label 1700 const brandedKeywordsLabel = Array.isArray(brandedKeywords) && brandedKeywords.length > 0 1701 ? `Branded KWs (${brandedKeywords.join(', ')})` 1702 : 'Branded KWs'; 1703 1688 1704 // First, ensure all orders have page IDs 1689 1705 const ordersWithPageIds = orders.map(async order => { … … 1760 1776 const brandedKwLinks = brandedKwKeyword ? (brandedKwKeyword.desiredLinks || 1) : ''; 1761 1777 1778 // Get the current branded keywords from localStorage 1779 let brandedKeywordsLabel = 'Branded KWs'; 1780 try { 1781 const storedBrandedKeywords = localStorage.getItem('seoaudp_branded_keywords'); 1782 if (storedBrandedKeywords) { 1783 const brandedKeywords = JSON.parse(storedBrandedKeywords); 1784 if (Array.isArray(brandedKeywords) && brandedKeywords.length > 0) { 1785 brandedKeywordsLabel = `Branded KWs (${brandedKeywords.join(', ')})`; 1786 } 1787 } 1788 } catch (error) { 1789 console.error('Error parsing branded keywords:', error); 1790 } 1791 1762 1792 // Add first row with URL, Naked URL keyword and delete button (with top border for group) 1763 1793 html += ` … … 1782 1812 <td></td> 1783 1813 <td></td> 1784 <td class="seoaudp-keyword-cell"> Branded KWs</td>1814 <td class="seoaudp-keyword-cell">${brandedKeywordsLabel}</td> 1785 1815 <td>${brandedKwLinks}</td> 1786 1816 <td class="seoaudp-order-actions"> … … 2026 2056 // Update the showKeywordEditor method to handle multiple keywords 2027 2057 async showKeywordEditor(cell, orderId, pageUrl) { 2058 // First create a loading indicator 2059 cell.innerHTML = `<span class="seoaudp-loading-spinner">Loading...</span>`; 2060 2028 2061 try { 2029 // Store the original content 2030 const originalContent = cell.innerHTML; 2031 cell.setAttribute('data-original-content', originalContent); 2032 2033 // Get the row 2034 const row = cell.closest('tr'); 2035 2036 // Try to get page ID directly from the row 2037 let pageId = row.getAttribute('data-page-id'); 2038 2039 // If not found, try to get it from the hidden input 2062 // Get page ID from URL 2063 let pageId = await this.getPageIdFromUrl(pageUrl); 2064 2040 2065 if (!pageId) { 2041 const hiddenInput = row.querySelector('.seoaudp-page-id-hidden'); 2042 if (hiddenInput) { 2043 pageId = hiddenInput.value; 2044 } 2045 } 2046 2047 // If still not found, try to get it from the URL 2048 if (!pageId) { 2049 // Make sure we have a valid URL 2050 if (!pageUrl) { 2051 const anchor = row.querySelector('a'); 2052 if (anchor) { 2053 pageUrl = anchor.href; 2054 } else { 2055 // Try to get URL from data attribute 2056 pageUrl = row.getAttribute('data-page-url'); 2057 if (!pageUrl) { 2058 // Try to get URL from a sibling row that has an anchor 2059 const siblingWithAnchor = row.parentElement.querySelector('tr[data-page-url] a'); 2060 if (siblingWithAnchor) { 2061 pageUrl = siblingWithAnchor.href; 2062 } else { 2063 console.error('Could not determine page URL'); 2064 alert('Could not determine page URL for this row'); 2065 return; 2066 } 2067 } 2066 throw new Error('Could not determine page ID'); 2067 } 2068 2069 // Get all keywords for this page 2070 const keywordsData = await this.getKeywordsForPage(pageId); 2071 2072 // Get current keywords in the row 2073 const currentKeywords = this.getCurrentKeywords(cell); 2074 2075 // Get branded keywords label with parentheses if available 2076 let brandedKeywordsLabel = 'Branded KWs'; 2077 try { 2078 const storedBrandedKeywords = localStorage.getItem('seoaudp_branded_keywords'); 2079 if (storedBrandedKeywords) { 2080 const brandedKeywords = JSON.parse(storedBrandedKeywords); 2081 if (Array.isArray(brandedKeywords) && brandedKeywords.length > 0) { 2082 brandedKeywordsLabel = `Branded KWs (${brandedKeywords.join(', ')})`; 2068 2083 } 2069 2084 } 2070 2071 // Get page ID from URL 2072 pageId = await this.getPageIdFromUrl(pageUrl); 2073 } 2074 2075 if (!pageId) { 2076 console.error('Could not determine page ID'); 2077 alert('Could not determine page ID for this row'); 2078 return; 2079 } 2080 2081 // Get keywords for this page 2082 const keywordsData = await this.getKeywordsForPage(pageId); 2083 if (!keywordsData) { 2084 alert('No keywords found for this page'); 2085 return; 2086 } 2087 2088 // Get all currently selected keywords for this order 2089 const currentKeywords = this.getCurrentKeywords(cell); 2090 2091 // Create the editor HTML 2085 } catch (error) { 2086 console.error('Error parsing branded keywords:', error); 2087 } 2088 2089 // Create editor HTML 2092 2090 const editorHtml = this.createKeywordEditorHtml(keywordsData, currentKeywords, orderId); 2093 2091 2094 // Replace the cell content with theeditor2092 // Replace loading indicator with editor 2095 2093 cell.innerHTML = editorHtml; 2096 2094 2097 // Don't show the save button initially - it will appear when changes are made 2095 // Replace "Branded KWs" text with the label that includes keywords in parentheses 2096 const brandedOptions = cell.querySelectorAll('option'); 2097 brandedOptions.forEach(option => { 2098 if (option.textContent === 'Branded KWs') { 2099 option.textContent = brandedKeywordsLabel; 2100 } 2101 }); 2102 2103 // Set up the editor 2104 const editor = cell.querySelector('.seoaudp-keyword-editor'); 2105 const saveButton = cell.querySelector('.seoaudp-save-keywords'); 2106 const cancelButton = cell.querySelector('.seoaudp-cancel-edit'); 2098 2107 } catch (error) { 2099 2108 console.error('Error showing keyword editor:', error); … … 2318 2327 // Method to create the keyword editor HTML 2319 2328 createKeywordEditorHtml(keywordsData, currentKeywords, orderId) { 2329 // Get branded keywords label with parentheses if available 2330 let brandedKeywordsLabel = 'Branded KWs'; 2320 2331 try { 2321 // Convert keywords string to array of objects 2322 const keywordArray = keywordsData.split('|') 2323 .filter(item => item) // Remove empty items 2324 .map(item => { 2325 const [keyword, volume, traffic] = item.split(':'); 2326 return { 2327 keyword: keyword || '', 2328 volume: parseInt(volume) || 0, 2329 traffic: parseInt(traffic) || 0 2330 }; 2331 }); 2332 2333 // If no keywords after processing, show message 2334 if (!keywordArray.length) { 2335 return '<div class="seoaudp-no-keywords">No keywords found for this URL</div>'; 2336 } 2337 2338 // Create table with data and checkboxes 2339 return ` 2340 <div class="seoaudp-keywords-editor" data-order-id="${orderId}"> 2341 <div class="seoaudp-keywords-editor-header"> 2342 <h4>Select Keywords</h4> 2343 <button type="button" class="seoaudp-close-keyword-editor"> 2344 <span class="dashicons dashicons-no-alt"></span> 2345 </button> 2346 </div> 2347 <table class="seoaudp-keywords-table"> 2348 <thead> 2349 <tr> 2350 <th>Keyword</th> 2351 <th>Volume</th> 2352 <th>Select</th> 2353 </tr> 2354 </thead> 2355 <tbody> 2356 ${keywordArray.map(kw => ` 2357 <tr> 2358 <td>${kw.keyword}</td> 2359 <td>${kw.volume}</td> 2360 <td> 2361 <input type="checkbox" 2362 class="seoaudp-keyword-selector" 2363 data-keyword="${kw.keyword}" 2364 data-original-state="${currentKeywords.includes(kw.keyword)}" 2365 ${currentKeywords.includes(kw.keyword) ? 'checked' : ''} /> 2366 </td> 2367 </tr> 2368 `).join('')} 2369 </tbody> 2370 </table> 2332 const storedBrandedKeywords = localStorage.getItem('seoaudp_branded_keywords'); 2333 if (storedBrandedKeywords) { 2334 const brandedKeywords = JSON.parse(storedBrandedKeywords); 2335 if (Array.isArray(brandedKeywords) && brandedKeywords.length > 0) { 2336 brandedKeywordsLabel = `Branded KWs (${brandedKeywords.join(', ')})`; 2337 } 2338 } 2339 } catch (error) { 2340 console.error('Error parsing branded keywords:', error); 2341 } 2342 2343 let html = ` 2344 <div class="seoaudp-keyword-editor-container"> 2345 <select class="seoaudp-keyword-editor" multiple> 2346 <option value="Naked URL" ${currentKeywords.includes('Naked URL') ? 'selected' : ''}>Naked URL</option> 2347 <option value="Branded KWs" ${currentKeywords.includes('Branded KWs') ? 'selected' : ''}>${brandedKeywordsLabel}</option> 2348 <option value="Keyword" ${currentKeywords.includes('Keyword') ? 'selected' : ''}>Keyword</option> 2349 </select> 2350 </div> 2351 `; 2352 2353 // Add checkboxes for individual keywords 2354 keywordsData.forEach(keyword => { 2355 html += ` 2356 <div class="seoaudp-keyword-selector-container"> 2357 <input type="checkbox" class="seoaudp-keyword-selector" data-keyword="${keyword}" data-original-state="${currentKeywords.includes(keyword)}"> 2358 <span class="seoaudp-keyword-label">${keyword}</span> 2371 2359 </div> 2372 2360 `; 2373 } catch (error) { 2374 console.error('Error creating keyword editor:', error); 2375 return '<div class="seoaudp-no-keywords">Error creating keyword editor</div>'; 2376 } 2361 }); 2362 2363 return html; 2377 2364 } 2378 2365 … … 2629 2616 // Helper method to set domain-based keywords 2630 2617 useDomainKeywords() { 2631 // Generar keywords basadas en el dominio2632 2618 const domainKeywords = this.getDomainBrandedKeywords(); 2633 console.log("Generated domain keywords:", domainKeywords);2634 2619 2635 2620 if (domainKeywords.length > 0 && this.tomSelect) { 2636 // Limpiar cualquier keyword existente2621 // Clear any existing keywords 2637 2622 this.tomSelect.clear(); 2638 2623 2639 // A gregar las nuevas keywords basadas en el dominio2624 // Add new keywords based on domain 2640 2625 domainKeywords.forEach(keyword => { 2641 2626 this.tomSelect.addOption({value: keyword, text: keyword}); … … 2643 2628 }); 2644 2629 2645 // Habilitar el botón de guardar2630 // Enable save button 2646 2631 const saveBtn = document.getElementById('save-branded-keywords-btn'); 2647 2632 if (saveBtn) { … … 2649 2634 } 2650 2635 2651 // Guardar automáticamente las keywords basadas en dominio2636 // Automatically save domain-based keywords 2652 2637 this.saveBrandedKeywords(); 2653 2654 console.log("Domain-based keywords set and saved");2655 2638 } else { 2656 2639 console.warn("No domain keywords generated or TomSelect not initialized"); -
seo-ai-audit-tool/trunk/changelog.txt
r3253527 r3257427 1 = 1.0.9 2025-03-17 2 3 Improved: Added branded keywords to backlinks order CSV export 4 Updated: Footer GUI update 5 Fixed: Security improvements 6 1 7 = 1.0.8 2025-03-10 2 8 -
seo-ai-audit-tool/trunk/includes/class-seo-audit-data-import.php
r3250723 r3257427 582 582 } 583 583 584 // Rest of the existing code...585 584 $content = mb_convert_encoding($content, 'UTF-8', mb_detect_encoding($content, 'UTF-8, ISO-8859-1', true)); 586 585 … … 588 587 $bom = pack('H*','EFBBBF'); 589 588 $content = preg_replace("/^$bom/", '', $content); 590 591 // Continue with existing CSV processing...592 589 593 590 $csv_data = array_map('str_getcsv', explode("\n", $content)); -
seo-ai-audit-tool/trunk/includes/class-seo-audit-db.php
r3250723 r3257427 1173 1173 1174 1174 public function seoaudp_handle_ahrefs_backlinks_csv_upload() { 1175 // ... existing validation code ...1176 1175 1177 1176 // Define column mappings -
seo-ai-audit-tool/trunk/includes/views/partials/footer-partial.php
r3216569 r3257427 40 40 <img src="<?php echo esc_url(SEOAUDP_PLUGIN_URL . 'assets/images/stb-logo.png'); ?>" alt="Smart Table Builder" title="Smart Table Builder"> 41 41 </a> 42 <a href=" #" target="_blank" class="seoaudp-footer-plugin-logos">43 <img src="<?php echo esc_url(SEOAUDP_PLUGIN_URL . 'assets/images/ hdh-logo.png'); ?>" alt="Help Desk Hero" title="Help Desk Hero">42 <a href="https://seo-ai-audit-tool.designful.ca/" target="_blank" class="seoaudp-footer-plugin-logos"> 43 <img src="<?php echo esc_url(SEOAUDP_PLUGIN_URL . 'assets/images/saat-logo.png'); ?>" alt="SEO Audit Tool" title="SEO Audit Tool"> 44 44 </a> 45 45 </div> -
seo-ai-audit-tool/trunk/readme.md
r3253527 r3257427 2 2 Contributors: Designful 3 3 Plugin URL: https://seo-ai-audit-tool.designful.ca/ 4 Version: 1.0. 84 Version: 1.0.9 5 5 Tags: seo audit, ai seo, conversion optimization, content analysis, search intent 6 6 Requires at least: 4.0 7 7 Tested up to: 6.7 8 Stable tag: 1.0. 88 Stable tag: 1.0.9 9 9 Requires PHP: 7.4 10 10 License: GPLv2 or later -
seo-ai-audit-tool/trunk/seo-ai-audit-tool.php
r3253527 r3257427 4 4 * Plugin URI: https://designful.ca/apps/seo-ai-audit-tool/ 5 5 * Description: A WordPress plugin to audit SEO elements of pages and perform AI-powered content analysis 6 * Version: 1.0. 86 * Version: 1.0.9 7 7 * Author: Designful 8 8 * License: GPL2 … … 20 20 define('SEOAUDP_PLUGIN_DIR', plugin_dir_path(__FILE__)); 21 21 define('SEOAUDP_PLUGIN_URL', plugin_dir_url(__FILE__)); 22 define('SEOAUDP_PLUGIN_VERSION', '1.0. 8');22 define('SEOAUDP_PLUGIN_VERSION', '1.0.9'); 23 23 define('SEOAUDP_PLUGIN_BETA_VERSION', false); 24 24 define('SEOAUDP_DB_VERSION', '1.6'); … … 434 434 seoaudp_debug_log($_POST); 435 435 436 try { 437 // ... existing code ... 438 } catch (Exception $e) { 439 seoaudp_debug_log('Error: ' . $e->getMessage()); 440 // ... existing error handling ... 441 } 442 } 436 }
Note: See TracChangeset
for help on using the changeset viewer.