Skip to content

Commit

Permalink
πŸ”§ fix(README.md): update documentation to reflect changes in version …
Browse files Browse the repository at this point in the history
…1.0.6 of the plugin

πŸ”§ fix(a11y-init.js): refactor code to inject axe-core script into the scoped iframe for better performance and security
πŸ”§ fix(a11y-tester.php): update plugin version to 1.0.6 and remove axe-core script from enqueueing as it will be loaded dynamically into the iframe
πŸ“ docs(readme.txt): add changelog entry for version 1.0.6, highlighting the implementation of iframe scoping for secure accessibility tests and code refactoring for improved performance and security
  • Loading branch information
skullzarmy committed Oct 25, 2023
1 parent 7f6c13a commit 77b23f1
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Axe-core is an industry standard for web accessibility, providing automated acce

### πŸƒβ€β™€οΈ How Does It Work?

Unlike typical client-side implementations, our plugin doesn't scan the admin edit screen where it resides. Instead, when you click the 'Run A11y Test' button in the A11y Tester meta box on your WordPress admin dashboard, an AJAX request is sent to the server. The plugin then uses axe-core to perform an accessibility scan on the full URL of the selected page or post. The server processes the scan and returns the results, which are displayed directly within the A11y Tester meta box, sorted by impact level for your convenience.
Starting from version 1.0.6, the plugin creates a scoped iframe to securely run the accessibility tests. When you click the 'Run A11y Test' button in the A11y Tester meta box on your WordPress admin dashboard, an AJAX request is sent to the server to retrieve the permalink. The plugin then uses axe-core to perform an accessibility scan on the full URL of the selected page or post within a scoped iframe. The server processes the scan and returns the results, which are displayed directly within the A11y Tester meta box, sorted by impact level for your convenience.

### πŸ› οΈ Future Plans for Customization

Expand Down
55 changes: 36 additions & 19 deletions a11y-init.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,19 @@ async function fetchPageContent(url) {
return doc;
}

function injectAxeScript(iframe) {
return new Promise((resolve, reject) => {
const script = iframe.contentWindow.document.createElement("script");
script.src = "https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.3.3/axe.min.js";
script.onload = resolve;
script.onerror = reject;
iframe.contentWindow.document.head.appendChild(script);
});
}

async function runA11yTests(event) {
event.preventDefault();

// Fetching the postID and security nonce
const postID = document.querySelector("input#post_ID").value;
const requestData = {
method: "POST",
Expand All @@ -174,7 +183,6 @@ async function runA11yTests(event) {
body: `action=run_a11y_test&post_id=${postID}&security=${wpData.nonce}`,
};

// Create and show the spinner for loading
const spinner = document.createElement("span");
spinner.className = "spinner is-active";
const metaBoxInsideDiv = document.querySelector("#a11y_meta_box .inside");
Expand All @@ -183,40 +191,47 @@ async function runA11yTests(event) {
}

try {
// Fetching the URL from the server
const response = await fetch(wpData.ajax_url, requestData);
const data = await response.json();
if (!response.ok) {
throw new Error(`Server responded with status ${response.status}`);
}

// Fetching the content of the specified URL
const data = await response.json();
const docContent = await fetchPageContent(data.data.url);

// Creating an iframe and appending it to the body
const iframe = document.createElement("iframe");
iframe.style.display = "none";
iframe.id = "a11yTestIframe";
iframe.style.position = "absolute";
iframe.style.opacity = "0";
iframe.style.width = "1px";
iframe.style.height = "1px";
iframe.style.border = "none";
document.body.appendChild(iframe);

// Writing the fetched HTML content into the iframe
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(docContent.documentElement.outerHTML);
iframe.contentWindow.document.close();

// Running axe.run when iframe is fully loaded
await new Promise((resolve, reject) => {
const script = iframe.contentWindow.document.createElement("script");
script.src = "https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.3.3/axe.min.js";
script.onload = resolve;
script.onerror = reject;
iframe.contentWindow.document.head.appendChild(script);
});

iframe.onload = () => {
axe.run(iframe.contentWindow.document, (err, results) => {
iframe.contentWindow.axe.run((err, results) => {
if (err) throw err;

// Remove spinner
if (spinner) spinner.remove();

// Removing any previous results
const oldResults = document.getElementById("a11y-results");
if (oldResults) oldResults.remove();

// Creating a new container for the results
const container = document.createElement("div");
container.id = "a11y-results";

// Adding summary and details to the container
const summarySection = createSummarySection(results);
container.appendChild(summarySection);

Expand All @@ -226,19 +241,21 @@ async function runA11yTests(event) {

appendViolationSections(container, results.violations);

// Appending the container to the meta box
if (metaBoxInsideDiv) {
metaBoxInsideDiv.appendChild(container);
}

// Removing the iframe when done
iframe.remove();
document.body.removeChild(iframe);
});
};
} catch (err) {
console.error("Error running accessibility tests:", err);

// Remove spinner if an error occurs
const errorMsg = document.createElement("div");
errorMsg.className = "error";
errorMsg.textContent = `Error: ${err.message}`;
if (metaBoxInsideDiv) {
metaBoxInsideDiv.appendChild(errorMsg);
}
if (spinner) spinner.remove();
}
}
Expand Down
6 changes: 3 additions & 3 deletions a11y-tester.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
/**
* Plugin Name: A11y Tester
* Description: A plugin to test accessibility of any page or post.
* Version: 1.0.4
* Version: 1.0.6
* Author: Joe Peterson
* Author URI: https://joepeterson.work
*/

function enqueue_a11y_scripts($hook)
{
if ('post.php' === $hook || 'post-new.php' === $hook) {
wp_enqueue_script('axe-core', 'https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.8.2/axe.min.js', array(), '4.8.2', true);
wp_enqueue_script('a11y-init', plugin_dir_url(__FILE__) . 'a11y-init.js', array('axe-core', 'jquery'), '1.0', true);
// axe-core is omitted as it will be loaded dynamically into the iframe
wp_enqueue_script('a11y-init', plugin_dir_url(__FILE__) . 'a11y-init.js', array('jquery'), '1.0', true);

$nonce = wp_create_nonce('a11y_nonce');
wp_localize_script('a11y-init', 'wpData', array('ajax_url' => admin_url('admin-ajax.php'), 'nonce' => $nonce));
Expand Down
9 changes: 9 additions & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ Initial release, no upgrades required.
= 1.0.5 =
* Restyled results summary and table

= 1.0.6 =
* Implemented iframe scoping to securely run accessibility tests.
* Enhanced performance and security by refactoring the iframe generation and execution code.


== License ==

This WordPress Plugin is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License or any later version.
Expand All @@ -97,6 +102,10 @@ Contributions, issues, and feature requests are welcome! For support, visit the

== Changelog ==

= 1.0.6 =
* Implemented iframe scoping to securely run accessibility tests.
* Enhanced performance and security by refactoring the iframe generation and execution code.

= 1.0.5 =
* Restyled results summary and table.

Expand Down

0 comments on commit 77b23f1

Please sign in to comment.