Changeset 3448236
- Timestamp:
- 01/27/2026 10:13:22 PM (2 months ago)
- Location:
- ask-my-content/trunk
- Files:
-
- 9 edited
-
ask-my-content.php (modified) (3 diffs)
-
assets/js/amc-admin-init.js (modified) (1 diff)
-
build/ask-my-content/block.json (modified) (1 diff)
-
build/blocks-manifest.php (modified) (1 diff)
-
includes/activate.php (modified) (2 diffs)
-
includes/cli.php (modified) (7 diffs)
-
includes/settings_embed.php (modified) (2 diffs)
-
readme.txt (modified) (5 diffs)
-
src/ask-my-content/block.json (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
ask-my-content/trunk/ask-my-content.php
r3445867 r3448236 4 4 * Plugin Name: Ask My Content - AI Q&A Chatbot 5 5 * Description: AI-powered Q&A chatbot, allowing users to ask questions and receive answers sourced from the site’s own posts and pages. 6 * Version: 0.8. 06 * Version: 0.8.1 7 7 * Requires at least: 5.8 8 8 * Requires PHP: 7.4 … … 92 92 $settings_path = $base_dir . 'assets/js/askmyco-settings.js'; 93 93 94 $core_ver = file_exists($core_path) ? filemtime($core_path) : '0.8. 0';95 $frontend_ver = file_exists($frontend_path) ? filemtime($frontend_path) : '0.8. 0';96 $admin_init_ver = file_exists($admin_init_path) ? filemtime($admin_init_path) : '0.8. 0';97 $style_ver = file_exists($style_path) ? filemtime($style_path) : '0.8. 0';98 $settings_ver = file_exists($settings_path) ? filemtime($settings_path) : '0.8. 0';94 $core_ver = file_exists($core_path) ? filemtime($core_path) : '0.8.1'; 95 $frontend_ver = file_exists($frontend_path) ? filemtime($frontend_path) : '0.8.1'; 96 $admin_init_ver = file_exists($admin_init_path) ? filemtime($admin_init_path) : '0.8.1'; 97 $style_ver = file_exists($style_path) ? filemtime($style_path) : '0.8.1'; 98 $settings_ver = file_exists($settings_path) ? filemtime($settings_path) : '0.8.1'; 99 99 100 100 if (! wp_script_is($core_handle, 'registered')) { … … 209 209 210 210 $floating_path = plugin_dir_path(__FILE__) . 'assets/js/amc-floating.js'; 211 $floating_ver = file_exists($floating_path) ? filemtime($floating_path) : '0.8. 0';211 $floating_ver = file_exists($floating_path) ? filemtime($floating_path) : '0.8.1'; 212 212 213 213 wp_enqueue_script( -
ask-my-content/trunk/assets/js/amc-admin-init.js
r3445867 r3448236 49 49 })(); 50 50 51 // AMC admin counters: fetch and update UI, no inline scripts needed52 (function () {53 function amcUpdateCountersDisplay(d) {54 if (!d) return;55 var i = document.getElementById('amc-indexed-count');56 var ci = document.getElementById('amc-chat-in-count');57 var co = document.getElementById('amc-chat-out-count');58 if (typeof d.embed_count === 'number' && i) i.textContent = d.embed_count;59 if (typeof d.chat_in_count === 'number' && ci) ci.textContent = d.chat_in_count;60 if (typeof d.chat_out_count === 'number' && co) co.textContent = d.chat_out_count;61 }62 63 async function amcFetchCounters() {64 var statusEl = document.getElementById('amc-counters-status');65 if (statusEl) statusEl.textContent = 'Loading…';66 try {67 var ajaxUrl = (window.amcAdminChat && window.amcAdminChat.ajaxUrl) || (window.ajaxurl) || '/wp-admin/admin-ajax.php';68 var body = new URLSearchParams();69 body.set('action', 'askmyco_get_counters');70 if (window.amcAdminChat && window.amcAdminChat.nonce) {71 body.set('security', window.amcAdminChat.nonce);72 }73 const res = await fetch(ajaxUrl, {74 method: 'POST',75 credentials: 'same-origin',76 headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },77 body: body.toString()78 });79 var data = await res.json();80 if (data && data.success) {81 amcUpdateCountersDisplay(data.data);82 if (statusEl) statusEl.textContent = '';83 } else {84 if (statusEl) {85 var msg = (data && data.data && data.data.message) ? data.data.message : (data && data.message) ? data.message : 'Failed to load';86 statusEl.textContent = msg;87 }88 }89 } catch (err) {90 if (statusEl) statusEl.textContent = (err && err.message) ? err.message : 'Error';91 }92 }93 94 function amcScheduleFinishedCheck() {95 setTimeout(function () {96 var s = document.getElementById('amc-status');97 var text = (s && s.textContent) ? s.textContent.toLowerCase() : '';98 if (text.includes('finished indexing')) amcFetchCounters();99 }, 1500);100 }101 102 // Wire button103 var btn = document.getElementById('amc-refresh-counters');104 if (btn) btn.addEventListener('click', amcFetchCounters);105 106 // Initial load107 if (document.readyState === 'loading') {108 document.addEventListener('DOMContentLoaded', function () {109 amcFetchCounters();110 amcScheduleFinishedCheck();111 });112 } else {113 amcFetchCounters();114 amcScheduleFinishedCheck();115 }116 117 // Refresh after chat answer event118 window.addEventListener('amc-chat-answered', function () { amcFetchCounters(); });119 })();120 121 51 // Enable Save Changes only when settings fields actually change 122 52 (function () { -
ask-my-content/trunk/build/ask-my-content/block.json
r3445867 r3448236 3 3 "apiVersion": 3, 4 4 "name": "amc/ask-my-content", 5 "version": "0.8. 0",5 "version": "0.8.1", 6 6 "title": "Ask My Content", 7 7 "category": "widgets", -
ask-my-content/trunk/build/blocks-manifest.php
r3445867 r3448236 6 6 'apiVersion' => 3, 7 7 'name' => 'amc/ask-my-content', 8 'version' => '0.8. 0',8 'version' => '0.8.1', 9 9 'title' => 'Ask My Content', 10 10 'category' => 'widgets', -
ask-my-content/trunk/includes/activate.php
r3440656 r3448236 73 73 askmyco_debug_log('Activate site_url: ' . $site_url, 'debug'); 74 74 75 // Capture the best-available email for the activating admin/user. 76 $activator_email = ''; 77 if (function_exists('wp_get_current_user')) { 78 $user = wp_get_current_user(); 79 if ($user instanceof WP_User && $user->exists()) { 80 $activator_email = sanitize_email($user->user_email); 81 } 82 } 83 if ($activator_email === '') { 84 $activator_email = sanitize_email((string) get_option('admin_email', '')); 85 } 75 $activator_email = askmyco_get_admin_email(); 86 76 87 77 // Fire-and-forget notification to backend about activation 88 78 if (function_exists('askmyco_send_content_to_backend')) { 89 79 // Endpoint will resolve to <base>/_api_/plugin; payload: { siteId, data: { domain, action } } 90 askmyco_debug_log(91 'Activation payload: domain=' . $domain . ' action=activated email=' . $activator_email,92 'debug'93 );94 80 askmyco_send_content_to_backend([ 95 81 'domain' => $domain, … … 106 92 askmyco_debug_log('Activation finished', 'info'); 107 93 } 94 95 /** 96 * Get the best-available admin email (current user if available, otherwise site admin email). 97 * 98 * @return string Sanitized email address. 99 */ 100 function askmyco_get_admin_email(): string 101 { 102 $email = ''; 103 if (function_exists('wp_get_current_user')) { 104 $user = wp_get_current_user(); 105 if ($user instanceof WP_User && $user->exists()) { 106 $email = sanitize_email($user->user_email); 107 } 108 } 109 if ($email === '') { 110 $email = sanitize_email((string) get_option('admin_email', '')); 111 } 112 return $email; 113 } 114 115 /** 116 * Handle plugin update notification via upgrader_process_complete hook. 117 * 118 * @param WP_Upgrader $upgrader Upgrader instance. 119 * @param array $options Array of bulk update data. 120 */ 121 function askmyco_on_plugin_update($upgrader, $options) 122 { 123 // Debug: log every call to see if hook fires and with what params 124 askmyco_debug_log('upgrader_process_complete hook fired', 'info'); 125 askmyco_debug_log('options: ' . wp_json_encode($options), 'info'); 126 127 // Only handle plugin updates 128 if (!isset($options['type']) || $options['type'] !== 'plugin') { 129 askmyco_debug_log('Skipping: type is not plugin', 'debug'); 130 return; 131 } 132 // Handle both 'update' action and 'install' action (zip uploads are reported as install) 133 $action = isset($options['action']) ? $options['action'] : ''; 134 if ($action !== 'update' && $action !== 'install') { 135 askmyco_debug_log('Skipping: action is not update or install', 'debug'); 136 return; 137 } 138 // Check if our plugin is in the list of updated plugins 139 $our_plugin = 'ask-my-content/ask-my-content.php'; 140 $plugins = []; 141 if (isset($options['plugins']) && is_array($options['plugins'])) { 142 $plugins = $options['plugins']; 143 } elseif (isset($options['plugin'])) { 144 $plugins = [$options['plugin']]; 145 } 146 // For install action, check the upgrader result for plugin info 147 if (empty($plugins) && $action === 'install' && $upgrader instanceof Plugin_Upgrader) { 148 $result = $upgrader->result; 149 if (is_array($result) && isset($result['destination_name'])) { 150 $dest = $result['destination_name']; 151 askmyco_debug_log('Install destination_name: ' . $dest, 'debug'); 152 if ($dest === 'ask-my-content') { 153 $plugins = [$our_plugin]; 154 } 155 } 156 } 157 askmyco_debug_log('Looking for ' . $our_plugin . ' in: ' . wp_json_encode($plugins), 'debug'); 158 159 if (!in_array($our_plugin, $plugins, true)) { 160 askmyco_debug_log('Skipping: our plugin not in list', 'debug'); 161 return; 162 } 163 // For 'install' action, this could be a fresh install or an overwrite (update via zip) 164 // We only want to send 'updated' for overwrites, not fresh installs 165 // Check if we had a stored UUID before (indicates plugin was previously installed) 166 $site_uuid = get_option('askmyco_site_uuid'); 167 if ($action === 'install' && !$site_uuid) { 168 askmyco_debug_log('Skipping: fresh install (no existing UUID)', 'debug'); 169 return; 170 } 171 askmyco_debug_log('Plugin update detected via ' . $action . ' action', 'info'); 172 173 $parsed = wp_parse_url(home_url()); 174 $domain = isset($parsed['host']) ? $parsed['host'] : ''; 175 $admin_email = askmyco_get_admin_email(); 176 177 // Fire-and-forget notification to backend about update 178 if (function_exists('askmyco_send_content_to_backend')) { 179 askmyco_send_content_to_backend([ 180 'domain' => $domain, 181 'action' => 'updated', 182 'email' => $admin_email, 183 ], 'plugin', 'non_blocking'); 184 askmyco_debug_log( 185 'Update ping sent (non-blocking) domain=' . $domain . ' action=updated email=' . $admin_email, 186 'info' 187 ); 188 } else { 189 askmyco_debug_log('askmyco_send_content_to_backend not available during update', 'warn'); 190 } 191 } 192 add_action('upgrader_process_complete', 'askmyco_on_plugin_update', 10, 2); -
ask-my-content/trunk/includes/cli.php
r3384523 r3448236 62 62 * : Include posts in addition to pages. 63 63 * 64 * [--pages-only] 65 * : Index pages only (exclude posts). Overrides any previously saved setting. 66 * 64 67 * [--force] 65 * : Steal an existing lock and run anyway .68 * : Steal an existing lock and run anyway (use with caution if another process may be running). 66 69 * 67 70 * ## EXAMPLES 68 71 * wp amc index 69 72 * wp amc index --include-posts 73 * wp amc index --pages-only 70 74 * wp amc index --force 71 75 */ … … 73 77 { 74 78 $include_posts = isset($assoc_args['include-posts']); 79 $pages_only = isset($assoc_args['pages-only']); 75 80 $force = isset($assoc_args['force']); 76 81 82 // Explicit control: --include-posts or --pages-only set the option for this run only 83 if ($include_posts && $pages_only) { 84 WP_CLI::error('Cannot use both --include-posts and --pages-only.'); 85 } 77 86 if ($include_posts) { 78 87 update_option('askmyco_include_posts', '1'); 88 } elseif ($pages_only) { 89 update_option('askmyco_include_posts', '0'); 79 90 } 91 // If neither flag given, use existing saved setting 80 92 81 93 // Handle existing lock 82 94 if (get_option('askmyco_indexing_lock')) { 83 95 if ($force) { 84 WP_CLI::warning('Existing lock found. Forcing takeover .');96 WP_CLI::warning('Existing lock found. Forcing takeover (ensure no other process is running).'); 85 97 delete_option('askmyco_indexing_lock'); 86 98 } else { … … 88 100 } 89 101 } 102 askmyco_db_clear_stop_requested(); 90 103 91 askmyco_db_clear_stop_requested();92 104 update_option('askmyco_embedding_status', 'starting (CLI)…'); 93 105 … … 96 108 WP_CLI::error('Indexing function not available.'); 97 109 } 98 99 WP_CLI::log( 'Starting indexing…'); // phpcs:ignore110 $posts_mode = get_option('askmyco_include_posts', '0') === '1' ? 'pages+posts' : 'pages only'; 111 WP_CLI::log("Starting indexing ({$posts_mode})…"); // phpcs:ignore 100 112 $start = microtime(true); 101 113 askmyco_cron_index_content(); … … 103 115 104 116 $status = get_option('askmyco_embedding_status', 'unknown'); 105 WP_CLI::success("Done ({$elapsed}s). Status: $status"); // phpcs:ignore 117 $status_lower = strtolower($status); 118 119 // Determine exit status based on result 120 if (strpos($status_lower, 'error') !== false || strpos($status_lower, 'failed') !== false) { 121 WP_CLI::error("Indexing failed ({$elapsed}s). Status: $status"); 122 } elseif (strpos($status_lower, 'stopped') !== false || strpos($status_lower, 'stopping') !== false) { 123 WP_CLI::warning("Indexing stopped ({$elapsed}s). Status: $status"); // phpcs:ignore 124 } else { 125 WP_CLI::success("Done ({$elapsed}s). Status: $status"); // phpcs:ignore 126 } 106 127 } 107 108 128 /** 109 129 * Show current indexing status and counters. … … 143 163 WP_CLI::log(json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); // phpcs:ignore 144 164 } 145 146 165 /** 147 166 * Request a stop for a running indexing process. … … 157 176 } 158 177 } 159 160 178 WP_CLI::add_command('amc', 'ASKMYCO_CLI_Command'); // phpcs:ignore 161 179 } -
ask-my-content/trunk/includes/settings_embed.php
r3414721 r3448236 6 6 7 7 // Settings Embed UI 8 9 // Normalize stale indexing state: if is_indexing='1' but no lock and no scheduled cron, reset to idle 10 $askmyco_is_indexing_flag = get_option('askmyco_is_indexing', '0') === '1'; 11 $askmyco_has_lock = (bool) get_option('askmyco_indexing_lock'); 12 $askmyco_has_scheduled = (bool) wp_next_scheduled(ASKMYCO_CRON_HOOK); 13 14 if ($askmyco_is_indexing_flag && !$askmyco_has_lock && !$askmyco_has_scheduled) { 15 // Indexing was marked as running but nothing is actually happening - reset 16 update_option('askmyco_is_indexing', '0'); 17 askmyco_db_clear_stop_requested(); 18 $askmyco_current_status = get_option('askmyco_embedding_status', ''); 19 // Only update status if it looks stale (scheduled/stopping but never ran) 20 if (in_array($askmyco_current_status, ['scheduled…', 'stopping…', 'stopping...'], true)) { 21 update_option('askmyco_embedding_status', 'reset (stale state detected)'); 22 } 23 } 8 24 9 25 // Fetch counts and stats … … 45 61 // schedule shortly to reduce immediate race with other requests 46 62 wp_schedule_single_event(time() + 1, ASKMYCO_CRON_HOOK); 63 } // Encourage immediate cron execution (helps with aggressive caching plugins) 64 if (function_exists('spawn_cron')) { 65 spawn_cron(); 47 66 } 48 67 } -
ask-my-content/trunk/readme.txt
r3445867 r3448236 5 5 Requires PHP: 7.4 6 6 Tested up to: 6.9 7 Stable tag: 0.8. 07 Stable tag: 0.8.1 8 8 License: GPL-2.0-or-later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 28 28 1. After activating the plugin, go to **Dashboard → Ask My Content** and press “Start Indexing” (or run `wp amc index`) to send your site content to the backend. Indexing must be completed before the chat can answer questions. 29 29 2. Enable the floating launcher to show the chat site-wide; or add the **Ask My Content** block to an existing or new page (or place the `[ask_my_content]` shortcode) and publish/update the page so the chat interface has a front-end location. 30 3. Content is converted into embeddings (vector representations). 31 4. When a visitor asks a question, the chatbot retrieves the most relevant content snippets from your indexed pages. 32 5. OpenAI generates an answer based on that content. 30 3. When a visitor asks a question, the chatbot retrieves the most relevant content snippets from your indexed pages. 31 4. OpenAI generates an answer based on that content. 33 32 34 33 After you edit content, rerun indexing from **Dashboard → Ask My Content** or via `wp amc index` to push the latest changes. Deleted posts are sent to the backend automatically when they are trashed or removed. … … 48 47 49 48 == Frequently Asked Questions == 49 50 = Why is indexing stuck? = 51 The admin "Start Indexing" button schedules a background task via WordPress cron. If your site uses aggressive caching (e.g., LiteSpeed Cache, WP Super Cache), cached pages may bypass cron triggers, causing indexing to appear stuck at "scheduled…" or "stopping…". 52 53 **Solutions:** 54 1. Refresh the settings page — stale state is auto-detected and reset. 55 2. Use `wp amc index` from the command line — it runs synchronously and doesn't depend on cron. See **Command Line Usage** below. 50 56 51 57 = Does this plugin use my OpenAI API key? = … … 73 79 * Use the settings page for a guided UI, manual start/stop buttons, and real-time counters inside the WordPress dashboard. 74 80 * Use `wp amc` when you need automation (cron jobs, SSH sessions, CI) or want to run indexing without opening a browser. Available commands include: 75 * `wp amc index [--include-posts] [-- force]`81 * `wp amc index [--include-posts] [--pages-only] [--force]` 76 82 * `wp amc status` 77 83 * `wp amc stop` 84 85 Run `wp help amc index` for full option descriptions: 86 87 ` 88 NAME 89 90 wp amc index 91 92 DESCRIPTION 93 94 Run indexing immediately (pages always, posts optional). 95 96 OPTIONS 97 98 [--include-posts] 99 Include posts in addition to pages. 100 101 [--pages-only] 102 Index pages only (exclude posts). Overrides any previously saved setting. 103 104 [--force] 105 Steal an existing lock and run anyway (use with caution if another process may be running). 106 107 EXAMPLES 108 109 wp amc index 110 wp amc index --include-posts 111 wp amc index --pages-only 112 wp amc index --force 113 ` 78 114 79 115 = Installing WP-CLI = … … 115 151 == Changelog == 116 152 153 = 0.8.1 = 154 Amended WP-CLI command suite (`wp amc`) 155 117 156 = 0.8.0 = 118 157 Added optional floating chat launcher that can appear site-wide. -
ask-my-content/trunk/src/ask-my-content/block.json
r3445867 r3448236 3 3 "apiVersion": 3, 4 4 "name": "amc/ask-my-content", 5 "version": "0.8. 0",5 "version": "0.8.1", 6 6 "title": "Ask My Content", 7 7 "category": "widgets",
Note: See TracChangeset
for help on using the changeset viewer.