Skip to content

Commit 6c22a9f

Browse files
committed
feat(plugin): apply ai selectors from service updates
1 parent 0a4fb59 commit 6c22a9f

3 files changed

Lines changed: 36 additions & 87 deletions

File tree

components/test-settings/script.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,13 @@ class VrtsTestSettings extends window.HTMLElement {
6767
this.$testIdInput.value = testId;
6868
this.$textarea.value = selectors;
6969
this.$success.classList.remove( 'is-active' );
70-
71-
// Populate AI panel.
7270
this.aiSelectors = [];
7371
this.$aiDetails.classList.remove( 'is-open' );
7472
this.$aiToggle.classList.remove( 'is-open' );
7573
this.$aiToggle.setAttribute( 'aria-expanded', 'false' );
7674
this.showAiPanel( aiSelectorsRaw, testStatus );
7775

78-
// Handle AI seen state.
7976
if ( aiSeen === '0' ) {
80-
// Mark as seen via REST.
8177
fetch(
8278
`${ window.vrts_admin_vars.rest_url }/tests/${ testId }/ai-seen`,
8379
{
@@ -88,11 +84,9 @@ class VrtsTestSettings extends window.HTMLElement {
8884
}
8985
);
9086

91-
// Clear gradient on button and update tooltip.
9287
button.setAttribute( 'data-ai-seen', 'true' );
9388
button.title = button.getAttribute( 'aria-label' );
9489

95-
// Update inline data.
9690
const aiSeenEl = hiddenData?.querySelector( '.ai_selectors_seen' );
9791
if ( aiSeenEl ) {
9892
aiSeenEl.textContent = '1';
@@ -112,7 +106,6 @@ class VrtsTestSettings extends window.HTMLElement {
112106
newSelectors = [];
113107
}
114108

115-
// Append new selectors, avoiding duplicates.
116109
const existingSet = new Set(
117110
this.aiSelectors.map( ( item ) => item.selector )
118111
);
@@ -203,7 +196,6 @@ class VrtsTestSettings extends window.HTMLElement {
203196
this.$success.classList.remove( 'is-active' );
204197
}, 5000 );
205198

206-
// Update hidden inline data so next open shows fresh value.
207199
const hiddenData = document.getElementById(
208200
'inline_' + testId
209201
);

includes/list-tables/class-tests-list-table.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,9 @@ public function column_post_title( $item ) {
142142
$this->row_actions( $actions )
143143
);
144144

145-
$ai_selectors_seen = isset( $item->parsed_meta['ai_selectors_seen'] ) && false === $item->parsed_meta['ai_selectors_seen'] ? '0' : '1';
146-
$ai_selectors_json = isset( $item->parsed_meta['ai_selectors'] ) ? esc_html( wp_json_encode( $item->parsed_meta['ai_selectors'] ) ) : '';
145+
$has_ai_suggestions = ! empty( $item->parsed_meta['ai_selectors'] );
146+
$ai_selectors_seen = $has_ai_suggestions && isset( $item->parsed_meta['ai_selectors_seen'] ) && false === $item->parsed_meta['ai_selectors_seen'] ? '0' : '1';
147+
$ai_selectors_json = array_key_exists( 'ai_selectors', $item->parsed_meta ) ? esc_html( wp_json_encode( $item->parsed_meta['ai_selectors'] ) ) : '';
147148

148149
$quickedit_hidden_fields = "
149150
<div class='hidden' id='inline_{$item->id}'>
@@ -409,8 +410,9 @@ public function inline_edit() {
409410
private function render_column_status( $item ) {
410411
$status_data = Test::get_status_data( $item );
411412

412-
$ai_seen = isset( $item->parsed_meta['ai_selectors_seen'] ) && false === $item->parsed_meta['ai_selectors_seen'] ? 'false' : 'true';
413-
$has_ai_meta = ! empty( $item->parsed_meta['ai_selectors'] );
413+
$has_ai_suggestions = ! empty( $item->parsed_meta['ai_selectors'] );
414+
$ai_seen = $has_ai_suggestions && isset( $item->parsed_meta['ai_selectors_seen'] ) && false === $item->parsed_meta['ai_selectors_seen'] ? 'false' : 'true';
415+
$has_ai_meta = array_key_exists( 'ai_selectors', $item->parsed_meta );
414416
$tooltip = 'false' === $ai_seen
415417
? esc_attr__( 'AI-optimized configuration available', 'visual-regression-tests' )
416418
: esc_attr__( 'Test settings', 'visual-regression-tests' );

includes/services/class-test-service.php

Lines changed: 30 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)