Changeset 3482407
- Timestamp:
- 03/14/2026 08:30:57 AM (3 weeks ago)
- Location:
- ai-discovery-files
- Files:
-
- 45 added
- 13 edited
-
tags/1.2.0/admin/class-admin.php (modified) (3 diffs)
-
tags/1.2.0/admin/css/admin.css (modified) (4 diffs)
-
tags/1.2.0/admin/js/admin.js (modified) (1 diff)
-
tags/1.2.0/admin/views/tab-identity.php (modified) (5 diffs)
-
tags/1.2.0/includes/class-data-collector.php (modified) (1 diff)
-
tags/1.2.1 (added)
-
tags/1.2.1/LICENSE (added)
-
tags/1.2.1/admin (added)
-
tags/1.2.1/admin/class-admin.php (added)
-
tags/1.2.1/admin/class-settings.php (added)
-
tags/1.2.1/admin/css (added)
-
tags/1.2.1/admin/css/admin.css (added)
-
tags/1.2.1/admin/js (added)
-
tags/1.2.1/admin/js/admin.js (added)
-
tags/1.2.1/admin/views (added)
-
tags/1.2.1/admin/views/partials (added)
-
tags/1.2.1/admin/views/partials/directory-cta.php (added)
-
tags/1.2.1/admin/views/partials/review-banner.php (added)
-
tags/1.2.1/admin/views/partials/tier-progress.php (added)
-
tags/1.2.1/admin/views/partials/verify-modal.php (added)
-
tags/1.2.1/admin/views/settings-page.php (added)
-
tags/1.2.1/admin/views/tab-advanced.php (added)
-
tags/1.2.1/admin/views/tab-content.php (added)
-
tags/1.2.1/admin/views/tab-identity.php (added)
-
tags/1.2.1/admin/views/tab-permissions.php (added)
-
tags/1.2.1/admin/views/tab-preview.php (added)
-
tags/1.2.1/admin/views/tab-status.php (added)
-
tags/1.2.1/ai-discovery-files.php (added)
-
tags/1.2.1/includes (added)
-
tags/1.2.1/includes/class-data-collector.php (added)
-
tags/1.2.1/includes/class-generator.php (added)
-
tags/1.2.1/includes/class-plugin.php (added)
-
tags/1.2.1/includes/class-server.php (added)
-
tags/1.2.1/includes/class-validator.php (added)
-
tags/1.2.1/languages (added)
-
tags/1.2.1/languages/ai-discovery-files.pot (added)
-
tags/1.2.1/languages/index.php (added)
-
tags/1.2.1/readme.txt (added)
-
tags/1.2.1/templates (added)
-
tags/1.2.1/templates/ai-json.php (added)
-
tags/1.2.1/templates/ai-txt.php (added)
-
tags/1.2.1/templates/brand-txt.php (added)
-
tags/1.2.1/templates/developer-ai-txt.php (added)
-
tags/1.2.1/templates/faq-ai-txt.php (added)
-
tags/1.2.1/templates/identity-json.php (added)
-
tags/1.2.1/templates/llm-txt.php (added)
-
tags/1.2.1/templates/llms-html.php (added)
-
tags/1.2.1/templates/llms-txt.php (added)
-
tags/1.2.1/templates/robots-ai-txt.php (added)
-
tags/1.2.1/uninstall.php (added)
-
trunk/admin/class-admin.php (modified) (3 diffs)
-
trunk/admin/css/admin.css (modified) (4 diffs)
-
trunk/admin/js/admin.js (modified) (1 diff)
-
trunk/admin/views/partials/review-banner.php (modified) (1 diff)
-
trunk/admin/views/tab-identity.php (modified) (5 diffs)
-
trunk/ai-discovery-files.php (modified) (2 diffs)
-
trunk/includes/class-data-collector.php (modified) (1 diff)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
ai-discovery-files/tags/1.2.0/admin/class-admin.php
r3475304 r3482407 38 38 add_action( 'wp_ajax_aidf_save_verify_code', array( __CLASS__, 'ajax_save_verify_code' ) ); 39 39 add_action( 'wp_ajax_aidf_dismiss_review', array( __CLASS__, 'ajax_dismiss_review' ) ); 40 add_action( 'wp_ajax_aidf_search_pages', array( __CLASS__, 'ajax_search_pages' ) ); 40 41 add_action( 'admin_notices', array( __CLASS__, 'maybe_show_welcome_notice' ) ); 41 42 add_action( 'admin_notices', array( __CLASS__, 'maybe_show_conflict_notice' ) ); … … 118 119 'verifyFileActive' => __( 'Verification file is live at', 'ai-discovery-files' ), 119 120 'verifyFileInactive' => __( 'No verification code set. Enter your code above to activate.', 'ai-discovery-files' ), 121 'searchPages' => __( 'Search pages…', 'ai-discovery-files' ), 122 'searching' => __( 'Searching…', 'ai-discovery-files' ), 123 'noResults' => __( 'No pages found', 'ai-discovery-files' ), 124 'typeToSearch' => __( 'Type to search…', 'ai-discovery-files' ), 120 125 ), 121 126 ) … … 599 604 wp_send_json_success(); 600 605 } 606 607 /** 608 * AJAX handler: search pages for the page picker autocomplete. 609 * 610 * @return void 611 */ 612 public static function ajax_search_pages() { 613 check_ajax_referer( 'aidf_admin_nonce', 'nonce' ); 614 615 if ( ! current_user_can( 'manage_options' ) ) { 616 wp_send_json_error( __( 'Permission denied.', 'ai-discovery-files' ) ); 617 } 618 619 $search = isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : ''; 620 621 if ( strlen( $search ) < 2 ) { 622 wp_send_json_success( array() ); 623 } 624 625 // Determine post types — defaults to page, but caller can request additional types. 626 $raw_types = isset( $_POST['post_types'] ) ? sanitize_text_field( wp_unslash( $_POST['post_types'] ) ) : 'page'; 627 $allowed = array( 'page', 'product' ); 628 $post_types = array_intersect( 629 array_map( 'trim', explode( ',', $raw_types ) ), 630 $allowed 631 ); 632 633 if ( empty( $post_types ) ) { 634 $post_types = array( 'page' ); 635 } 636 637 $query = new WP_Query( 638 array( 639 's' => $search, 640 'post_type' => $post_types, 641 'post_status' => 'publish', 642 'posts_per_page' => 20, 643 'orderby' => 'relevance', 644 'no_found_rows' => true, 645 ) 646 ); 647 648 $results = array(); 649 foreach ( $query->posts as $post ) { 650 $results[] = array( 651 'id' => $post->ID, 652 'title' => $post->post_title, 653 'url' => get_permalink( $post ), 654 'type' => $post->post_type, 655 ); 656 } 657 658 wp_send_json_success( $results ); 659 } 601 660 } -
ai-discovery-files/tags/1.2.0/admin/css/admin.css
r3475304 r3482407 580 580 581 581 /* -------------------------------------------------------- 582 9c. Page Picker (URL + dropdown)582 9c. Page Search Autocomplete (URL + AJAX search) 583 583 -------------------------------------------------------- */ 584 584 .aidf-url-with-picker { … … 594 594 } 595 595 596 .aidf-page- picker{597 display: block;598 width: auto;596 .aidf-page-search { 597 position: relative; 598 flex-shrink: 0; 599 599 min-width: 160px; 600 600 max-width: 220px; 601 padding: var(--aidf-sp-2) 36px var(--aidf-sp-2) var(--aidf-sp-3); 601 } 602 603 .aidf-page-search__input { 604 display: block; 605 width: 100%; 606 padding: var(--aidf-sp-2) var(--aidf-sp-3); 602 607 font-family: var(--aidf-font); 603 608 font-size: var(--aidf-text-sm); 604 color: var(--aidf-text -secondary);609 color: var(--aidf-text); 605 610 background: var(--aidf-white); 606 611 border: 1px solid var(--aidf-border); … … 608 613 transition: border-color var(--aidf-transition), box-shadow var(--aidf-transition); 609 614 line-height: 1.5; 610 appearance: none; 611 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M6 8L1 3h10z' fill='%238b8fa3'/%3E%3C/svg%3E"); 612 background-repeat: no-repeat; 613 background-position: right 12px center; 614 cursor: pointer; 615 flex-shrink: 0; 616 } 617 618 .aidf-page-picker:focus { 615 box-sizing: border-box; 616 } 617 618 .aidf-page-search__input:focus { 619 619 outline: none; 620 620 border-color: var(--aidf-orange); 621 621 box-shadow: 0 0 0 3px var(--aidf-orange-glow); 622 } 623 624 .aidf-page-search__results { 625 display: none; 626 position: absolute; 627 top: 100%; 628 left: 0; 629 right: 0; 630 margin: 4px 0 0; 631 padding: 0; 632 list-style: none; 633 background: var(--aidf-white); 634 border: 1px solid var(--aidf-border); 635 border-radius: var(--aidf-radius); 636 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); 637 max-height: 240px; 638 overflow-y: auto; 639 z-index: 100; 640 } 641 642 .aidf-page-search__results--open { 643 display: block; 644 } 645 646 .aidf-page-search__item { 647 display: flex; 648 align-items: center; 649 justify-content: space-between; 650 gap: var(--aidf-sp-2); 651 padding: var(--aidf-sp-2) var(--aidf-sp-3); 652 cursor: pointer; 653 transition: background-color 0.15s ease; 654 } 655 656 .aidf-page-search__item:hover, 657 .aidf-page-search__item--active { 658 background-color: var(--aidf-orange-glow); 659 } 660 661 .aidf-page-search__title { 662 flex: 1; 663 min-width: 0; 664 overflow: hidden; 665 text-overflow: ellipsis; 666 white-space: nowrap; 667 font-size: var(--aidf-text-sm); 668 color: var(--aidf-text); 669 } 670 671 .aidf-page-search__type { 672 flex-shrink: 0; 673 font-size: 0.6875rem; 674 color: var(--aidf-text-secondary); 675 background: var(--aidf-bg); 676 padding: 1px 6px; 677 border-radius: 3px; 678 text-transform: capitalize; 679 } 680 681 .aidf-page-search__status { 682 padding: var(--aidf-sp-2) var(--aidf-sp-3); 683 font-size: var(--aidf-text-sm); 684 color: var(--aidf-text-secondary); 685 font-style: italic; 622 686 } 623 687 … … 628 692 } 629 693 630 .aidf-page- picker{694 .aidf-page-search { 631 695 max-width: none; 632 696 min-width: 0; -
ai-discovery-files/tags/1.2.0/admin/js/admin.js
r3475304 r3482407 401 401 402 402 /* ------------------------------------------------------- 403 Page Picker — populate URL input from dropdown 404 ------------------------------------------------------- */ 405 $('.aidf-page-picker').on('change', function () { 406 var $select = $(this); 407 var url = $select.val(); 408 409 if (url) { 410 $('#' + $select.data('target')).val(url); 411 $select.val(''); 412 } 413 }); 403 Page Search Autocomplete 404 ------------------------------------------------------- */ 405 (function () { 406 var debounceTimers = {}; 407 408 /** 409 * Perform the AJAX search and render results. 410 * 411 * @param {jQuery} $wrapper The .aidf-page-search container. 412 * @param {string} query The search string. 413 */ 414 function doSearch($wrapper, query) { 415 var $results = $wrapper.find('.aidf-page-search__results'); 416 var postTypes = $wrapper.data('post-types') || 'page'; 417 418 if (query.length < 2) { 419 $results.empty().removeClass('aidf-page-search__results--open'); 420 $wrapper.find('.aidf-page-search__input').attr('aria-expanded', 'false'); 421 return; 422 } 423 424 $results.html('<li class="aidf-page-search__status">' + escAttr(aidfAdmin.i18n.searching) + '</li>') 425 .addClass('aidf-page-search__results--open'); 426 $wrapper.find('.aidf-page-search__input').attr('aria-expanded', 'true'); 427 428 $.post(aidfAdmin.ajaxUrl, { 429 action: 'aidf_search_pages', 430 nonce: aidfAdmin.nonce, 431 search: query, 432 post_types: postTypes 433 }, function (response) { 434 $results.empty(); 435 436 if (!response.success || !response.data.length) { 437 $results.html('<li class="aidf-page-search__status">' + escAttr(aidfAdmin.i18n.noResults) + '</li>'); 438 return; 439 } 440 441 $.each(response.data, function (i, page) { 442 $results.append( 443 '<li class="aidf-page-search__item" role="option" data-url="' + escAttr(page.url) + '">' + 444 '<span class="aidf-page-search__title">' + escAttr(page.title) + '</span>' + 445 (page.type !== 'page' ? '<span class="aidf-page-search__type">' + escAttr(page.type) + '</span>' : '') + 446 '</li>' 447 ); 448 }); 449 }).fail(function () { 450 $results.html('<li class="aidf-page-search__status">' + escAttr(aidfAdmin.i18n.noResults) + '</li>'); 451 }); 452 } 453 454 // Debounced input handler. 455 $(document).on('input', '.aidf-page-search__input', function () { 456 var $input = $(this); 457 var $wrapper = $input.closest('.aidf-page-search'); 458 var id = $wrapper.data('target'); 459 460 clearTimeout(debounceTimers[id]); 461 debounceTimers[id] = setTimeout(function () { 462 doSearch($wrapper, $.trim($input.val())); 463 }, 300); 464 }); 465 466 // Click on a result. 467 $(document).on('click', '.aidf-page-search__item', function () { 468 var $item = $(this); 469 var $wrapper = $item.closest('.aidf-page-search'); 470 var targetId = $wrapper.data('target'); 471 472 $('#' + targetId).val($item.data('url')); 473 $wrapper.find('.aidf-page-search__input').val('').attr('aria-expanded', 'false'); 474 $wrapper.find('.aidf-page-search__results').empty().removeClass('aidf-page-search__results--open'); 475 }); 476 477 // Keyboard navigation. 478 $(document).on('keydown', '.aidf-page-search__input', function (e) { 479 var $wrapper = $(this).closest('.aidf-page-search'); 480 var $results = $wrapper.find('.aidf-page-search__results'); 481 var $items = $results.find('.aidf-page-search__item'); 482 var $active = $items.filter('.aidf-page-search__item--active'); 483 var index = $items.index($active); 484 485 if (e.keyCode === 40) { // Down 486 e.preventDefault(); 487 index = index < $items.length - 1 ? index + 1 : 0; 488 $items.removeClass('aidf-page-search__item--active'); 489 $items.eq(index).addClass('aidf-page-search__item--active'); 490 } else if (e.keyCode === 38) { // Up 491 e.preventDefault(); 492 index = index > 0 ? index - 1 : $items.length - 1; 493 $items.removeClass('aidf-page-search__item--active'); 494 $items.eq(index).addClass('aidf-page-search__item--active'); 495 } else if (e.keyCode === 13) { // Enter 496 e.preventDefault(); 497 if ($active.length) { 498 $active.trigger('click'); 499 } 500 } else if (e.keyCode === 27) { // Escape 501 $results.empty().removeClass('aidf-page-search__results--open'); 502 $(this).attr('aria-expanded', 'false'); 503 } 504 }); 505 506 // Close on click outside. 507 $(document).on('click', function (e) { 508 if (!$(e.target).closest('.aidf-page-search').length) { 509 $('.aidf-page-search__results').empty().removeClass('aidf-page-search__results--open'); 510 $('.aidf-page-search__input').attr('aria-expanded', 'false'); 511 } 512 }); 513 })(); 414 514 415 515 /* ------------------------------------------------------- -
ai-discovery-files/tags/1.2.0/admin/views/tab-identity.php
r3472044 r3482407 14 14 15 15 $settings = AIDF_Plugin::get_settings(); 16 $site_pages = get_pages( array( 'post_status' => 'publish', 'sort_column' => 'post_title', 'number' => 100 ) );17 if ( ! is_array( $site_pages ) ) {18 $site_pages = array();19 }20 16 21 17 // Normalise legacy services string to array for the repeater. … … 157 153 class="aidf-input" 158 154 placeholder="https://"> 159 <select class="aidf-page-picker" data-target="aidf-contact-url"> 160 <option value=""><?php esc_html_e( 'Select a page…', 'ai-discovery-files' ); ?></option> 161 <?php foreach ( $site_pages as $page ) : ?> 162 <option value="<?php echo esc_url( get_permalink( $page ) ); ?>"><?php echo esc_html( $page->post_title ); ?></option> 163 <?php endforeach; ?> 164 </select> 155 <div class="aidf-page-search" data-target="aidf-contact-url"> 156 <input type="text" class="aidf-page-search__input" placeholder="<?php esc_attr_e( 'Search pages…', 'ai-discovery-files' ); ?>" autocomplete="off" role="combobox" aria-expanded="false" aria-autocomplete="list"> 157 <ul class="aidf-page-search__results" role="listbox" aria-live="polite"></ul> 158 </div> 165 159 </div> 166 160 </div> … … 410 404 <div class="aidf-url-with-picker"> 411 405 <input type="url" id="aidf-products-url" name="aidf_settings[products_url]" value="<?php echo esc_url( $settings['products_url'] ); ?>" class="aidf-input" placeholder="https://"> 412 <select class="aidf-page-picker" data-target="aidf-products-url"> 413 <option value=""><?php esc_html_e( 'Select a page…', 'ai-discovery-files' ); ?></option> 414 <?php foreach ( $site_pages as $page ) : ?> 415 <option value="<?php echo esc_url( get_permalink( $page ) ); ?>"><?php echo esc_html( $page->post_title ); ?></option> 416 <?php endforeach; ?> 417 </select> 406 <div class="aidf-page-search" data-target="aidf-products-url" data-post-types="page,product"> 407 <input type="text" class="aidf-page-search__input" placeholder="<?php esc_attr_e( 'Search pages…', 'ai-discovery-files' ); ?>" autocomplete="off" role="combobox" aria-expanded="false" aria-autocomplete="list"> 408 <ul class="aidf-page-search__results" role="listbox" aria-live="polite"></ul> 409 </div> 418 410 </div> 419 411 <p class="aidf-description"><?php esc_html_e( 'Linked from llms.txt as a key commercial page.', 'ai-discovery-files' ); ?></p> … … 602 594 <div class="aidf-url-with-picker"> 603 595 <input type="url" id="aidf-privacy-url" name="aidf_settings[privacy_policy_url]" value="<?php echo esc_url( $settings['privacy_policy_url'] ); ?>" class="aidf-input" placeholder="https://"> 604 <select class="aidf-page-picker" data-target="aidf-privacy-url"> 605 <option value=""><?php esc_html_e( 'Select a page…', 'ai-discovery-files' ); ?></option> 606 <?php foreach ( $site_pages as $page ) : ?> 607 <option value="<?php echo esc_url( get_permalink( $page ) ); ?>"><?php echo esc_html( $page->post_title ); ?></option> 608 <?php endforeach; ?> 609 </select> 596 <div class="aidf-page-search" data-target="aidf-privacy-url"> 597 <input type="text" class="aidf-page-search__input" placeholder="<?php esc_attr_e( 'Search pages…', 'ai-discovery-files' ); ?>" autocomplete="off" role="combobox" aria-expanded="false" aria-autocomplete="list"> 598 <ul class="aidf-page-search__results" role="listbox" aria-live="polite"></ul> 599 </div> 610 600 </div> 611 601 <p class="aidf-description"><?php esc_html_e( 'Auto-detected from WordPress Settings if set.', 'ai-discovery-files' ); ?></p> … … 616 606 <div class="aidf-url-with-picker"> 617 607 <input type="url" id="aidf-terms-url" name="aidf_settings[terms_url]" value="<?php echo esc_url( $settings['terms_url'] ); ?>" class="aidf-input" placeholder="https://"> 618 <select class="aidf-page-picker" data-target="aidf-terms-url"> 619 <option value=""><?php esc_html_e( 'Select a page…', 'ai-discovery-files' ); ?></option> 620 <?php foreach ( $site_pages as $page ) : ?> 621 <option value="<?php echo esc_url( get_permalink( $page ) ); ?>"><?php echo esc_html( $page->post_title ); ?></option> 622 <?php endforeach; ?> 623 </select> 608 <div class="aidf-page-search" data-target="aidf-terms-url"> 609 <input type="text" class="aidf-page-search__input" placeholder="<?php esc_attr_e( 'Search pages…', 'ai-discovery-files' ); ?>" autocomplete="off" role="combobox" aria-expanded="false" aria-autocomplete="list"> 610 <ul class="aidf-page-search__results" role="listbox" aria-live="polite"></ul> 611 </div> 624 612 </div> 625 613 </div> -
ai-discovery-files/tags/1.2.0/includes/class-data-collector.php
r3472044 r3482407 167 167 'sort_column' => 'menu_order,post_title', 168 168 'post_status' => 'publish', 169 'number' => 50,169 'number' => 200, 170 170 ) 171 171 ); -
ai-discovery-files/trunk/admin/class-admin.php
r3475304 r3482407 38 38 add_action( 'wp_ajax_aidf_save_verify_code', array( __CLASS__, 'ajax_save_verify_code' ) ); 39 39 add_action( 'wp_ajax_aidf_dismiss_review', array( __CLASS__, 'ajax_dismiss_review' ) ); 40 add_action( 'wp_ajax_aidf_search_pages', array( __CLASS__, 'ajax_search_pages' ) ); 40 41 add_action( 'admin_notices', array( __CLASS__, 'maybe_show_welcome_notice' ) ); 41 42 add_action( 'admin_notices', array( __CLASS__, 'maybe_show_conflict_notice' ) ); … … 118 119 'verifyFileActive' => __( 'Verification file is live at', 'ai-discovery-files' ), 119 120 'verifyFileInactive' => __( 'No verification code set. Enter your code above to activate.', 'ai-discovery-files' ), 121 'searchPages' => __( 'Search pages…', 'ai-discovery-files' ), 122 'searching' => __( 'Searching…', 'ai-discovery-files' ), 123 'noResults' => __( 'No pages found', 'ai-discovery-files' ), 124 'typeToSearch' => __( 'Type to search…', 'ai-discovery-files' ), 120 125 ), 121 126 ) … … 599 604 wp_send_json_success(); 600 605 } 606 607 /** 608 * AJAX handler: search pages for the page picker autocomplete. 609 * 610 * @return void 611 */ 612 public static function ajax_search_pages() { 613 check_ajax_referer( 'aidf_admin_nonce', 'nonce' ); 614 615 if ( ! current_user_can( 'manage_options' ) ) { 616 wp_send_json_error( __( 'Permission denied.', 'ai-discovery-files' ) ); 617 } 618 619 $search = isset( $_POST['search'] ) ? sanitize_text_field( wp_unslash( $_POST['search'] ) ) : ''; 620 621 if ( strlen( $search ) < 2 ) { 622 wp_send_json_success( array() ); 623 } 624 625 // Determine post types — defaults to page, but caller can request additional types. 626 $raw_types = isset( $_POST['post_types'] ) ? sanitize_text_field( wp_unslash( $_POST['post_types'] ) ) : 'page'; 627 $allowed = array( 'page', 'product' ); 628 $post_types = array_intersect( 629 array_map( 'trim', explode( ',', $raw_types ) ), 630 $allowed 631 ); 632 633 if ( empty( $post_types ) ) { 634 $post_types = array( 'page' ); 635 } 636 637 $query = new WP_Query( 638 array( 639 's' => $search, 640 'post_type' => $post_types, 641 'post_status' => 'publish', 642 'posts_per_page' => 20, 643 'orderby' => 'relevance', 644 'no_found_rows' => true, 645 ) 646 ); 647 648 $results = array(); 649 foreach ( $query->posts as $post ) { 650 $results[] = array( 651 'id' => $post->ID, 652 'title' => $post->post_title, 653 'url' => get_permalink( $post ), 654 'type' => $post->post_type, 655 ); 656 } 657 658 wp_send_json_success( $results ); 659 } 601 660 } -
ai-discovery-files/trunk/admin/css/admin.css
r3475304 r3482407 580 580 581 581 /* -------------------------------------------------------- 582 9c. Page Picker (URL + dropdown)582 9c. Page Search Autocomplete (URL + AJAX search) 583 583 -------------------------------------------------------- */ 584 584 .aidf-url-with-picker { … … 594 594 } 595 595 596 .aidf-page- picker{597 display: block;598 width: auto;596 .aidf-page-search { 597 position: relative; 598 flex-shrink: 0; 599 599 min-width: 160px; 600 600 max-width: 220px; 601 padding: var(--aidf-sp-2) 36px var(--aidf-sp-2) var(--aidf-sp-3); 601 } 602 603 .aidf-page-search__input { 604 display: block; 605 width: 100%; 606 padding: var(--aidf-sp-2) var(--aidf-sp-3); 602 607 font-family: var(--aidf-font); 603 608 font-size: var(--aidf-text-sm); 604 color: var(--aidf-text -secondary);609 color: var(--aidf-text); 605 610 background: var(--aidf-white); 606 611 border: 1px solid var(--aidf-border); … … 608 613 transition: border-color var(--aidf-transition), box-shadow var(--aidf-transition); 609 614 line-height: 1.5; 610 appearance: none; 611 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M6 8L1 3h10z' fill='%238b8fa3'/%3E%3C/svg%3E"); 612 background-repeat: no-repeat; 613 background-position: right 12px center; 614 cursor: pointer; 615 flex-shrink: 0; 616 } 617 618 .aidf-page-picker:focus { 615 box-sizing: border-box; 616 } 617 618 .aidf-page-search__input:focus { 619 619 outline: none; 620 620 border-color: var(--aidf-orange); 621 621 box-shadow: 0 0 0 3px var(--aidf-orange-glow); 622 } 623 624 .aidf-page-search__results { 625 display: none; 626 position: absolute; 627 top: 100%; 628 left: 0; 629 right: 0; 630 margin: 4px 0 0; 631 padding: 0; 632 list-style: none; 633 background: var(--aidf-white); 634 border: 1px solid var(--aidf-border); 635 border-radius: var(--aidf-radius); 636 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); 637 max-height: 240px; 638 overflow-y: auto; 639 z-index: 100; 640 } 641 642 .aidf-page-search__results--open { 643 display: block; 644 } 645 646 .aidf-page-search__item { 647 display: flex; 648 align-items: center; 649 justify-content: space-between; 650 gap: var(--aidf-sp-2); 651 padding: var(--aidf-sp-2) var(--aidf-sp-3); 652 cursor: pointer; 653 transition: background-color 0.15s ease; 654 } 655 656 .aidf-page-search__item:hover, 657 .aidf-page-search__item--active { 658 background-color: var(--aidf-orange-glow); 659 } 660 661 .aidf-page-search__title { 662 flex: 1; 663 min-width: 0; 664 overflow: hidden; 665 text-overflow: ellipsis; 666 white-space: nowrap; 667 font-size: var(--aidf-text-sm); 668 color: var(--aidf-text); 669 } 670 671 .aidf-page-search__type { 672 flex-shrink: 0; 673 font-size: 0.6875rem; 674 color: var(--aidf-text-secondary); 675 background: var(--aidf-bg); 676 padding: 1px 6px; 677 border-radius: 3px; 678 text-transform: capitalize; 679 } 680 681 .aidf-page-search__status { 682 padding: var(--aidf-sp-2) var(--aidf-sp-3); 683 font-size: var(--aidf-text-sm); 684 color: var(--aidf-text-secondary); 685 font-style: italic; 622 686 } 623 687 … … 628 692 } 629 693 630 .aidf-page- picker{694 .aidf-page-search { 631 695 max-width: none; 632 696 min-width: 0; -
ai-discovery-files/trunk/admin/js/admin.js
r3475304 r3482407 401 401 402 402 /* ------------------------------------------------------- 403 Page Picker — populate URL input from dropdown 404 ------------------------------------------------------- */ 405 $('.aidf-page-picker').on('change', function () { 406 var $select = $(this); 407 var url = $select.val(); 408 409 if (url) { 410 $('#' + $select.data('target')).val(url); 411 $select.val(''); 412 } 413 }); 403 Page Search Autocomplete 404 ------------------------------------------------------- */ 405 (function () { 406 var debounceTimers = {}; 407 408 /** 409 * Perform the AJAX search and render results. 410 * 411 * @param {jQuery} $wrapper The .aidf-page-search container. 412 * @param {string} query The search string. 413 */ 414 function doSearch($wrapper, query) { 415 var $results = $wrapper.find('.aidf-page-search__results'); 416 var postTypes = $wrapper.data('post-types') || 'page'; 417 418 if (query.length < 2) { 419 $results.empty().removeClass('aidf-page-search__results--open'); 420 $wrapper.find('.aidf-page-search__input').attr('aria-expanded', 'false'); 421 return; 422 } 423 424 $results.html('<li class="aidf-page-search__status">' + escAttr(aidfAdmin.i18n.searching) + '</li>') 425 .addClass('aidf-page-search__results--open'); 426 $wrapper.find('.aidf-page-search__input').attr('aria-expanded', 'true'); 427 428 $.post(aidfAdmin.ajaxUrl, { 429 action: 'aidf_search_pages', 430 nonce: aidfAdmin.nonce, 431 search: query, 432 post_types: postTypes 433 }, function (response) { 434 $results.empty(); 435 436 if (!response.success || !response.data.length) { 437 $results.html('<li class="aidf-page-search__status">' + escAttr(aidfAdmin.i18n.noResults) + '</li>'); 438 return; 439 } 440 441 $.each(response.data, function (i, page) { 442 $results.append( 443 '<li class="aidf-page-search__item" role="option" data-url="' + escAttr(page.url) + '">' + 444 '<span class="aidf-page-search__title">' + escAttr(page.title) + '</span>' + 445 (page.type !== 'page' ? '<span class="aidf-page-search__type">' + escAttr(page.type) + '</span>' : '') + 446 '</li>' 447 ); 448 }); 449 }).fail(function () { 450 $results.html('<li class="aidf-page-search__status">' + escAttr(aidfAdmin.i18n.noResults) + '</li>'); 451 }); 452 } 453 454 // Debounced input handler. 455 $(document).on('input', '.aidf-page-search__input', function () { 456 var $input = $(this); 457 var $wrapper = $input.closest('.aidf-page-search'); 458 var id = $wrapper.data('target'); 459 460 clearTimeout(debounceTimers[id]); 461 debounceTimers[id] = setTimeout(function () { 462 doSearch($wrapper, $.trim($input.val())); 463 }, 300); 464 }); 465 466 // Click on a result. 467 $(document).on('click', '.aidf-page-search__item', function () { 468 var $item = $(this); 469 var $wrapper = $item.closest('.aidf-page-search'); 470 var targetId = $wrapper.data('target'); 471 472 $('#' + targetId).val($item.data('url')); 473 $wrapper.find('.aidf-page-search__input').val('').attr('aria-expanded', 'false'); 474 $wrapper.find('.aidf-page-search__results').empty().removeClass('aidf-page-search__results--open'); 475 }); 476 477 // Keyboard navigation. 478 $(document).on('keydown', '.aidf-page-search__input', function (e) { 479 var $wrapper = $(this).closest('.aidf-page-search'); 480 var $results = $wrapper.find('.aidf-page-search__results'); 481 var $items = $results.find('.aidf-page-search__item'); 482 var $active = $items.filter('.aidf-page-search__item--active'); 483 var index = $items.index($active); 484 485 if (e.keyCode === 40) { // Down 486 e.preventDefault(); 487 index = index < $items.length - 1 ? index + 1 : 0; 488 $items.removeClass('aidf-page-search__item--active'); 489 $items.eq(index).addClass('aidf-page-search__item--active'); 490 } else if (e.keyCode === 38) { // Up 491 e.preventDefault(); 492 index = index > 0 ? index - 1 : $items.length - 1; 493 $items.removeClass('aidf-page-search__item--active'); 494 $items.eq(index).addClass('aidf-page-search__item--active'); 495 } else if (e.keyCode === 13) { // Enter 496 e.preventDefault(); 497 if ($active.length) { 498 $active.trigger('click'); 499 } 500 } else if (e.keyCode === 27) { // Escape 501 $results.empty().removeClass('aidf-page-search__results--open'); 502 $(this).attr('aria-expanded', 'false'); 503 } 504 }); 505 506 // Close on click outside. 507 $(document).on('click', function (e) { 508 if (!$(e.target).closest('.aidf-page-search').length) { 509 $('.aidf-page-search__results').empty().removeClass('aidf-page-search__results--open'); 510 $('.aidf-page-search__input').attr('aria-expanded', 'false'); 511 } 512 }); 513 })(); 414 514 415 515 /* ------------------------------------------------------- -
ai-discovery-files/trunk/admin/views/partials/review-banner.php
r3475304 r3482407 19 19 <span class="aidf-review-banner__text"><?php esc_html_e( 'Enjoying AI Discovery Files?', 'ai-discovery-files' ); ?></span> 20 20 <span class="aidf-review-banner__stars" id="aidf-review-stars" role="radiogroup" aria-label="<?php esc_attr_e( 'Rate from 1 to 5 stars', 'ai-discovery-files' ); ?>"> 21 <?php for ( $i = 1; $i <= 5; $i++ ) : ?> 22 <button type="button" class="aidf-review-star" data-rating="<?php echo esc_attr( $i ); ?>" aria-label="<?php echo esc_attr( sprintf( __( '%d star', 'ai-discovery-files' ), $i ) ); ?>"> 21 <?php for ( $aidf_star = 1; $aidf_star <= 5; $aidf_star++ ) : ?> 22 <?php /* translators: %d: star rating number (1-5) */ ?> 23 <button type="button" class="aidf-review-star" data-rating="<?php echo esc_attr( $aidf_star ); ?>" aria-label="<?php echo esc_attr( sprintf( __( '%d star', 'ai-discovery-files' ), $aidf_star ) ); ?>"> 23 24 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> 24 25 <path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/> -
ai-discovery-files/trunk/admin/views/tab-identity.php
r3472044 r3482407 14 14 15 15 $settings = AIDF_Plugin::get_settings(); 16 $site_pages = get_pages( array( 'post_status' => 'publish', 'sort_column' => 'post_title', 'number' => 100 ) );17 if ( ! is_array( $site_pages ) ) {18 $site_pages = array();19 }20 16 21 17 // Normalise legacy services string to array for the repeater. … … 157 153 class="aidf-input" 158 154 placeholder="https://"> 159 <select class="aidf-page-picker" data-target="aidf-contact-url"> 160 <option value=""><?php esc_html_e( 'Select a page…', 'ai-discovery-files' ); ?></option> 161 <?php foreach ( $site_pages as $page ) : ?> 162 <option value="<?php echo esc_url( get_permalink( $page ) ); ?>"><?php echo esc_html( $page->post_title ); ?></option> 163 <?php endforeach; ?> 164 </select> 155 <div class="aidf-page-search" data-target="aidf-contact-url"> 156 <input type="text" class="aidf-page-search__input" placeholder="<?php esc_attr_e( 'Search pages…', 'ai-discovery-files' ); ?>" autocomplete="off" role="combobox" aria-expanded="false" aria-autocomplete="list"> 157 <ul class="aidf-page-search__results" role="listbox" aria-live="polite"></ul> 158 </div> 165 159 </div> 166 160 </div> … … 410 404 <div class="aidf-url-with-picker"> 411 405 <input type="url" id="aidf-products-url" name="aidf_settings[products_url]" value="<?php echo esc_url( $settings['products_url'] ); ?>" class="aidf-input" placeholder="https://"> 412 <select class="aidf-page-picker" data-target="aidf-products-url"> 413 <option value=""><?php esc_html_e( 'Select a page…', 'ai-discovery-files' ); ?></option> 414 <?php foreach ( $site_pages as $page ) : ?> 415 <option value="<?php echo esc_url( get_permalink( $page ) ); ?>"><?php echo esc_html( $page->post_title ); ?></option> 416 <?php endforeach; ?> 417 </select> 406 <div class="aidf-page-search" data-target="aidf-products-url" data-post-types="page,product"> 407 <input type="text" class="aidf-page-search__input" placeholder="<?php esc_attr_e( 'Search pages…', 'ai-discovery-files' ); ?>" autocomplete="off" role="combobox" aria-expanded="false" aria-autocomplete="list"> 408 <ul class="aidf-page-search__results" role="listbox" aria-live="polite"></ul> 409 </div> 418 410 </div> 419 411 <p class="aidf-description"><?php esc_html_e( 'Linked from llms.txt as a key commercial page.', 'ai-discovery-files' ); ?></p> … … 602 594 <div class="aidf-url-with-picker"> 603 595 <input type="url" id="aidf-privacy-url" name="aidf_settings[privacy_policy_url]" value="<?php echo esc_url( $settings['privacy_policy_url'] ); ?>" class="aidf-input" placeholder="https://"> 604 <select class="aidf-page-picker" data-target="aidf-privacy-url"> 605 <option value=""><?php esc_html_e( 'Select a page…', 'ai-discovery-files' ); ?></option> 606 <?php foreach ( $site_pages as $page ) : ?> 607 <option value="<?php echo esc_url( get_permalink( $page ) ); ?>"><?php echo esc_html( $page->post_title ); ?></option> 608 <?php endforeach; ?> 609 </select> 596 <div class="aidf-page-search" data-target="aidf-privacy-url"> 597 <input type="text" class="aidf-page-search__input" placeholder="<?php esc_attr_e( 'Search pages…', 'ai-discovery-files' ); ?>" autocomplete="off" role="combobox" aria-expanded="false" aria-autocomplete="list"> 598 <ul class="aidf-page-search__results" role="listbox" aria-live="polite"></ul> 599 </div> 610 600 </div> 611 601 <p class="aidf-description"><?php esc_html_e( 'Auto-detected from WordPress Settings if set.', 'ai-discovery-files' ); ?></p> … … 616 606 <div class="aidf-url-with-picker"> 617 607 <input type="url" id="aidf-terms-url" name="aidf_settings[terms_url]" value="<?php echo esc_url( $settings['terms_url'] ); ?>" class="aidf-input" placeholder="https://"> 618 <select class="aidf-page-picker" data-target="aidf-terms-url"> 619 <option value=""><?php esc_html_e( 'Select a page…', 'ai-discovery-files' ); ?></option> 620 <?php foreach ( $site_pages as $page ) : ?> 621 <option value="<?php echo esc_url( get_permalink( $page ) ); ?>"><?php echo esc_html( $page->post_title ); ?></option> 622 <?php endforeach; ?> 623 </select> 608 <div class="aidf-page-search" data-target="aidf-terms-url"> 609 <input type="text" class="aidf-page-search__input" placeholder="<?php esc_attr_e( 'Search pages…', 'ai-discovery-files' ); ?>" autocomplete="off" role="combobox" aria-expanded="false" aria-autocomplete="list"> 610 <ul class="aidf-page-search__results" role="listbox" aria-live="polite"></ul> 611 </div> 624 612 </div> 625 613 </div> -
ai-discovery-files/trunk/ai-discovery-files.php
r3479765 r3482407 4 4 * Plugin URI: https://www.ai-visibility.org.uk/wordpress-plugin/ai-discovery-files/ 5 5 * Description: Generate AI Discovery Files so AI systems like ChatGPT, Claude, and Gemini can correctly discover and cite your website. Built by 365i. 6 * Version: 1.2. 06 * Version: 1.2.1 7 7 * Requires at least: 6.2 8 8 * Requires PHP: 8.0 … … 24 24 * Plugin constants. 25 25 */ 26 define( 'AIDF_VERSION', '1.2. 0' );26 define( 'AIDF_VERSION', '1.2.1' ); 27 27 define( 'AIDF_PLUGIN_FILE', __FILE__ ); 28 28 define( 'AIDF_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); -
ai-discovery-files/trunk/includes/class-data-collector.php
r3472044 r3482407 167 167 'sort_column' => 'menu_order,post_title', 168 168 'post_status' => 'publish', 169 'number' => 50,169 'number' => 200, 170 170 ) 171 171 ); -
ai-discovery-files/trunk/readme.txt
r3479765 r3482407 5 5 Tested up to: 6.9 6 6 Requires PHP: 8.0 7 Stable tag: 1.2. 07 Stable tag: 1.2.1 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 167 167 168 168 == Changelog == 169 170 = 1.2.1 = 171 * Replace static page picker dropdowns with AJAX-powered search autocomplete 172 * Page pickers now scale to sites with hundreds or thousands of pages 173 * Products/Pricing field also searches WooCommerce product pages 174 * Full keyboard navigation (arrow keys, Enter, Escape) and ARIA accessibility 175 * Increase page limit in generated AI discovery files from 50 to 200 169 176 170 177 = 1.2.0 =
Note: See TracChangeset
for help on using the changeset viewer.