PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 3.2.24
MxChat – AI Chatbot & Content Generation for WordPress v3.2.24
3.2.25 3.2.24 3.2.23 3.2.22 3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 All 156 releases
← All changes | js/knowledge-processing.js +157 -19 3.2.11 → 3.2.24 View file →
@@ -1086,12 +1086,11 @@
1086 1086 $(this).remove();
1087 1087 // Update entry count displays (header and sidebar)
1088 1088 var $countSpan = $('#mxchat-entry-count');
1089 1089 if ($countSpan.length) {
1090 - var currentText = $countSpan.text();
1091 - var match = currentText.match(/\((\d+)\)/);
1092 - if (match) {
1093 - var newCount = Math.max(0, parseInt(match[1]) - 1);
1090 + var currentCount = readEntryCount($countSpan);
1091 + if (!isNaN(currentCount)) {
1092 + var newCount = Math.max(0, currentCount - 1);
1094 1093 updateEntryCount(newCount);
1095 1094 }
1096 1095 }
1097 1096 });
@@ -1150,12 +1149,11 @@
1150 1149 $(this).remove();
1151 1150 // Update entry count displays (header and sidebar)
1152 1151 var $countSpan = $('#mxchat-entry-count');
1153 1152 if ($countSpan.length) {
1154 - var currentText = $countSpan.text();
1155 - var match = currentText.match(/\((\d+)\)/);
1156 - if (match) {
1157 - var newCount = Math.max(0, parseInt(match[1]) - 1);
1153 + var currentCount = readEntryCount($countSpan);
1154 + if (!isNaN(currentCount)) {
1155 + var newCount = Math.max(0, currentCount - 1);
1158 1156 updateEntryCount(newCount);
1159 1157 }
1160 1158 }
1161 1159 });
@@ -1351,12 +1349,11 @@
1351 1349 // Update entry count displays (header and sidebar)
1352 1350 if (successCount > 0) {
1353 1351 var $countSpan = $('#mxchat-entry-count');
1354 1352 if ($countSpan.length) {
1355 - var currentText = $countSpan.text();
1356 - var match = currentText.match(/\((\d+)\)/);
1357 - if (match) {
1358 - var newCount = Math.max(0, parseInt(match[1]) - successCount);
1353 + var currentCount = readEntryCount($countSpan);
1354 + if (!isNaN(currentCount)) {
1355 + var newCount = Math.max(0, currentCount - successCount);
1359 1356 updateEntryCount(newCount);
1360 1357 }
1361 1358 }
1362 1359 }
@@ -1529,9 +1526,9 @@
1529 1526 }
1530 1527
1531 1528 // Update the count display
1532 1529 if (response.data.total_count !== undefined) {
1533 - updateEntryCount(response.data.total_count);
1530 + updateEntryCount(response.data.total_count, response.data.count_unit);
1534 1531 }
1535 1532
1536 1533 // Show success feedback
1537 1534 showNotification('success', 'Entries refreshed successfully!');
@@ -1744,9 +1741,9 @@
1744 1741 success: function(response) {
1745 1742 if (response.success && response.data) {
1746 1743 // Update count
1747 1744 if (response.data.total_count !== undefined) {
1748 - updateEntryCount(response.data.total_count);
1745 + updateEntryCount(response.data.total_count, response.data.count_unit);
1749 1746 }
1750 1747
1751 1748 // Handle Pinecone data source differently
1752 1749 if (response.data.data_source === 'pinecone') {
@@ -1819,14 +1816,32 @@
1819 1816 }
1820 1817 });
1821 1818 }
1822 1819
1823 - // Update the entry count display
1824 - function updateEntryCount(count) {
1820 + // Read the heading's count from its data attribute, not from the text: the
1821 + // text now carries a thousands separator and a unit ("(1,240 vectors)") on
1822 + // the Pinecone cursor path (plan dd6e10).
1823 + function readEntryCount($countSpan) {
1824 + var stored = parseInt($countSpan.attr('data-count'), 10);
1825 + if (!isNaN(stored)) {
1826 + return stored;
1827 + }
1828 + var match = $countSpan.text().match(/\(([\d,]+)/);
1829 + return match ? parseInt(match[1].replace(/,/g, ''), 10) : NaN;
1830 + }
1831 +
1832 + // Update the entry count display. `unit` is 'vectors' on the Pinecone
1833 + // cursor path and '' otherwise; omitted = keep whatever the span carries.
1834 + function updateEntryCount(count, unit) {
1825 1835 // Update main table count
1826 1836 const $countSpan = $('#mxchat-entry-count');
1827 1837 if ($countSpan.length) {
1828 - $countSpan.text('(' + count + ')');
1838 + if (unit === undefined) {
1839 + unit = $countSpan.attr('data-unit') || '';
1840 + }
1841 + var shown = Number(count).toLocaleString();
1842 + $countSpan.attr('data-count', count).attr('data-unit', unit);
1843 + $countSpan.text('(' + shown + (unit === 'vectors' ? ' vectors' : '') + ')');
1829 1844
1830 1845 // Flash animation to indicate update
1831 1846 $countSpan.addClass('mxchat-count-updated');
1832 1847 setTimeout(function() {
@@ -1893,9 +1908,9 @@
1893 1908 }
1894 1909
1895 1910 // Update count display
1896 1911 if (response.data.total_count !== undefined) {
1897 - updateEntryCount(response.data.total_count);
1912 + updateEntryCount(response.data.total_count, response.data.count_unit);
1898 1913 }
1899 1914 }
1900 1915 },
1901 1916 error: function(xhr, status, error) {
@@ -1929,9 +1944,9 @@
1929 1944 const sourceHtml = entry.has_link
1930 1945 ? '<a href="' + entry.source_url + '" target="_blank" style="color: var(--mxch-primary); text-decoration: none;"><span class="dashicons dashicons-external" style="font-size: 14px;"></span> View</a>'
1931 1946 : '<span style="color: var(--mxch-text-muted);">Manual</span>';
1932 1947
1933 - const deleteUrl = mxchatAdmin.admin_url + 'admin-post.php?action=mxchat_delete_prompt&id=' + entry.id + '&_wpnonce=' + entry.delete_nonce;
1948 + const deleteUrl = mxchatAdmin.admin_url + 'admin-post.php?action=mxchat_delete_prompt&id=' + entry.id + '&bot_id=' + encodeURIComponent(mxchatAdmin.bot_id || 'default') + '&_wpnonce=' + entry.delete_nonce;
1934 1949
1935 1950 // Check if content needs expand button (content longer than preview)
1936 1951 const needsExpand = entry.content_length > entry.preview_length;
1937 1952
@@ -2271,6 +2286,129 @@
2271 2286 $(document).on('DOMNodeInserted', function(e) {
2272 2287 if ($(e.target).hasClass('notice') && $(e.target).hasClass('is-dismissible')) {
2273 2288 setTimeout(initDismissibleNotices, 10);
2274 2289 }
2290 + });
2291 +
2292 + // ========================================
2293 + // CUSTOM META-KEY DISCOVERY PICKER (plan-mxchat-20260709-fe8e4e)
2294 + // Mirror the ACF picker's discover-and-click UX for non-ACF post meta: scan
2295 + // published content for meta keys, render clickable chips, and append chosen
2296 + // keys into the existing whitelist textarea (its autosave then persists them).
2297 + // ========================================
2298 + (function() {
2299 + var $scanBtn = $('#mxchat-scan-meta-btn');
2300 + if (!$scanBtn.length) { return; }
2301 +
2302 + var $results = $('#mxchat-meta-scan-results');
2303 + var $textarea = $('#mxchat_custom_meta_whitelist');
2304 + var $internal = $('#mxchat-scan-internal');
2305 + var $label = $scanBtn.find('.mxchat-scan-label');
2306 + var defaultLabel = $label.text();
2307 +
2308 + function currentKeys() {
2309 + return ($textarea.val() || '')
2310 + .split('\n')
2311 + .map(function(k) { return k.trim(); })
2312 + .filter(function(k) { return k.length; });
2313 + }
2314 +
2315 + function addKey(key) {
2316 + var keys = currentKeys();
2317 + if (keys.indexOf(key) !== -1) { return false; }
2318 + keys.push(key);
2319 + $textarea.val(keys.join('\n'));
2320 + // Fire the existing autosave (bound on 'change' in mxchat-admin.js).
2321 + $textarea.trigger('change');
2322 + return true;
2323 + }
2324 +
2325 + function escapeHtml(s) {
2326 + return String(s).replace(/[&<>"']/g, function(c) {
2327 + return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
2328 + });
2329 + }
2330 +
2331 + function humanize(key) {
2332 + var h = key.replace(/^_+/, '').replace(/[_-]+/g, ' ').trim();
2333 + return h.length ? h.charAt(0).toUpperCase() + h.slice(1) : key;
2334 + }
2335 +
2336 + function renderChips(keys) {
2337 + if (!keys || !keys.length) {
2338 + $results.html('<p class="mxchat-meta-scan-empty">' +
2339 + 'No custom meta keys found on your published content. Try enabling internal keys, or add keys manually below.' +
2340 + '</p>');
2341 + return;
2342 + }
2343 + var existing = currentKeys();
2344 + var html = '<div class="mxchat-meta-chip-grid">';
2345 + keys.forEach(function(item) {
2346 + var already = existing.indexOf(item.key) !== -1;
2347 + html += '<button type="button" class="mxchat-meta-chip' + (already ? ' is-added' : '') +
2348 + '" data-key="' + escapeHtml(item.key) + '"' + (already ? ' aria-pressed="true"' : '') + '>' +
2349 + '<span class="mxchat-meta-chip-main">' +
2350 + '<span class="mxchat-meta-chip-name">' + escapeHtml(humanize(item.key)) + '</span>' +
2351 + '<span class="mxchat-meta-chip-key">' + escapeHtml(item.key) + '</span>' +
2352 + '</span>' +
2353 + '<span class="mxchat-meta-chip-meta">on ' + item.count + ' post' + (item.count === 1 ? '' : 's') +
2354 + (item.sample ? ' · e.g. ' + escapeHtml(item.sample) : '') + '</span>' +
2355 + '<span class="mxchat-meta-chip-tick">' + (already ? '✓ Added' : '+ Add') + '</span>' +
2356 + '</button>';
2357 + });
2358 + html += '</div>';
2359 + $results.html(html);
2360 + }
2361 +
2362 + $scanBtn.on('click', function() {
2363 + var nonce = $scanBtn.data('nonce') ||
2364 + (window.mxchatAdmin && mxchatAdmin.settings_nonce) || '';
2365 + var ajaxUrl = (window.mxchatAdmin && (mxchatAdmin.ajax_url || mxchatAdmin.ajaxurl)) ||
2366 + window.ajaxurl || '/wp-admin/admin-ajax.php';
2367 +
2368 + $scanBtn.prop('disabled', true);
2369 + $label.text('Scanning…');
2370 + $results.html('<p class="mxchat-meta-scan-loading">Scanning your content for meta keys…</p>');
2371 +
2372 + $.post(ajaxUrl, {
2373 + action: 'mxchat_scan_custom_meta_keys',
2374 + _ajax_nonce: nonce,
2375 + include_internal: $internal.is(':checked') ? '1' : '0'
2376 + }).done(function(resp) {
2377 + if (resp && resp.success && resp.data && resp.data.keys) {
2378 + renderChips(resp.data.keys);
2379 + } else {
2380 + var msg = (resp && resp.data && resp.data.message) ? resp.data.message : 'Scan failed. Please try again.';
2381 + $results.html('<p class="mxchat-meta-scan-empty">' + escapeHtml(msg) + '</p>');
2382 + }
2383 + }).fail(function() {
2384 + $results.html('<p class="mxchat-meta-scan-empty">Scan request failed. Please try again.</p>');
2385 + }).always(function() {
2386 + $scanBtn.prop('disabled', false);
2387 + $label.text(defaultLabel);
2388 + });
2389 + });
2390 +
2391 + // Chip click -> add the raw key to the whitelist textarea (dedup) + autosave.
2392 + $results.on('click', '.mxchat-meta-chip', function() {
2393 + var $chip = $(this);
2394 + if ($chip.hasClass('is-added')) { return; }
2395 + var key = String($chip.data('key'));
2396 + if (addKey(key)) {
2397 + $chip.addClass('is-added').attr('aria-pressed', 'true');
2398 + $chip.find('.mxchat-meta-chip-tick').text('✓ Added');
2399 + }
2400 + });
2401 + })();
2402 +
2403 + // ========================================
2404 + // VIDEO CARDS — threshold follows the master switch (plan f52492)
2405 + // ========================================
2406 + // Presentation only. The server gate does NOT consult the threshold when
2407 + // the switch is off, so hiding the field never changes behavior — it just
2408 + // stops the page offering a number that is currently inert. Mirrors the
2409 + // YouTube import form's own show/hide idiom on this same page. Autosave is
2410 + // untouched: both fields keep their own change handler in mxchat-admin.js.
2411 + $('#mxchat_video_embed_enabled').on('change', function() {
2412 + $('#mxchat-video-embed-threshold-field').toggle($(this).is(':checked'));
2275 2413 });
2276 2414 });