@@ -69,17 +69,41 @@ public function update_test_from_schedule( $test_id, $data ) {
6969 [ 'service_test_id ' => $ test_id ]
7070 );
7171
72- // Generate AI selectors if none exist after initial screenshot .
72+ // Save AI selectors from service callback payload .
7373 $ post_id = Test::get_post_id_by_service_test_id ( $ test_id );
7474 if ( $ post_id ) {
7575 $ test = Test::get_item_by_post_id ( $ post_id );
76- if ( $ test && empty ( $ test ->hide_css_selectors ) ) {
77- $ result = self ::generate_ai_selectors ();
78- Test::save_hide_css_selectors ( $ test ->id , $ result ['selectors ' ] );
76+ if ( $ test && array_key_exists ( 'ai_selectors ' , $ data ) && is_array ( $ data ['ai_selectors ' ] ) ) {
77+ $ ai_selectors = array_values ( array_filter ( array_map (
78+ function ( $ entry ) {
79+ if ( ! is_array ( $ entry ) || empty ( $ entry ['selector ' ] ) ) {
80+ return null ;
81+ }
82+
83+ return [
84+ 'selector ' => sanitize_text_field ( $ entry ['selector ' ] ),
85+ 'reason ' => isset ( $ entry ['reason ' ] ) ? sanitize_text_field ( $ entry ['reason ' ] ) : '' ,
86+ ];
87+ },
88+ $ data ['ai_selectors ' ]
89+ ) ) );
90+
91+ $ has_ai_suggestions = ! empty ( $ ai_selectors );
92+
7993 Test::set_meta ( $ test ->id , [
80- 'ai_selectors ' => $ result [ ' ai_selectors ' ] ,
81- 'ai_selectors_seen ' => false ,
94+ 'ai_selectors ' => $ ai_selectors ,
95+ 'ai_selectors_seen ' => ! $ has_ai_suggestions ,
8296 ] );
97+
98+ if ( $ has_ai_suggestions ) {
99+ // Apply only when user has not configured manual hide selectors yet.
100+ if ( empty ( $ test ->hide_css_selectors ) ) {
101+ $ selectors = implode ( ', ' , array_values ( array_unique ( array_column ( $ ai_selectors , 'selector ' ) ) ) );
102+ if ( ! empty ( $ selectors ) ) {
103+ Test::save_hide_css_selectors ( $ test ->id , $ selectors );
104+ }
105+ }
106+ }
83107 }
84108 }
85109 }//end if
@@ -460,75 +484,6 @@ public function update_css_hide_selectors( $test_id, $css_hide_selector ) {
460484 }
461485 }
462486
463- /**
464- * Generate random AI selectors from a predefined pool.
465- *
466- * @return array{selectors: string, ai_selectors: array} Selector string and structured data.
467- */
468- private static function generate_ai_selectors () {
469- $ pool = [
470- [
471- 'selector ' => '.elementor-background-video-hosted ' ,
472- 'reason ' => 'Background video frame changes on every capture ' ,
473- ],
474- [
475- 'selector ' => '.cmplz-cookiebanner ' ,
476- 'reason ' => 'Cookie consent banner appears conditionally based on visitor state ' ,
477- ],
478- [
479- 'selector ' => '.wp-block-embed__wrapper iframe ' ,
480- 'reason ' => 'Embedded iframe content may load differently between visits ' ,
481- ],
482- [
483- 'selector ' => '#tidio-chat ' ,
484- 'reason ' => 'Live chat widget position and visibility varies per session ' ,
485- ],
486- [
487- 'selector ' => '.swiper-slide-active ' ,
488- 'reason ' => 'Active slide in carousel rotates automatically between captures ' ,
489- ],
490- [
491- 'selector ' => '.woocommerce-store-notice ' ,
492- 'reason ' => 'Store notice banner can be dismissed and may not always display ' ,
493- ],
494- [
495- 'selector ' => '.elementor-widget-countdown ' ,
496- 'reason ' => 'Countdown timer value changes continuously between screenshots ' ,
497- ],
498- [
499- 'selector ' => '.google-auto-placed ' ,
500- 'reason ' => 'Auto-placed ad content differs on every page load ' ,
501- ],
502- [
503- 'selector ' => '.jetpack-lazy-image ' ,
504- 'reason ' => 'Lazy-loaded image placeholder may appear before full image renders ' ,
505- ],
506- [
507- 'selector ' => '.wpforms-confirmation-container ' ,
508- 'reason ' => 'Form confirmation message only appears after submission ' ,
509- ],
510- ];
511-
512- // phpcs:ignore WordPress.WP.AlternativeFunctions.rand_mt_rand -- Non-security random.
513- $ count = mt_rand ( 3 , 5 );
514- $ keys = array_rand ( $ pool , $ count );
515-
516- if ( ! is_array ( $ keys ) ) {
517- $ keys = [ $ keys ];
518- }
519-
520- $ selected = array_map ( function ( $ key ) use ( $ pool ) {
521- return $ pool [ $ key ];
522- }, $ keys );
523-
524- $ selectors_string = implode ( ', ' , array_column ( $ selected , 'selector ' ) );
525-
526- return [
527- 'selectors ' => $ selectors_string ,
528- 'ai_selectors ' => array_values ( $ selected ),
529- ];
530- }
531-
532487 /**
533488 * Resume test.
534489 *
0 commit comments