Changeset 3486701
- Timestamp:
- 03/19/2026 05:07:02 PM (2 weeks ago)
- Location:
- intufind
- Files:
-
- 36 added
- 9 edited
-
tags/1.4.1 (added)
-
tags/1.4.1/admin (added)
-
tags/1.4.1/admin/class-intufind-admin.php (added)
-
tags/1.4.1/admin/class-intufind-components.php (added)
-
tags/1.4.1/admin/css (added)
-
tags/1.4.1/admin/css/intufind-admin.css (added)
-
tags/1.4.1/admin/js (added)
-
tags/1.4.1/admin/js/intufind-admin.js (added)
-
tags/1.4.1/admin/partials (added)
-
tags/1.4.1/admin/partials/chat-display.php (added)
-
tags/1.4.1/admin/partials/recommendations-display.php (added)
-
tags/1.4.1/admin/partials/search-display.php (added)
-
tags/1.4.1/admin/partials/settings-display.php (added)
-
tags/1.4.1/admin/partials/status-display.php (added)
-
tags/1.4.1/admin/partials/sync-display.php (added)
-
tags/1.4.1/includes (added)
-
tags/1.4.1/includes/class-intufind-api.php (added)
-
tags/1.4.1/includes/class-intufind-chat-widget.php (added)
-
tags/1.4.1/includes/class-intufind-content-extractor.php (added)
-
tags/1.4.1/includes/class-intufind-exclusions.php (added)
-
tags/1.4.1/includes/class-intufind-list-columns.php (added)
-
tags/1.4.1/includes/class-intufind-mcp.php (added)
-
tags/1.4.1/includes/class-intufind-plugin.php (added)
-
tags/1.4.1/includes/class-intufind-recommendations-override.php (added)
-
tags/1.4.1/includes/class-intufind-search-override.php (added)
-
tags/1.4.1/includes/class-intufind-search-widget.php (added)
-
tags/1.4.1/includes/class-intufind-shortcodes.php (added)
-
tags/1.4.1/includes/class-intufind-sync-status.php (added)
-
tags/1.4.1/includes/class-intufind-sync.php (added)
-
tags/1.4.1/includes/integrations (added)
-
tags/1.4.1/includes/integrations/class-intufind-facetwp.php (added)
-
tags/1.4.1/intufind.php (added)
-
tags/1.4.1/languages (added)
-
tags/1.4.1/languages/intufind.pot (added)
-
tags/1.4.1/readme.txt (added)
-
tags/1.4.1/uninstall.php (added)
-
trunk/admin/css/intufind-admin.css (modified) (5 diffs)
-
trunk/admin/js/intufind-admin.js (modified) (6 diffs)
-
trunk/admin/partials/search-display.php (modified) (1 diff)
-
trunk/includes/class-intufind-content-extractor.php (modified) (2 diffs)
-
trunk/includes/class-intufind-exclusions.php (modified) (1 diff)
-
trunk/includes/class-intufind-list-columns.php (modified) (21 diffs)
-
trunk/intufind.php (modified) (2 diffs)
-
trunk/languages/intufind.pot (modified) (5 diffs)
-
trunk/readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
intufind/trunk/admin/css/intufind-admin.css
r3463908 r3486701 1608 1608 } 1609 1609 1610 .wp-list-table th.column-intufind_ searchable,1611 .wp-list-table td.column-intufind_ searchable{1612 width: 40px !important;1610 .wp-list-table th.column-intufind_index_status, 1611 .wp-list-table td.column-intufind_index_status { 1612 width: 90px !important; 1613 1613 text-align: center; 1614 1614 } 1615 1615 1616 1616 .wp-list-table th.column-intufind_sync, 1617 .wp-list-table th.column-intufind_ searchable{1617 .wp-list-table th.column-intufind_index_status { 1618 1618 padding: 8px 4px; 1619 1619 } … … 1635 1635 } 1636 1636 1637 .wp-list-table th.column-intufind_ searchable{1637 .wp-list-table th.column-intufind_index_status { 1638 1638 cursor: help; 1639 1639 } … … 1659 1659 /* Align cell content with other columns (top) */ 1660 1660 .wp-list-table td.column-intufind_sync, 1661 .wp-list-table td.column-intufind_ searchable{1661 .wp-list-table td.column-intufind_index_status { 1662 1662 vertical-align: top; 1663 1663 padding-top: 12px; … … 1665 1665 padding-left: 4px; 1666 1666 padding-right: 4px; 1667 } 1668 1669 /* Index status select in list tables */ 1670 .intufind-index-status-select { 1671 font-size: 12px; 1672 padding: 2px 4px; 1673 min-width: 70px; 1674 max-width: 85px; 1675 height: auto; 1676 line-height: 1.4; 1667 1677 } 1668 1678 … … 2134 2144 /* Hide Intufind columns on small screens */ 2135 2145 .wp-list-table .column-intufind_sync, 2136 .wp-list-table .column-intufind_ searchable{2146 .wp-list-table .column-intufind_index_status { 2137 2147 display: none; 2138 2148 } -
intufind/trunk/admin/js/intufind-admin.js
r3461186 r3486701 1213 1213 /** 1214 1214 * Intufind List Columns module. 1215 * Handles sync/ searchabletoggles in post list tables.1215 * Handles sync/index-status toggles in post list tables. 1216 1216 */ 1217 1217 const IntufindListColumns = { … … 1228 1228 bindEvents: function () { 1229 1229 $(document).on('change', '.intufind-sync-toggle', this.handleSyncToggle.bind(this)); 1230 $(document).on('change', '.intufind- searchable-toggle', this.handleSearchableToggle.bind(this));1230 $(document).on('change', '.intufind-index-status-select', this.handleIndexStatusChange.bind(this)); 1231 1231 }, 1232 1232 … … 1254 1254 success: (response) => { 1255 1255 if (response.success) { 1256 // Find the searchable column container (by column class, not by checkbox). 1257 const $searchableContainer = $row.find('.column-intufind_searchable .intufind-col-toggle'); 1256 const $indexStatusContainer = $row.find('.column-intufind_index_status .intufind-col-toggle'); 1258 1257 1259 1258 if (response.data.synced) { … … 1277 1276 } 1278 1277 1279 // Re-enable searchable toggle if it was disabled. 1280 if ($searchableContainer.length && $searchableContainer.hasClass('intufind-col-toggle--disabled') && response.data.syncStatus === 'success') { 1281 // Restore searchable toggle (default to checked/searchable for published posts). 1282 const searchableNonce = response.data.searchableNonce || ''; 1283 $searchableContainer 1278 // Re-enable index status select if it was disabled. 1279 if ($indexStatusContainer.length && $indexStatusContainer.hasClass('intufind-col-toggle--disabled') && response.data.syncStatus === 'success') { 1280 const indexStatusNonce = response.data.indexStatusNonce || ''; 1281 $indexStatusContainer 1284 1282 .removeClass('intufind-col-toggle--disabled') 1285 1283 .removeAttr('title') 1286 1284 .html(` 1287 <label class="intufind-mini-toggle"> 1288 <input type="checkbox" class="intufind-searchable-toggle" data-post-id="${postId}" data-nonce="${searchableNonce}" checked /> 1289 <span class="intufind-mini-toggle__slider"></span> 1290 </label> 1285 <select class="intufind-index-status-select" data-post-id="${postId}" data-nonce="${indexStatusNonce}"> 1286 <option value="active" selected>Active</option> 1287 <option value="hidden">Hidden</option> 1288 <option value="disabled">Disabled</option> 1289 </select> 1291 1290 `); 1292 1291 } 1293 1292 } else { 1294 // Sync disabled - remove status and disable searchable.1293 // Sync disabled - remove status and disable index status. 1295 1294 $container.find('.intufind-col-status').remove(); 1296 if ($ searchableContainer.length) {1297 $ searchableContainer1295 if ($indexStatusContainer.length) { 1296 $indexStatusContainer 1298 1297 .html('<span class="intufind-col-dash">—</span>') 1299 1298 .addClass('intufind-col-toggle--disabled') … … 1319 1318 1320 1319 /** 1321 * Handle searchable toggle change. 1322 */ 1323 handleSearchableToggle: (e) => { 1324 const $checkbox = $(e.currentTarget); 1325 const postId = $checkbox.data('post-id'); 1326 const nonce = $checkbox.data('nonce'); 1327 const $container = $checkbox.closest('.intufind-col-toggle'); 1328 1320 * Handle index status select change. 1321 */ 1322 handleIndexStatusChange: (e) => { 1323 const $select = $(e.currentTarget); 1324 const postId = $select.data('post-id'); 1325 const nonce = $select.data('nonce'); 1326 const newStatus = $select.val(); 1327 const previousStatus = $select.data('previous-value') || $select.find('option:first').val(); 1328 const $container = $select.closest('.intufind-col-toggle'); 1329 1330 $select.data('previous-value', newStatus); 1329 1331 $container.addClass('is-loading'); 1330 $ checkbox.prop('disabled', true);1332 $select.prop('disabled', true); 1331 1333 1332 1334 $.ajax({ … … 1334 1336 type: 'POST', 1335 1337 data: { 1336 action: 'intufind_toggle_ searchable',1338 action: 'intufind_toggle_index_status', 1337 1339 post_id: postId, 1338 1340 nonce: nonce, 1341 status: newStatus, 1339 1342 }, 1340 1343 success: (response) => { 1341 1344 if (!response.success) { 1342 $ checkbox.prop('checked', !$checkbox.prop('checked'));1343 alert(response.data.message || 'Error toggling searchable.');1345 $select.val(previousStatus); 1346 alert(response.data.message || 'Error updating index status.'); 1344 1347 } 1345 1348 }, 1346 1349 error: () => { 1347 $ checkbox.prop('checked', !$checkbox.prop('checked'));1350 $select.val(previousStatus); 1348 1351 alert('Request failed.'); 1349 1352 }, 1350 1353 complete: () => { 1351 1354 $container.removeClass('is-loading'); 1352 $ checkbox.prop('disabled', false);1355 $select.prop('disabled', false); 1353 1356 }, 1354 1357 }); -
intufind/trunk/admin/partials/search-display.php
r3463908 r3486701 390 390 391 391 <div class="intufind-info-section"> 392 <h4><?php esc_html_e( 'S earchable Content', 'intufind' ); ?></h4>392 <h4><?php esc_html_e( 'Status', 'intufind' ); ?></h4> 393 393 <p> 394 <?php esc_html_e( 'Only synced content marked as "Searchable" appears in search results. Use the Knowledge page and post list columns to control what\'s searchable.', 'intufind' ); ?>394 <?php esc_html_e( 'Only synced content with an "Active" index status appears in search results. Use the Knowledge page and post list columns to control visibility.', 'intufind' ); ?> 395 395 </p> 396 396 </div> -
intufind/trunk/includes/class-intufind-content-extractor.php
r3484551 r3486701 117 117 'tags' => $tags, 118 118 'featuredImage' => $image_url, 119 ' searchable' => Intufind_List_Columns::is_searchable( $post_id ),119 'indexStatus' => Intufind_List_Columns::get_index_status( $post_id ), 120 120 'source' => 'wordpress', 121 121 ); … … 289 289 // Visibility. 290 290 'catalogVisibility' => $product->get_catalog_visibility(), 291 ' searchable' => Intufind_List_Columns::is_searchable( $product_id ) && 'hidden' !== $product->get_catalog_visibility(),291 'indexStatus' => 'hidden' === $product->get_catalog_visibility() ? 'hidden' : Intufind_List_Columns::get_index_status( $product_id ), 292 292 293 293 // Source tracking. -
intufind/trunk/includes/class-intufind-exclusions.php
r3461186 r3486701 432 432 } 433 433 434 // Private posts can be synced (they'll be marked as non-searchable/chatbot only).434 // Private posts can be synced (they'll default to 'hidden' index status/chatbot only). 435 435 if ( 'private' === $status ) { 436 436 return true; -
intufind/trunk/includes/class-intufind-list-columns.php
r3461186 r3486701 3 3 * List Columns functionality. 4 4 * 5 * Adds sync and searchablecolumns to WordPress post list tables5 * Adds sync and index status columns to WordPress post list tables 6 6 * for granular control over AI indexing. 7 7 * … … 23 23 */ 24 24 const META_EXCLUDE_SYNC = '_intufind_exclude_sync'; 25 const META_ SEARCHABLE = '_intufind_searchable';25 const META_INDEX_STATUS = '_intufind_index_status'; 26 26 27 27 /** … … 80 80 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) ); 81 81 add_action( 'wp_ajax_intufind_toggle_sync', array( $this, 'ajax_toggle_sync' ) ); 82 add_action( 'wp_ajax_intufind_toggle_ searchable', array( $this, 'ajax_toggle_searchable' ) );82 add_action( 'wp_ajax_intufind_toggle_index_status', array( $this, 'ajax_toggle_index_status' ) ); 83 83 } 84 84 … … 165 165 // Column headers with WordPress-style icon markup and tooltips. 166 166 $sync_title = __( 'Intufind: AI Sync', 'intufind' ); 167 $ searchable_title = __( 'Intufind: Searchable', 'intufind' );167 $index_status_title = __( 'Intufind: Status', 'intufind' ); 168 168 169 169 $sync_header = sprintf( … … 172 172 esc_html( $sync_title ) 173 173 ); 174 $ searchable_header = sprintf(174 $index_status_header = sprintf( 175 175 '<span class="intufind-col-header dashicons dashicons-visibility" aria-hidden="true" title="%s"></span><span class="screen-reader-text">%s</span>', 176 esc_attr( $ searchable_title ),177 esc_html( $ searchable_title )176 esc_attr( $index_status_title ), 177 esc_html( $index_status_title ) 178 178 ); 179 179 … … 181 181 // Insert before date column. 182 182 if ( 'date' === $key ) { 183 $new_columns['intufind_sync'] = $sync_header;184 $new_columns['intufind_ searchable'] = $searchable_header;183 $new_columns['intufind_sync'] = $sync_header; 184 $new_columns['intufind_index_status'] = $index_status_header; 185 185 } 186 186 $new_columns[ $key ] = $label; … … 189 189 // If date doesn't exist, add at end. 190 190 if ( ! isset( $new_columns['intufind_sync'] ) ) { 191 $new_columns['intufind_sync'] = $sync_header;192 $new_columns['intufind_ searchable'] = $searchable_header;191 $new_columns['intufind_sync'] = $sync_header; 192 $new_columns['intufind_index_status'] = $index_status_header; 193 193 } 194 194 … … 205 205 if ( 'intufind_sync' === $column ) { 206 206 $this->render_sync_column( $post_id ); 207 } elseif ( 'intufind_ searchable' === $column ) {208 $this->render_ searchable_column( $post_id );207 } elseif ( 'intufind_index_status' === $column ) { 208 $this->render_index_status_column( $post_id ); 209 209 } 210 210 } … … 304 304 305 305 /** 306 * Render searchablecolumn.306 * Render index status column. 307 307 * 308 308 * @param int $post_id Post ID. 309 309 */ 310 private function render_ searchable_column( $post_id ) {310 private function render_index_status_column( $post_id ) { 311 311 $post = get_post( $post_id ); 312 312 if ( ! $post ) { … … 316 316 // Not a syncable status (drafts, etc.). 317 317 if ( ! in_array( $post->post_status, array( 'publish', 'private' ), true ) ) { 318 $this->render_disabled_toggle( ' searchable', __( 'Publish first', 'intufind' ) );319 return; 320 } 321 322 // System-excluded posts can't be synced, so searchabledoesn't apply.318 $this->render_disabled_toggle( 'index_status', __( 'Publish first', 'intufind' ) ); 319 return; 320 } 321 322 // System-excluded posts can't be synced, so index status doesn't apply. 323 323 if ( $this->is_system_excluded( $post_id, $post ) ) { 324 $this->render_disabled_toggle( ' searchable', __( 'Cannot be synced', 'intufind' ) );325 return; 326 } 327 328 // Check if synced - searchableonly applies to synced content.324 $this->render_disabled_toggle( 'index_status', __( 'Cannot be synced', 'intufind' ) ); 325 return; 326 } 327 328 // Check if synced - index status only applies to synced content. 329 329 if ( ! self::is_synced( $post_id ) ) { 330 $this->render_disabled_toggle( 'searchable', __( 'Enable sync first', 'intufind' ) ); 331 return; 332 } 333 334 // Get searchable setting. 335 // Default: published = searchable, private = not searchable (chatbot only). 336 $searchable_meta = get_post_meta( $post_id, self::META_SEARCHABLE, true ); 337 if ( '' === $searchable_meta ) { 338 // No explicit setting - use defaults. 339 $is_searchable = 'publish' === $post->post_status; 340 } else { 341 $is_searchable = 'no' !== $searchable_meta; 342 } 343 344 $nonce = wp_create_nonce( 'intufind_toggle_searchable_' . $post_id ); 330 $this->render_disabled_toggle( 'index_status', __( 'Enable sync first', 'intufind' ) ); 331 return; 332 } 333 334 $current_status = self::get_index_status( $post_id ); 335 $nonce = wp_create_nonce( 'intufind_toggle_index_status_' . $post_id ); 336 337 $statuses = array( 338 'active' => __( 'Active', 'intufind' ), 339 'hidden' => __( 'Hidden', 'intufind' ), 340 'disabled' => __( 'Disabled', 'intufind' ), 341 ); 345 342 346 343 ?> 347 344 <div class="intufind-col-toggle" data-post-id="<?php echo esc_attr( $post_id ); ?>"> 348 <label class="intufind-mini-toggle"> 349 <input 350 type="checkbox" 351 class="intufind-searchable-toggle" 352 data-post-id="<?php echo esc_attr( $post_id ); ?>" 353 data-nonce="<?php echo esc_attr( $nonce ); ?>" 354 <?php checked( $is_searchable ); ?> 355 /> 356 <span class="intufind-mini-toggle__slider"></span> 357 </label> 345 <select 346 class="intufind-index-status-select" 347 data-post-id="<?php echo esc_attr( $post_id ); ?>" 348 data-nonce="<?php echo esc_attr( $nonce ); ?>" 349 > 350 <?php foreach ( $statuses as $value => $label ) : ?> 351 <option value="<?php echo esc_attr( $value ); ?>" <?php selected( $current_status, $value ); ?>> 352 <?php echo esc_html( $label ); ?> 353 </option> 354 <?php endforeach; ?> 355 </select> 358 356 </div> 359 357 <?php … … 440 438 */ 441 439 public function add_bulk_actions( $actions ) { 442 $actions['intufind_enable_sync'] = __( 'Enable AI Sync', 'intufind' ); 443 $actions['intufind_disable_sync'] = __( 'Disable AI Sync', 'intufind' ); 444 $actions['intufind_make_searchable'] = __( 'Make Searchable', 'intufind' ); 445 $actions['intufind_hide_search'] = __( 'Hide from Search', 'intufind' ); 440 $actions['intufind_enable_sync'] = __( 'Enable AI Sync', 'intufind' ); 441 $actions['intufind_disable_sync'] = __( 'Disable AI Sync', 'intufind' ); 442 $actions['intufind_index_active'] = __( 'Set Index: Active', 'intufind' ); 443 $actions['intufind_index_hidden'] = __( 'Set Index: Hidden', 'intufind' ); 444 $actions['intufind_index_disabled'] = __( 'Set Index: Disabled', 'intufind' ); 446 445 447 446 return $actions; … … 460 459 'intufind_enable_sync', 461 460 'intufind_disable_sync', 462 'intufind_make_searchable', 463 'intufind_hide_search', 461 'intufind_index_active', 462 'intufind_index_hidden', 463 'intufind_index_disabled', 464 464 ); 465 465 … … 483 483 484 484 if ( $document ) { 485 $document[' searchable'] = self::is_searchable( $post_id );485 $document['indexStatus'] = self::get_index_status( $post_id ); 486 486 487 487 if ( 'product' === $post_type ) { … … 519 519 break; 520 520 521 case 'intufind_make_searchable': 522 update_post_meta( $post_id, self::META_SEARCHABLE, 'yes' ); 523 $count++; 524 break; 525 526 case 'intufind_hide_search': 527 update_post_meta( $post_id, self::META_SEARCHABLE, 'no' ); 521 case 'intufind_index_active': 522 case 'intufind_index_hidden': 523 case 'intufind_index_disabled': 524 $status_map = array( 525 'intufind_index_active' => 'active', 526 'intufind_index_hidden' => 'hidden', 527 'intufind_index_disabled' => 'disabled', 528 ); 529 $new_idx_status = $status_map[ $action ]; 530 531 update_post_meta( $post_id, self::META_INDEX_STATUS, $new_idx_status ); 532 533 if ( self::is_synced( $post_id ) ) { 534 $post = get_post( $post_id ); 535 $post_type = $post ? $post->post_type : 'post'; 536 $document = $this->extractor->extract( $post_id, $post_type ); 537 538 if ( $document ) { 539 $document['indexStatus'] = $new_idx_status; 540 541 if ( 'product' === $post_type ) { 542 $upsert_result = $this->api->upsert_products( array( $document ) ); 543 } else { 544 $upsert_result = $this->api->upsert_posts( array( $document ) ); 545 } 546 547 if ( ! is_wp_error( $upsert_result ) ) { 548 $this->status->mark_synced( $post_id, '', 'manual' ); 549 } else { 550 $this->status->mark_error( $post_id, $upsert_result->get_error_message() ); 551 } 552 } 553 } 554 528 555 $count++; 529 556 break; … … 601 628 $count 602 629 ), 603 'intufind_ make_searchable'=> sprintf(630 'intufind_index_active' => sprintf( 604 631 /* translators: %d: number of posts */ 605 _n( '%d item made searchable.', '%d items made searchable.', $count, 'intufind' ),632 _n( '%d item set to active.', '%d items set to active.', $count, 'intufind' ), 606 633 $count 607 634 ), 608 'intufind_ hide_search'=> sprintf(635 'intufind_index_hidden' => sprintf( 609 636 /* translators: %d: number of posts */ 610 _n( '%d item hidden from search.', '%d items hidden from search.', $count, 'intufind' ), 637 _n( '%d item set to hidden.', '%d items set to hidden.', $count, 'intufind' ), 638 $count 639 ), 640 'intufind_index_disabled' => sprintf( 641 /* translators: %d: number of posts */ 642 _n( '%d item set to disabled.', '%d items set to disabled.', $count, 'intufind' ), 611 643 $count 612 644 ), … … 696 728 697 729 if ( $document ) { 698 $document[' searchable'] = self::is_searchable( $post_id );730 $document['indexStatus'] = self::get_index_status( $post_id ); 699 731 700 732 if ( 'product' === $post_type ) { … … 719 751 ); 720 752 721 // Include searchable nonce when enabling sync so JS can restore the toggle.753 // Include index status nonce when enabling sync so JS can restore the select. 722 754 if ( $is_synced ) { 723 $response[' searchableNonce'] = wp_create_nonce( 'intufind_toggle_searchable_' . $post_id );755 $response['indexStatusNonce'] = wp_create_nonce( 'intufind_toggle_index_status_' . $post_id ); 724 756 } 725 757 … … 728 760 729 761 /** 730 * AJAX handler for toggling searchable. 731 */ 732 public function ajax_toggle_searchable() { 733 $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0; 734 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : ''; 762 * AJAX handler for setting index status. 763 */ 764 public function ajax_toggle_index_status() { 765 $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0; 766 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : ''; 767 $new_status = isset( $_POST['status'] ) ? sanitize_text_field( wp_unslash( $_POST['status'] ) ) : ''; 735 768 736 769 if ( ! $post_id ) { … … 738 771 } 739 772 740 if ( ! wp_verify_nonce( $nonce, 'intufind_toggle_ searchable_' . $post_id ) ) {773 if ( ! wp_verify_nonce( $nonce, 'intufind_toggle_index_status_' . $post_id ) ) { 741 774 wp_send_json_error( array( 'message' => __( 'Session expired. Please refresh the page and try again.', 'intufind' ) ) ); 742 775 } … … 746 779 } 747 780 748 // Get current effective state and toggle to opposite. 749 $is_currently_searchable = self::is_searchable( $post_id ); 750 751 if ( $is_currently_searchable ) { 752 // Was searchable, now hide. 753 update_post_meta( $post_id, self::META_SEARCHABLE, 'no' ); 754 $is_searchable = false; 755 } else { 756 // Was hidden, now searchable. 757 update_post_meta( $post_id, self::META_SEARCHABLE, 'yes' ); 758 $is_searchable = true; 759 } 781 $valid_statuses = array( 'active', 'hidden', 'disabled' ); 782 if ( ! in_array( $new_status, $valid_statuses, true ) ) { 783 wp_send_json_error( array( 'message' => __( 'Invalid status.', 'intufind' ) ) ); 784 } 785 786 update_post_meta( $post_id, self::META_INDEX_STATUS, $new_status ); 787 788 $post = get_post( $post_id ); 789 $post_type = $post ? $post->post_type : 'post'; 790 $document = $this->extractor->extract( $post_id, $post_type ); 791 792 $sync_success = false; 793 if ( $document ) { 794 $document['indexStatus'] = $new_status; 795 796 if ( 'product' === $post_type ) { 797 $result = $this->api->upsert_products( array( $document ) ); 798 } else { 799 $result = $this->api->upsert_posts( array( $document ) ); 800 } 801 802 if ( ! is_wp_error( $result ) ) { 803 $this->status->mark_synced( $post_id, '', 'manual' ); 804 $sync_success = true; 805 } else { 806 $this->status->mark_error( $post_id, $result->get_error_message() ); 807 } 808 } 809 810 $labels = array( 811 'active' => __( 'Index status: Active', 'intufind' ), 812 'hidden' => __( 'Index status: Hidden', 'intufind' ), 813 'disabled' => __( 'Index status: Disabled', 'intufind' ), 814 ); 760 815 761 816 wp_send_json_success( 762 817 array( 763 'searchable' => $is_searchable, 764 'message' => $is_searchable ? __( 'Now searchable', 'intufind' ) : __( 'Hidden from search', 'intufind' ), 818 'indexStatus' => $new_status, 819 'syncStatus' => $sync_success ? 'success' : 'error', 820 'message' => $labels[ $new_status ], 765 821 ) 766 822 ); … … 806 862 807 863 /** 808 * Check if a post is searchable.809 * 810 * Defaults: published = searchable, private = not searchable (chatbot only).864 * Get the index status of a post. 865 * 866 * Defaults: published = 'active', private = 'hidden'. 811 867 * User can override either default. 812 868 * 813 869 * @param int $post_id Post ID. 814 * @return bool Whether searchable. 815 */ 816 public static function is_searchable( $post_id ) { 817 // Must be synced to be searchable. 870 * @return string Index status: 'active', 'hidden', or 'disabled'. 871 */ 872 public static function get_index_status( $post_id ) { 818 873 if ( ! self::is_synced( $post_id ) ) { 819 return false;874 return 'disabled'; 820 875 } 821 876 822 877 $post = get_post( $post_id ); 823 878 if ( ! $post ) { 824 return false; 825 } 826 827 $searchable_meta = get_post_meta( $post_id, self::META_SEARCHABLE, true ); 828 829 // Explicit setting overrides defaults. 830 if ( 'no' === $searchable_meta ) { 831 return false; 832 } 833 if ( 'yes' === $searchable_meta ) { 834 return true; 879 return 'disabled'; 880 } 881 882 $status_meta = get_post_meta( $post_id, self::META_INDEX_STATUS, true ); 883 884 $valid_statuses = array( 'active', 'hidden', 'disabled' ); 885 if ( in_array( $status_meta, $valid_statuses, true ) ) { 886 return $status_meta; 835 887 } 836 888 837 889 // Default based on post status. 838 return 'publish' === $post->post_status ;890 return 'publish' === $post->post_status ? 'active' : 'hidden'; 839 891 } 840 892 } -
intufind/trunk/intufind.php
r3484551 r3486701 4 4 * Plugin URI: https://intufind.com/integrations/wordpress 5 5 * Description: AI-powered search and chat for WordPress. Syncs your content to the cloud for semantic search, intelligent recommendations, and conversational AI. 6 * Version: 1.4. 06 * Version: 1.4.1 7 7 * Requires at least: 6.0 8 8 * Requires PHP: 8.0 … … 26 26 * Plugin constants. 27 27 */ 28 define( 'INTUFIND_VERSION', '1.4. 0' );28 define( 'INTUFIND_VERSION', '1.4.1' ); 29 29 define( 'INTUFIND_PLUGIN_FILE', __FILE__ ); 30 30 define( 'INTUFIND_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); -
intufind/trunk/languages/intufind.pot
r3461186 r3486701 695 695 696 696 #: admin/partials/search-display.php:274 697 msgid "S earchable Content"697 msgid "Status" 698 698 msgstr "" 699 699 700 700 #: admin/partials/search-display.php:276 701 msgid "Only synced content marked as \"Searchable\" appears in search results. Use the Knowledge page and post list columns to control what's searchable."701 msgid "Only synced content with an \"Active\" index status appears in search results. Use the Knowledge page and post list columns to control each item's index status." 702 702 msgstr "" 703 703 … … 1274 1274 1275 1275 #: includes/class-intufind-list-columns.php:167 1276 msgid "Intufind: S earchable"1276 msgid "Intufind: Status" 1277 1277 msgstr "" 1278 1278 … … 1320 1320 msgstr "" 1321 1321 1322 #: includes/class-intufind-list-columns.php:442 1323 msgid "Set Index: Active" 1324 msgstr "" 1325 1326 #: includes/class-intufind-list-columns.php:443 1327 msgid "Set Index: Hidden" 1328 msgstr "" 1329 1322 1330 #: includes/class-intufind-list-columns.php:444 1323 msgid "Make Searchable" 1324 msgstr "" 1325 1326 #: includes/class-intufind-list-columns.php:445 1327 msgid "Hide from Search" 1331 msgid "Set Index: Disabled" 1328 1332 msgstr "" 1329 1333 … … 1345 1349 1346 1350 #. translators: %d: number of posts 1347 #: includes/class-intufind-list-columns.php: 5321348 #, php-format 1349 msgid "%d item made searchable."1350 msgid_plural "%d items made searchable."1351 #: includes/class-intufind-list-columns.php:610 1352 #, php-format 1353 msgid "%d item set to active." 1354 msgid_plural "%d items set to active." 1351 1355 msgstr[0] "" 1352 1356 msgstr[1] "" 1353 1357 1354 1358 #. translators: %d: number of posts 1355 #: includes/class-intufind-list-columns.php:537 1356 #, php-format 1357 msgid "%d item hidden from search." 1358 msgid_plural "%d items hidden from search." 1359 #: includes/class-intufind-list-columns.php:615 1360 #, php-format 1361 msgid "%d item set to hidden." 1362 msgid_plural "%d items set to hidden." 1363 msgstr[0] "" 1364 msgstr[1] "" 1365 1366 #. translators: %d: number of posts 1367 #: includes/class-intufind-list-columns.php:620 1368 #, php-format 1369 msgid "%d item set to disabled." 1370 msgid_plural "%d items set to disabled." 1359 1371 msgstr[0] "" 1360 1372 msgstr[1] "" … … 1378 1390 msgstr "" 1379 1391 1380 #: includes/class-intufind-list-columns.php:675 1381 msgid "Now searchable" 1382 msgstr "" 1383 1384 #: includes/class-intufind-list-columns.php:675 1385 msgid "Hidden from search" 1392 #: includes/class-intufind-list-columns.php:767 1393 msgid "Index status: Active" 1394 msgstr "" 1395 1396 #: includes/class-intufind-list-columns.php:768 1397 msgid "Index status: Hidden" 1398 msgstr "" 1399 1400 #: includes/class-intufind-list-columns.php:769 1401 msgid "Index status: Disabled" 1386 1402 msgstr "" 1387 1403 -
intufind/trunk/readme.txt
r3484551 r3486701 5 5 Tested up to: 6.9 6 6 Requires PHP: 8.0 7 Stable tag: 1.4. 07 Stable tag: 1.4.1 8 8 WC tested up to: 9.6 9 9 License: GPLv2 or later … … 215 215 == Changelog == 216 216 217 = 1.4.1 = 218 * Added per-document index status control (active, hidden, disabled) with a new Status column in the Knowledge list 219 * Index status is synced to the cloud on every content update and bulk sync 220 * Hidden catalog visibility products are automatically set to hidden index status 221 217 222 = 1.4.0 = 218 223 * Content sync now preserves document structure (headings, lists, bold, links) as markdown for better AI search and chat quality … … 304 309 == Upgrade Notice == 305 310 311 = 1.4.1 = 312 Adds per-document index status controls. You can now set individual posts and products to active, hidden, or disabled directly from the WordPress admin list. 313 306 314 = 1.4.0 = 307 315 Content sync now converts HTML to markdown, preserving headings, lists, and formatting for significantly better AI search and chat responses. Re-sync recommended after updating.
Note: See TracChangeset
for help on using the changeset viewer.