Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fba7d12
Move the tooLongTimeout to a higher scope so it can be managed across…
pattonwebz May 21, 2025
1e0ab7f
Add helpers for detecting and getting options when in iframe context
pattonwebz May 21, 2025
be4761e
Create an axe runner method that lives on the window object and wrap …
pattonwebz May 21, 2025
c506e9d
Correct the passed type of error to the dispatchDoneEvent during cleanup
pattonwebz May 21, 2025
03cf745
Avoid potential error for nodes that no longer exist when trying get …
pattonwebz May 21, 2025
fe2ce25
Always give a failed message if cleanup fails
pattonwebz Jun 3, 2025
f364efe
Merge branch 'develop' into william/try/make-scan-runnable-from-front…
pattonwebz Jun 3, 2025
06488e9
Fix some lint issues
pattonwebz Jun 3, 2025
37d17eb
Add scanner bundle URL to frontend highlighter app
pattonwebz Jul 3, 2025
a924364
Implement scan initiation and result handling in frontend
pattonwebz Jul 3, 2025
b9af45b
Merge branch 'develop' into william/try/make-scan-runnable-from-front…
pattonwebz Jul 3, 2025
19fffc2
Add selector fields to database for improved accessibility checks
pattonwebz Jul 3, 2025
f0d250e
Add helper function to process violations and return formatted object
pattonwebz Jul 3, 2025
7a2f0cc
Pass the selectors to Insert_Rule_Data for enhanced data handling
pattonwebz Jul 3, 2025
31d8418
Add selectors and ancestry parameters to insert method
pattonwebz Jul 3, 2025
8aefaa0
Update landmark and selectors in existing issue when refound
pattonwebz Jul 3, 2025
1d4fb44
Defaults for selector, ancestry and xpath should be an array, not a s…
pattonwebz Jul 7, 2025
a83d706
Update database setup and table creations for InsertRuleDataTest.php
pattonwebz Jul 7, 2025
8d4227f
Make the scan state feedback messages translatable
pattonwebz Jul 8, 2025
8808e3d
Define default state for scanAttempted
pattonwebz Jul 8, 2025
9832bae
Use more readable check for data type when kicking off scan
pattonwebz Jul 8, 2025
d848fd0
Clarify comment on processViolation function regarding selector array
pattonwebz Jul 8, 2025
da57e09
No need to bump this here, another PR did the bump from 1.0.3 to 1.0.4
pattonwebz Jul 8, 2025
f2e9565
Merge remote-tracking branch 'origin/develop' into william/integratio…
pattonwebz Jul 8, 2025
f364662
Merge branch 'william/try/make-scan-runnable-from-frontend-loaded-pag…
pattonwebz Jul 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions admin/class-insert-rule-data.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,18 @@ class Insert_Rule_Data {
*
* @since 1.10.0
*
* @param object $post The post object. Must have a valid ID.
* @param string $rule The rule.
* @param string $ruletype The rule type.
* @param string $rule_obj The object.
* @param string|null $landmark The landmark type (main, header, footer, nav), optional.
* @param object $post The post object. Must have a valid ID.
* @param string $rule The rule.
* @param string $ruletype The rule type.
* @param string $rule_obj The object.
* @param string|null $landmark The landmark type (main, header, footer, nav), optional.
* @param string|null $landmark_selector The landmark selector, optional.
* @param array $selectors An array of selectors that point to the object, optional.
*
* @return void|int|\WP_Error The ID of the inserted record, void if no
* record was inserted or a WP_Error if the insert failed.
*/
public function insert( object $post, string $rule, string $ruletype, string $rule_obj, ?string $landmark = null, ?string $landmark_selector = null ) {
public function insert( object $post, string $rule, string $ruletype, string $rule_obj, ?string $landmark = null, ?string $landmark_selector = null, array $selectors = [] ) {

if ( ! isset( $post->ID, $post->post_type )
|| empty( $rule )
Expand All @@ -51,6 +52,9 @@ public function insert( object $post, string $rule, string $ruletype, string $ru
'type' => $post->post_type,
'landmark' => $landmark,
'landmark_selector' => $landmark_selector,
'selector' => $selectors['selector'][0] ?? null,
'ancestry' => $selectors['ancestry'][0] ?? null,
'xpath' => $selectors['xpath'][0] ?? null,
'rule' => $rule,
'ruletype' => $ruletype,
'object' => esc_attr( $rule_obj ),
Expand Down Expand Up @@ -96,9 +100,14 @@ public function insert( object $post, string $rule, string $ruletype, string $ru
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Using direct query for adding data to database, caching not required for one time operation.
$wpdb->query(
$wpdb->prepare(
'UPDATE %i SET recordcheck = %d, ignre = %d WHERE siteid = %d and postid = %d and rule = %s and object = %s and type = %s',
'UPDATE %i SET recordcheck = %d, landmark = %s, landmark_selector = %s, selector = %s, ancestry = %s, xpath = %s, ignre = %d WHERE siteid = %d and postid = %d and rule = %s and object = %s and type = %s',
$table_name,
1,
$rule_data['landmark'],
$rule_data['landmark_selector'],
$rule_data['selector'],
$rule_data['ancestry'],
$rule_data['xpath'],
$rule_data['ignre'],
$rule_data['siteid'],
$rule_data['postid'],
Expand Down Expand Up @@ -134,6 +143,9 @@ public function insert( object $post, string $rule, string $ruletype, string $ru
'type' => sanitize_text_field( $rule_data['type'] ),
'landmark' => isset( $rule_data['landmark'] ) ? sanitize_text_field( $rule_data['landmark'] ) : null,
'landmark_selector' => isset( $rule_data['landmark_selector'] ) ? sanitize_text_field( $rule_data['landmark_selector'] ) : null,
'selector' => sanitize_text_field( $rule_data['selector'] ?? '' ),
'ancestry' => sanitize_text_field( $rule_data['ancestry'] ?? '' ),
'xpath' => sanitize_text_field( $rule_data['xpath'] ?? '' ),
'rule' => sanitize_text_field( $rule_data['rule'] ),
'ruletype' => sanitize_text_field( $rule_data['ruletype'] ),
'object' => esc_attr( $rule_data['object'] ),
Expand Down
3 changes: 3 additions & 0 deletions admin/class-update-database.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public function edac_update_database() {
type text NOT NULL,
landmark varchar(20) NULL,
landmark_selector text NULL,
selector text NULL,
ancestry text NULL,
xpath text NULL,
rule text NOT NULL,
ruletype text NOT NULL,
object mediumtext NOT NULL,
Expand Down
21 changes: 11 additions & 10 deletions includes/classes/class-enqueue-frontend.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,17 @@ public static function maybe_enqueue_frontend_highlighter() {
'edac-frontend-highlighter-app',
'edacFrontendHighlighterApp',
[
'postID' => $post_id,
'nonce' => wp_create_nonce( 'ajax-nonce' ),
'restNonce' => wp_create_nonce( 'wp_rest' ),
'userCanFix' => current_user_can( apply_filters( 'edac_filter_settings_capability', 'manage_options' ) ),
'edacUrl' => esc_url_raw( get_site_url() ),
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'loggedIn' => is_user_logged_in(),
'appCssUrl' => EDAC_PLUGIN_URL . 'build/css/frontendHighlighterApp.css?ver=' . EDAC_VERSION,
'widgetPosition' => get_option( 'edac_frontend_highlighter_position', 'right' ),
'editorLink' => get_edit_post_link( $post_id ),
'postID' => $post_id,
'nonce' => wp_create_nonce( 'ajax-nonce' ),
'restNonce' => wp_create_nonce( 'wp_rest' ),
'userCanFix' => current_user_can( apply_filters( 'edac_filter_settings_capability', 'manage_options' ) ),
'edacUrl' => esc_url_raw( get_site_url() ),
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'loggedIn' => is_user_logged_in(),
'appCssUrl' => EDAC_PLUGIN_URL . 'build/css/frontendHighlighterApp.css?ver=' . EDAC_VERSION,
'widgetPosition' => get_option( 'edac_frontend_highlighter_position', 'right' ),
'editorLink' => get_edit_post_link( $post_id ),
'scannerBundleUrl' => plugin_dir_url( EDAC_PLUGIN_FILE ) . 'build/pageScanner.bundle.js',
]
);

Expand Down
7 changes: 6 additions & 1 deletion includes/classes/class-rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,12 @@ public function set_post_scan_results( $request ) {
$landmark = $violation['landmark'] ?? null;
$landmark_selector = $violation['landmarkSelector'] ?? null;

( new Insert_Rule_Data() )->insert( $post, $actual_rule_id, $impact, $html, $landmark, $landmark_selector );
$selectors = [
'selector' => $violation['selector'] ?? [],
'ancestry' => $violation['ancestry'] ?? [],
'xpath' => $violation['xpath'] ?? [],
];
( new Insert_Rule_Data() )->insert( $post, $actual_rule_id, $impact, $html, $landmark, $landmark_selector, $selectors );

/**
* Fires after a rule is run against the content.
Expand Down
130 changes: 125 additions & 5 deletions src/frontendHighlighterApp/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class AccessibilityCheckerHighlight {
};

this.settings = { ...defaultSettings, ...settings };
this._scanAttempted = false;

this.highlightPanel = this.addHighlightPanel();
this.nextButton = document.querySelector( '#edac-highlight-next' );
Expand Down Expand Up @@ -188,15 +189,21 @@ class AccessibilityCheckerHighlight {
},
);
}
} else if ( ! self._scanAttempted && response.data?.[ 0 ]?.code === -3 ) {
// Only try kickoffScan once per highlightAjax call
self._scanAttempted = true;
self.kickoffScan();
// After kickoffScan, try highlightAjax again, but only once
setTimeout( () => {
self.highlightAjax().then( resolve ).catch( reject );
}, 5000 ); // Wait 5s for scan to complete.
Comment on lines 191 to +199

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The highlightAjax function retries the scan with a 5-second timeout. If the scan consistently fails or takes longer than 5 seconds, this could lead to an infinite loop and degrade performance. Consider adding a maximum retry count or implementing exponential backoff to prevent this.1

      } else if ( ! self._scanAttempted && response.data?.[ 0 ]?.code === -3 ) {
						// Only try kickoffScan once per highlightAjax call
						self._scanAttempted = true;
						self.kickoffScan();
						// After kickoffScan, try highlightAjax again, but only once
						setTimeout( () => {
							self.highlightAjax().then( resolve ).catch( reject );
						}, 5000 ); // Wait 5s for scan to complete.

Style Guide References

Footnotes

  1. Avoid infinite loops by adding retry limits or exponential backoff. (link)

} else {
resolve( [] );
//console.log(response);
// Default: resolve with empty issues/fixes
resolve( { issues: [], fixes: [] } );
}
} else {
self.showWait( false );

//console.log( 'Request failed. Returned status of ' + xhr.status );

reject( {
status: xhr.status,
statusText: xhr.statusText,
Expand Down Expand Up @@ -541,7 +548,11 @@ class AccessibilityCheckerHighlight {
}
}
).catch( ( err ) => {
//TODO:
// Output a message that says that there are no issues or that the issues could not be loaded.
const summary = document.querySelector( '.edac-highlight-panel-controls-summary' );
if ( summary ) {
summary.textContent = __( 'An error occurred when loading the issues.', 'accessibility-checker' );
}
} );
}

Expand Down Expand Up @@ -1088,6 +1099,115 @@ class AccessibilityCheckerHighlight {
element.removeAttribute( 'data-edac-landmark-label-id' );
} );
}

/**
* Kick off the accessibility scan.
*/
kickoffScan() {
const getPageDensity = () => {
const elementCount = document.body.getElementsByTagName( '*' ).length;
const contentLength = document.body.innerText.length;
return { elementCount, contentLength };
};
const densityMetrics = getPageDensity();
const self = this;
const scriptId = 'edac-accessibility-checker-scanner-script';
if ( ! document.getElementById( scriptId ) ) {
const script = document.createElement( 'script' );
script.src = window.edacFrontendHighlighterApp?.scannerBundleUrl || '/wp-content/plugins/accessibility-checker/build/pageScanner.bundle.js';
script.id = scriptId;
script.onload = function() {
setTimeout( () => {
self._runScanOrShowError( densityMetrics );
}, 100 );
};
script.onerror = function() {
self.showWait( false );
self.showScanError( 'Failed to load scanner script.' );
};
document.head.appendChild( script );
} else {
self._runScanOrShowError( densityMetrics );
}
}

_runScanOrShowError( densityMetrics ) {
if ( window.runAccessibilityScan ) {
this.runAccessibilityScanAndSave( densityMetrics );
} else {
this.showWait( false );
this.showScanError( __( 'Scanner function not found.', 'accessibility-checker' ) );
}
}

runAccessibilityScanAndSave( densityMetrics ) {
const self = this;
const summary = document.querySelector( '.edac-highlight-panel-controls-summary' );
if ( summary ) {
summary.textContent = __( 'Scanning...', 'accessibility-checker' );
summary.classList.remove( 'edac-error' );
}
window.runAccessibilityScan().then( ( result ) => {
const postId = window.edacFrontendHighlighterApp && window.edacFrontendHighlighterApp.postID;
const nonce = window.edacFrontendHighlighterApp && window.edacFrontendHighlighterApp.restNonce;
if ( ! postId || ! nonce ) {
self.showWait( false );
self.showScanError( __( 'Missing postId or nonce.', 'accessibility-checker' ) );
return;
}
if ( ! result || ! result.violations || result.violations.length === 0 ) {
self.showWait( false );
self.showScanError( __( 'No violations found, skipping save.', 'accessibility-checker' ) );
return;
}
self.saveScanResults( postId, nonce, result.violations, densityMetrics );
} ).catch( () => {
self.showWait( false );
self.showScanError( __( 'Accessibility scan error.', 'accessibility-checker' ) );
} );
}

saveScanResults( postId, nonce, violations, densityMetrics ) {
const self = this;
fetch( '/wp-json/accessibility-checker/v1/post-scan-results/' + postId, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': nonce,
},
body: JSON.stringify( {
violations,
isSkipped: false,
isFailure: false,
densityMetrics,
} ),
} )
.then( ( response ) => response.json() )
.then( ( data ) => {
self.showWait( false );
if ( data && data.success ) {
// Optionally show a success message or update UI
} else {
self.showScanError( __( 'Saving failed.', 'accessibility-checker' ) );
}
} )
.catch( () => {
self.showWait( false );
self.showScanError( __( 'Error saving scan results.', 'accessibility-checker' ) );
} );
}

/**
* Show an error message in the scan panel or as an alert fallback.
* @param {string} message
*/
showScanError( message ) {
const summary = document.querySelector( '.edac-highlight-panel-controls-summary' );
if ( summary ) {
summary.textContent = message;
summary.classList.add( 'edac-error' );
}
}
}

// Some systems (Cloudflare Rocket Loader) defers scripts for performance but that can
Expand Down
Loading