PluginProbe
wpForo Forum / 3.2.0
wpForo Forum v3.2.0
3.2.1 3.2.0 3.1.7 3.1.6 3.1.5 3.1.4 3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.10 All 141 releases
← All changes | admin/assets/js/ai-features.js +193 -4 3.0.8 → 3.2.0 View file →
@@ -1372,8 +1372,14 @@
1372 1372
1373 1373 // Check for in-progress local indexing and auto-resume
1374 1374 this.checkLocalIndexingProgress();
1375 1375
1376 + // Check for in-progress cloud indexing auto-refresh (survives page reloads)
1377 + this.checkForumIndexingAutoRefresh();
1378 +
1379 + // Load indexing breakdown asynchronously (cached 1 day)
1380 + this.loadIndexingBreakdown();
1381 +
1376 1382 // Note: Polling is started from PHP inline script based on server-side $is_indexing status
1377 1383 // No need to start it here to avoid duplicate polling
1378 1384 },
1379 1385
@@ -1633,8 +1639,91 @@
1633 1639 }
1634 1640 });
1635 1641 },
1636 1642
1643 + /**
1644 + * Load indexing breakdown via AJAX (private/unapproved topic counts)
1645 + * Data is cached server-side for 1 day to avoid slow GROUP BY queries
1646 + */
1647 + loadIndexingBreakdown: function() {
1648 + const $container = $('#wpforo-ai-indexing-breakdown-container');
1649 + if (!$container.length) {
1650 + return;
1651 + }
1652 +
1653 + const self = this;
1654 + const loadingText = $container.data('loading-text') || 'Loading...';
1655 +
1656 + // Show small loading spinner
1657 + $container.html('<span class="wpforo-ai-breakdown-loading"><span class="dashicons dashicons-update wpforo-spin"></span> ' + loadingText + '</span>');
1658 +
1659 + $.ajax({
1660 + url: wpforoAIAdmin.ajaxUrl,
1661 + type: 'POST',
1662 + data: {
1663 + action: 'wpforo_ai_get_indexing_breakdown',
1664 + nonce: wpforoAIAdmin.nonce
1665 + },
1666 + success: function(response) {
1667 + if (response.success && response.data) {
1668 + self.renderIndexingBreakdown($container, response.data);
1669 + } else {
1670 + $container.empty();
1671 + }
1672 + },
1673 + error: function() {
1674 + $container.empty();
1675 + }
1676 + });
1677 + },
1678 +
1679 + /**
1680 + * Render the indexing breakdown HTML
1681 + */
1682 + renderIndexingBreakdown: function($container, data) {
1683 + const privateCount = parseInt(data.private, 10) || 0;
1684 + const unapprovedCount = parseInt(data.unapproved, 10) || 0;
1685 +
1686 + if (privateCount === 0 && unapprovedCount === 0) {
1687 + $container.empty();
1688 + return;
1689 + }
1690 +
1691 + const excludedCount = privateCount + unapprovedCount;
1692 + const excludedText = $container.data('excluded-text') || '%s topics are excluded from indexing';
1693 + const introText = $container.data('intro-text') || 'The following topics are automatically excluded from AI indexing:';
1694 + const privateText = $container.data('private-text') || 'private topics - these are only visible to their authors';
1695 + const unapprovedText = $container.data('unapproved-text') || 'unapproved topics - these will be indexed once approved by moderators';
1696 + const noteText = $container.data('note-text') || 'Private topics are never indexed to protect user privacy. Unapproved topics will be automatically indexed when approved.';
1697 +
1698 + let html = '<div class="wpforo-ai-indexing-breakdown">';
1699 + html += '<details class="wpforo-ai-breakdown-details">';
1700 + html += '<summary class="wpforo-ai-breakdown-summary">';
1701 + html += '<span class="dashicons dashicons-info-outline"></span>';
1702 + html += excludedText.replace('%s', '<strong>' + this.formatNumber(excludedCount) + '</strong>');
1703 + html += '<span class="dashicons dashicons-arrow-down-alt2 wpforo-ai-breakdown-arrow"></span>';
1704 + html += '</summary>';
1705 + html += '<div class="wpforo-ai-breakdown-content">';
1706 + html += '<p class="wpforo-ai-breakdown-intro">' + introText + '</p>';
1707 + html += '<ul class="wpforo-ai-breakdown-list">';
1708 +
1709 + if (privateCount > 0) {
1710 + html += '<li><span class="dashicons dashicons-lock"></span>';
1711 + html += '<strong>' + this.formatNumber(privateCount) + '</strong> ' + privateText + '</li>';
1712 + }
1713 +
1714 + if (unapprovedCount > 0) {
1715 + html += '<li><span class="dashicons dashicons-clock"></span>';
1716 + html += '<strong>' + this.formatNumber(unapprovedCount) + '</strong> ' + unapprovedText + '</li>';
1717 + }
1718 +
1719 + html += '</ul>';
1720 + html += '<p class="wpforo-ai-breakdown-note"><em>' + noteText + '</em></p>';
1721 + html += '</div></details></div>';
1722 +
1723 + $container.html(html);
1724 + },
1725 +
1637 1726 // WordPress Content Indexing Methods have been moved to
1638 1727 // ai-features-wp-indexing.js for the dedicated WordPress Indexing tab.
1639 1728 // See: WpForoWPIndexing in admin/assets/js/ai-features-wp-indexing.js
1640 1729
@@ -1993,8 +2082,11 @@
1993 2082 // Use localStorage to persist across page reloads
1994 2083 this.indexingStopping = true;
1995 2084 localStorage.setItem('wpforo_indexing_stopping', 'true');
1996 2085
2086 + // Clear auto-refresh flag so page doesn't keep reloading after stop
2087 + this.stopForumIndexingAutoRefresh();
2088 +
1997 2089 // Immediately update status to show "Stopping..."
1998 2090 const $statusElement = $('#rag-indexing-status');
1999 2091 if ($statusElement.length) {
2000 2092 $statusElement.text('Stopping...');
@@ -2066,16 +2158,18 @@
2066 2158 const originalHtml = $button.html();
2067 2159 $button.prop('disabled', true).html('<span class="dashicons dashicons-update"></span> Cleaning up...');
2068 2160
2069 2161 // Clear any browser-side stuck state first — regardless of AJAX
2070 - // outcome. This is the only client-side flag the plugin sets for
2162 + // outcome. These are the client-side flags the plugin sets for
2071 2163 // indexing (see handleStopIndexing / checkLocalIndexingProgress).
2072 2164 try {
2073 2165 localStorage.removeItem('wpforo_indexing_stopping');
2074 2166 localStorage.removeItem('wpforo_wp_indexing_auto_refresh');
2167 + localStorage.removeItem('wpforo_forum_indexing_auto_refresh');
2075 2168 } catch (err) { /* localStorage may be blocked in some contexts */ }
2076 2169 this.indexingStopping = false;
2077 2170 this.stopWPIndexingAutoRefresh();
2171 + this.stopForumIndexingAutoRefresh();
2078 2172
2079 2173 const self = this;
2080 2174 $.ajax({
2081 2175 url: ajaxurl,
@@ -2183,8 +2277,15 @@
2183 2277
2184 2278 // Add loading state to button
2185 2279 $button.addClass('loading').prop('disabled', true);
2186 2280
2281 + // Set localStorage flag for reindex actions so auto-refresh survives page reloads
2282 + if (action === 'reindex_all' || action === 'clear_and_reindex' || action === 'reindex_images') {
2283 + try {
2284 + localStorage.setItem('wpforo_forum_indexing_auto_refresh', '1');
2285 + } catch (e) { /* localStorage may be blocked */ }
2286 + }
2287 +
2187 2288 // Append form to body and submit
2188 2289 $('body').append($form);
2189 2290 $form.submit();
2190 2291 },
@@ -2436,8 +2537,95 @@
2436 2537 }
2437 2538 },
2438 2539
2439 2540 /**
2541 + * Start auto page refresh for forum content indexing (cloud mode).
2542 + * Sets localStorage flag so polling survives page reloads.
2543 + */
2544 + startForumIndexingAutoRefresh: function() {
2545 + try {
2546 + localStorage.setItem('wpforo_forum_indexing_auto_refresh', '1');
2547 + } catch (e) { /* localStorage may be blocked */ }
2548 +
2549 + console.log('Forum indexing: reloading page to start auto-refresh...');
2550 + window.location.hash = 'rag-status-section';
2551 + window.location.reload();
2552 + },
2553 +
2554 + /**
2555 + * Check on page load if forum indexing auto-refresh should continue.
2556 + * Polls API and schedules next reload if still indexing.
2557 + */
2558 + checkForumIndexingAutoRefresh: function() {
2559 + const self = this;
2560 +
2561 + let inAutoRefresh = false;
2562 + try {
2563 + inAutoRefresh = localStorage.getItem('wpforo_forum_indexing_auto_refresh') === '1';
2564 + } catch (e) { /* localStorage may be blocked */ }
2565 +
2566 + if (!inAutoRefresh) {
2567 + return;
2568 + }
2569 +
2570 + $.ajax({
2571 + url: ajaxurl,
2572 + type: 'POST',
2573 + data: {
2574 + action: 'wpforo_ai_get_rag_status',
2575 + _wpnonce: wpforoAIAdmin.nonce
2576 + },
2577 + success: function(response) {
2578 + if (response.success && response.data) {
2579 + const cronActive = response.data.pending_cron_jobs && response.data.pending_cron_jobs.is_actively_processing;
2580 + const hasPendingJobs = response.data.pending_cron_jobs && response.data.pending_cron_jobs.has_pending_jobs;
2581 + const isActivelyProcessing = response.data.is_indexing || cronActive || hasPendingJobs;
2582 +
2583 + if (isActivelyProcessing) {
2584 + console.log('Forum indexing in progress, will refresh in 20 seconds...');
2585 + self._forumAutoRefreshTimeout = setTimeout(function() {
2586 + window.location.hash = 'rag-status-section';
2587 + window.location.reload();
2588 + }, 20000);
2589 + } else {
2590 + console.log('Forum indexing complete, final reload');
2591 + self.stopForumIndexingAutoRefresh();
2592 + window.location.hash = 'rag-status-section';
2593 + window.location.reload();
2594 + }
2595 + }
2596 + },
2597 + error: function() {
2598 + self.stopForumIndexingAutoRefresh();
2599 + }
2600 + });
2601 + },
2602 +
2603 + /**
2604 + * Stop forum indexing auto page refresh and clear the flag.
2605 + */
2606 + stopForumIndexingAutoRefresh: function() {
2607 + try {
2608 + localStorage.removeItem('wpforo_forum_indexing_auto_refresh');
2609 + } catch (e) { /* localStorage may be blocked */ }
2610 +
2611 + if (this._forumAutoRefreshTimeout) {
2612 + clearTimeout(this._forumAutoRefreshTimeout);
2613 + this._forumAutoRefreshTimeout = null;
2614 + }
2615 + },
2616 +
2617 + /**
2618 + * Stop WP indexing auto refresh (stub for cleanup handler).
2619 + * The actual implementation lives in ai-features-wp-indexing.js.
2620 + */
2621 + stopWPIndexingAutoRefresh: function() {
2622 + try {
2623 + localStorage.removeItem('wpforo_wp_indexing_auto_refresh');
2624 + } catch (e) { /* localStorage may be blocked */ }
2625 + },
2626 +
2627 + /**
2440 2628 * Handle search test form submission
2441 2629 */
2442 2630 handleSearchTest: function(e) {
2443 2631 e.preventDefault();
@@ -2690,11 +2878,12 @@
2690 2878 success: function(response) {
2691 2879 if (response.success) {
2692 2880 console.log('Local indexing started:', response.data);
2693 2881
2694 - // Reload page — checkLocalIndexingProgress() will detect
2695 - // the queue on load and start the AJAX batch loop
2696 - window.location.reload();
2882 + // Use auto-refresh mechanism for consistent UX with cloud mode.
2883 + // Sets localStorage flag and reloads; checkForumIndexingAutoRefresh()
2884 + // will continue refreshing every 20s while indexing is in progress.
2885 + WpForoAI.startForumIndexingAutoRefresh();
2697 2886 } else {
2698 2887 const errorMsg = response.data && response.data.message
2699 2888 ? response.data.message
2700 2889 : 'Failed to start indexing';