Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
ded54fd
Add a SystemInfo class and tests for it
pattonwebz May 4, 2026
736b933
Add the extra context data to the activate and checking crons
pattonwebz May 4, 2026
948f88d
Update tests to cover actual functionality of the systeminfo getters
pattonwebz May 4, 2026
17d9556
Move SystemInfo class to it's own namespace location
pattonwebz May 6, 2026
6ff279b
Enforce always array even on parse failure for active theme and plugi…
pattonwebz May 6, 2026
261f8d9
Use raw plugin headers and JSON-string fallbacks in SystemInfo context
Copilot May 12, 2026
fe127ba
Merge pull request #1695 from equalizedigital/release/1.41.0
pattonwebz May 14, 2026
5a0c3ef
Replaced inline permission callback with a named method for improved …
pattonwebz May 14, 2026
e98494e
Merge pull request #1679 from equalizedigital/william/add-extra-compa…
pattonwebz May 14, 2026
7239efc
Merge pull request #1697 from equalizedigital/william/no-issue/make-g…
pattonwebz May 14, 2026
16a2132
Add: support for named anchors as jump targets in link validation
SteveJonesDev May 15, 2026
cd8449a
Add: enhance link validation to handle named anchors and empty href c…
SteveJonesDev May 15, 2026
e927611
Add tests for the API endpoints that power the stats requests
pattonwebz May 15, 2026
bf5948b
Don't include the 'tools' directory in code coverage checking
pattonwebz May 15, 2026
997e678
chore: improve REST API test performance and assertions
pattonwebz May 15, 2026
8f87dab
test: align REST API stats assertions with actual response shape
Copilot May 15, 2026
5afbb03
test: refine stats value assertion style in endpoint test
Copilot May 15, 2026
1bea54e
Merge pull request #1699 from equalizedigital/william/add-some-tests-…
pattonwebz May 15, 2026
b1c4426
Tweak some of the new test setup for rest api endpoints
pattonwebz May 18, 2026
4025c07
Merge branch 'william/add-some-tests-for-rest-api-callbacks' of githu…
pattonwebz May 18, 2026
6622d54
Refactor REST API stats validation in tests
pattonwebz May 18, 2026
5ee4148
Merge pull request #1701 from equalizedigital/william/add-some-tests-…
pattonwebz May 18, 2026
fbbe6f9
docs: regenerate hooks docs
github-actions[bot] May 18, 2026
9da8dd6
Add some checks for linkimproper anchors to only skip them if they ar…
pattonwebz May 18, 2026
a0ff0f7
Add some test cases for bypassed link improper when it's an anchor
pattonwebz May 18, 2026
caa8b4b
Add one more test case to cover named anchor that matches parity with…
pattonwebz May 18, 2026
2501f1c
Merge pull request #1702 from equalizedigital/automation/regenerate-h…
SteveJonesDev May 18, 2026
a9e770d
Merge pull request #1698 from equalizedigital/steve/pro-808-improper-…
SteveJonesDev May 18, 2026
c5fd3bb
Bump version * Version: 1.41.0 -> 1.42.0
pattonwebz May 18, 2026
c324d0e
Resolve release 1.42.0 review follow-ups (tests, changelog, lockfile …
Copilot May 18, 2026
d9ae994
Add changelog entry for v1.42.0
pattonwebz May 18, 2026
8431fe0
Merge branch 'release/1.42.0' of github.com:equalizedigital/accessibi…
pattonwebz May 18, 2026
4a395ff
Add extra safety include for the get_plugin_data function and make ar…
pattonwebz May 18, 2026
61f69c6
Add test to ensure plugins are valid and active when returned
pattonwebz May 18, 2026
6131937
Merge branch 'main' into release/1.42.0
pattonwebz May 18, 2026
ac471ce
Add role="none" support alongside role="presentation" in image alt ch…
claude May 19, 2026
532ad2a
Use role token list parsing in image alt checks for consistency
claude May 19, 2026
694efa1
Add role="none" and multi-value token tests to image alt check test s…
claude May 19, 2026
3ad6868
Move role="none/presentation" exclusion to rule selectors for img alt…
claude May 19, 2026
01e5505
Merge pull request #1704 from equalizedigital/claude/update-gutenberg…
SteveJonesDev May 19, 2026
51815d3
Update POT translation file
pattonwebz May 19, 2026
41c4dc5
Merge pull request #1705 from equalizedigital/update-translations/dev…
pattonwebz May 19, 2026
baf9eca
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
ec78486
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
f825f99
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
a923f17
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
4147b2a
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
7f9a98e
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
1f77733
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
9541607
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
2abac32
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
c12e2eb
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
c355c65
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
6fca3e2
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
642a2aa
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
bbf0d98
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
5a91cc2
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
9ebf731
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
8206cbc
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
568790c
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
c804849
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
1ab2ed1
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
05e4d28
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
94628a0
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
5ce7d71
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
fe45b7b
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
fe679a5
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
eb4d3a3
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
da8da08
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
ff8f64d
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
472a6f7
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
2bd84af
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
833001c
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
0b94840
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
f024dd9
PTC accessibility-checker (1985): Automatic Translations May 19, 2026…
May 19, 2026
54e2803
Merge pull request #1706 from equalizedigital/ptc_1985_automatic_tran…
pattonwebz May 19, 2026
a01362f
Merge remote-tracking branch 'origin/develop' into release/1.42.0
pattonwebz May 19, 2026
fc890cc
Merge remote-tracking branch 'origin/release/1.42.0' into release/1.42.0
pattonwebz May 19, 2026
77b9a85
Add changelog entry for new role="none" handling
pattonwebz May 19, 2026
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
4 changes: 2 additions & 2 deletions accessibility-checker.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* Plugin Name: Accessibility Checker
* Plugin URI: https://a11ychecker.com
* Description: Audit and check your website for accessibility before you hit publish. In-post accessibility scanner and guidance.
* Version: 1.41.0
* Version: 1.42.0
* Requires PHP: 7.4
* Author: Equalize Digital
* Author URI: https://equalizedigital.com
Expand All @@ -36,7 +36,7 @@

// Current plugin version.
if ( ! defined( 'EDAC_VERSION' ) ) {
define( 'EDAC_VERSION', '1.41.0' );
define( 'EDAC_VERSION', '1.42.0' );
}

// Current database version.
Expand Down
5 changes: 5 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
*** Accessibility Checker ***

2026-05-18 - version 1.42.0
* Updated - add support for role="none" in several of the link and image alt related rules.
* Updated - added support for named anchors as jump links.
* New - added system info checker for compatibility checking of plugins and themes.

2026-05-13 - version 1.41.0
* Updated - the possible heading rule now accounts for elements with role="heading" appropriately.
* Fix - several language translations are now properly detected by WordPress when using them.
Expand Down
34 changes: 17 additions & 17 deletions docs/hooks.md

Large diffs are not rendered by default.

19 changes: 9 additions & 10 deletions includes/classes/MyDot/Connector.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace EqualizeDigital\AccessibilityChecker\MyDot;

use EqualizeDigital\AccessibilityChecker\Admin\AdminPage\ConnectedServicesPage;
use EqualizeDigital\AccessibilityChecker\SystemInfo\SystemInfo;

/**
* Class Connector
Expand Down Expand Up @@ -264,15 +265,14 @@ private function activate_license() {
}

$api_params = [
'edd_action' => 'activate_license',
'license' => $license,
'item_id' => self::PRODUCT_ID,
'url' => home_url(),
'environment' => function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production',
'wp_version' => get_bloginfo( 'version' ),
'php_version' => phpversion(),
'edd_action' => 'activate_license',
'license' => $license,
'item_id' => self::PRODUCT_ID,
'url' => home_url(),
];

$api_params = array_merge( $api_params, SystemInfo::get_license_request_context() );

$response = wp_remote_post(
self::get_api_endpoint(),
[
Expand Down Expand Up @@ -432,12 +432,11 @@ public function periodic_check_license() {
'item_id' => self::PRODUCT_ID,
'item_name' => rawurlencode( self::PRODUCT_NAME ),
'url' => home_url(),
'environment' => function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production',
'edac_version' => defined( 'EDAC_VERSION' ) ? EDAC_VERSION : '0.0.0',
'wp_version' => get_bloginfo( 'version' ),
'php_version' => phpversion(),
];

$api_params = array_merge( $api_params, SystemInfo::get_license_request_context() );

// Call the custom API.
$response = wp_remote_post(
self::get_api_endpoint(),
Expand Down
5 changes: 3 additions & 2 deletions includes/classes/Rules/Rule/ImgAltEmptyRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ public static function get_rule(): array {
),
'why_it_matters' => esc_html__( 'Screen readers rely on alternative text to describe images to users who cannot see them. If the alt attribute is empty, it signals that the image is decorative and should be skipped. However, if a meaningful image has an empty alt attribute, users with visual impairments will miss important information. Proper use of alternative text improves accessibility and ensures all users can understand the content.', 'accessibility-checker' ),
'how_to_fix' => sprintf(
// translators: %1$s is <code>alt=""</code> and %2$s is <code>role="presentation"</code>.
esc_html__( 'Review the image to determine if it is decorative. If it is decorative, it is correct to use an empty %1$s attribute and you can dismiss this warning by using the "Ignore" feature in Accessibility Checker or adding %2$s to the image and rescanning the page. If the image conveys information, add descriptive alt text that communicates the image\'s purpose or meaning.', 'accessibility-checker' ),
// translators: %1$s is <code>alt=""</code>, %2$s is <code>role="presentation"</code>, and %3$s is <code>role="none"</code>.
esc_html__( 'Review the image to determine if it is decorative. If it is decorative, it is correct to use an empty %1$s attribute and you can dismiss this warning by using the "Ignore" feature in Accessibility Checker or adding %2$s or %3$s to the image and rescanning the page. If the image conveys information, add descriptive alt text that communicates the image\'s purpose or meaning.', 'accessibility-checker' ),
'<code>alt=""</code>',
'<code>role="presentation"</code>',
'<code>role="none"</code>',
),
'references' => [
[
Expand Down
167 changes: 167 additions & 0 deletions includes/classes/SystemInfo/SystemInfo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
<?php
/**
* System information helpers.
*
* @package Accessibility_Checker
*/

namespace EqualizeDigital\AccessibilityChecker\SystemInfo;

use WP_Theme;

/**
* Collects active plugin and theme information.
*/
class SystemInfo {

/**
* Returns active plugins with name, slug, and version.
*
* @return array<int, array<string, string>>
*/
public static function get_active_plugins() {
if ( ! function_exists( 'get_plugin_data' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}

$active_plugins = [];
$plugins = wp_get_active_and_valid_plugins();

if ( is_array( $plugins ) ) {
foreach ( $plugins as $plugin_path ) {
$plugin_data = get_plugin_data( $plugin_path, false, false );
if ( is_array( $plugin_data ) ) {
$active_plugins[] = [
'name' => $plugin_data['Name'] ?? '',
'slug' => self::get_plugin_slug_from_path( $plugin_path ),
'version' => $plugin_data['Version'] ?? '',
];
}
}
}

return $active_plugins;
}
Comment thread
pattonwebz marked this conversation as resolved.

/**
* Gets the plugin slug from a plugin file path.
*
* @param string $plugin_path Path to a plugin file.
* @return string
*/
public static function get_plugin_slug_from_path( $plugin_path ) {
if ( ! is_string( $plugin_path ) || '' === $plugin_path ) {
return '';
}

$relative = plugin_basename( $plugin_path );
$dir = dirname( $relative );

if ( '.' !== $dir ) {
return $dir;
}

return basename( $relative, '.php' );
}

/**
* Returns active theme information, including parent data for child themes.
*
* @return array<string, mixed>
*/
public static function get_active_theme() {
$theme_data = wp_get_theme();

$active_theme = self::get_theme_data_collection( $theme_data );

$active_theme['accessibility_ready'] = self::is_theme_accessibility_ready( $theme_data );

$active_theme['parent_theme'] = [];
if ( $theme_data->parent() ) {
$active_theme['parent_theme'] = self::get_theme_data_collection( $theme_data->parent() );
}

return $active_theme;
}

/**
* Gets theme details as a normalized collection.
*
* @param mixed $theme Theme object.
* @return array<string, mixed>
*/
public static function get_theme_data_collection( $theme ) {
if ( ! is_a( $theme, '\\WP_Theme' ) ) {
return [];
}

return [
'name' => $theme->get( 'Name' ) ?? '',
'slug' => $theme->get_stylesheet() ?? '',
'version' => $theme->get( 'Version' ) ?? '',
'tags' => $theme->get( 'Tags' ) ?? [],
];
}

/**
* Checks whether theme or parent theme is tagged accessibility-ready.
*
* @param WP_Theme $theme_data Theme object to check.
* @return bool
*/
public static function is_theme_accessibility_ready( WP_Theme $theme_data ) {
$tags = is_array( $theme_data->get( 'Tags' ) ) ? $theme_data->get( 'Tags' ) : [];

if ( $theme_data->parent() ) {
$parent_tags = $theme_data->parent()->get( 'Tags' );
$tags = array_merge( $tags, is_array( $parent_tags ) ? $parent_tags : [] );
}

return in_array( 'accessibility-ready', $tags, true );
}

/**
* Gets the current WordPress environment type.
*
* @return string
*/
public static function get_environment_type() {
return function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production';
}

/**
* Gets the current WordPress version.
*
* @return string
*/
public static function get_wordpress_version() {
return (string) get_bloginfo( 'version' );
}

/**
* Gets the current PHP version.
*
* @return string
*/
public static function get_php_version() {
return (string) phpversion();
}

/**
* Gets a payload-ready set of system fields for license API requests.
*
* @return array<string, mixed>
*/
public static function get_license_request_context() {
$active_plugins = wp_json_encode( self::get_active_plugins() );
$active_theme = wp_json_encode( self::get_active_theme() );

return [
'environment' => self::get_environment_type(),
'wp_version' => self::get_wordpress_version(),
'php_version' => self::get_php_version(),
'active_plugins' => false !== $active_plugins ? $active_plugins : '[]',
'active_theme' => false !== $active_theme ? $active_theme : '{}',
];
}
}
26 changes: 18 additions & 8 deletions includes/classes/class-rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,7 @@ function () use ( $ns, $version ) {
[
'methods' => 'GET',
'callback' => [ $this, 'get_scans_stats' ],
'permission_callback' => function ( $request ) {
if ( Connector::validate_jwt_token_in_request_with_fallback( $request ) ) {
// Only allow if the site is still registered (site_id present).
$site_id = (string) get_option( 'edac_site_id', '' );
return '' !== $site_id;
}
return current_user_can( 'edit_posts' );
},
'permission_callback' => [ $this, 'can_get_scans_stats' ],
]
);
}
Expand Down Expand Up @@ -365,6 +358,23 @@ function () use ( $ns, $version ) {
);
}

/**
* Determine whether the current request may access the scans stats endpoint.
*
* @param \WP_REST_Request $request REST request.
*
* @return bool
*/
public function can_get_scans_stats( \WP_REST_Request $request ): bool {
if ( Connector::validate_jwt_token_in_request_with_fallback( $request ) ) {
// Only allow if the site is still registered (site_id present).
$site_id = (string) get_option( 'edac_site_id', '' );
return '' !== $site_id;
}

return current_user_can( 'edit_posts' );
}

/**
* REST handler to clear issues results for a given post ID.
*
Expand Down
Binary file modified languages/accessibility-checker-ar.mo
Binary file not shown.
Loading
Loading