PluginProbe ʕ •ᴥ•ʔ
Web Accessibility Toolkit – Accessibility Checker & ARIA for WCAG, Section 508 & ADA Compliance / 1.4.1
Web Accessibility Toolkit – Accessibility Checker & ARIA for WCAG, Section 508 & ADA Compliance v1.4.1
trunk 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.10 1.5.11 1.5.12 1.5.13 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6
aria-accessibility-toolkit / includes / class-admin.php
aria-accessibility-toolkit / includes Last commit date
class-admin.php 11 months ago index.php 11 months ago
class-admin.php
796 lines
1 <?php
2
3 // Exit if accessed directly
4 if ( ! defined( 'ABSPATH' ) ) exit;
5
6 class ARIAAT_Admin {
7
8 /**
9 * Constructor to hook the necessary actions.
10 */
11 public function __construct() {
12
13 add_action( 'admin_enqueue_scripts', [ $this, 'admin_scripts_styles' ] );
14
15 add_action('admin_menu', [$this, 'register_admin_menu']);
16 add_action('admin_init', [$this, 'register_settings']);
17
18 }
19
20 public function admin_scripts_styles( $hook ) {
21 $v = ARIAATVERSION;
22 //$v = time();
23
24 if ( strpos( $hook, 'ariaat' ) !== false ) {
25 wp_enqueue_script(
26 'ariaat-admin',
27 ARIAATURL . 'assets/js/ariaat-admin.js',
28 ['jquery'],
29 $v,
30 true
31 );
32
33 wp_localize_script('ariaat-admin', 'ARIAAT_Data', [
34 'aria_options' => array_map(function($item) {
35 return [
36 'label' => $item['label'],
37 ];
38 }, $this->get_aria_attributes()),
39 'role_options' => array_map(function($item) {
40 return [
41 'label' => $item['label'],
42 ];
43 }, $this->get_role_options()),
44 ]);
45
46 wp_enqueue_style( 'ariaat-style', ARIAATURL .'assets/css/ariaat-admin.css', false, $v );
47 }
48 }
49
50 public function register_admin_menu() {
51 add_options_page('ARIA Toolkit', 'ARIA Toolkit', 'manage_options', 'ariaat', [$this, 'render_settings_page']);
52 }
53
54 public function register_settings() {
55
56 register_setting('ariaat_general_group', 'ariaat_general_settings', [$this, 'sanitize_general_settings']);
57
58 register_setting('ariaat_aria_group', 'ariaat_aria_mappings', [$this, 'sanitize_array']);
59 register_setting('ariaat_aria_group', 'ariaat_aria_menus', [$this, 'sanitize_menu_selection']);
60
61 register_setting('ariaat_role_group', 'ariaat_role_mappings', [$this, 'sanitize_array']);
62 register_setting('ariaat_role_group', 'ariaat_role_menus', [$this, 'sanitize_menu_selection']);
63
64 register_setting('ariaat_contrast_group', 'ariaat_contrast_mappings', [$this, 'sanitize_array']);
65
66 register_setting('ariaat_images_group', 'ariaat_image_settings', [$this, 'sanitize_array']);
67
68 }
69
70
71 public function get_all_menus() {
72 $menus = wp_get_nav_menus();
73 $output = [];
74 foreach ($menus as $menu) {
75 $output[$menu->term_id] = $menu->name;
76 }
77 return $output;
78 }
79
80
81 public function render_settings_page() {
82
83 $active_tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'general';
84 ?>
85 <div class="wrap ariaat">
86 <h1>ARIA & Accessibility Toolkit <span><?php echo esc_attr( ARIAATVERSION ); ?></span></h1>
87
88 <div class="main_content">
89 <h2 class="nav-tab-wrapper">
90 <a href="?page=ariaat&tab=general" class="nav-tab <?php echo $active_tab == 'general' ? 'nav-tab-active' : '' ?>">General</a>
91 <a href="?page=ariaat&tab=aria" class="nav-tab <?php echo $active_tab == 'aria' ? 'nav-tab-active' : '' ?>">ARIA</a>
92 <a href="?page=ariaat&tab=roles" class="nav-tab <?php echo $active_tab == 'roles' ? 'nav-tab-active' : '' ?>">Roles</a>
93 <a href="?page=ariaat&tab=contrast" class="nav-tab <?php echo $active_tab == 'contrast' ? 'nav-tab-active' : '' ?>">Contrast</a>
94 <a href="?page=ariaat&tab=images" class="nav-tab <?php echo $active_tab == 'images' ? 'nav-tab-active' : '' ?>">Images</a>
95 <?php do_action( 'ariaat_after_nav_tab_wrapper', $active_tab ); ?>
96 </h2>
97
98
99 <form method="post" action="options.php">
100 <?php
101 if ($active_tab === 'general') {
102 settings_fields('ariaat_general_group');
103 $settings = get_option('ariaat_general_settings', []);
104
105 ?>
106 <h3>Frontend Accessibility Checker</h3>
107 <table class="form-table general-table">
108 <tr>
109 <th scope="row">Frontend Checker</th>
110 <td>
111 <label>
112 <input type="checkbox" name="ariaat_general_settings[enable_frontend_checker]" value="1" <?php checked($settings['enable_frontend_checker'] ?? '', '1'); ?> />
113 Display the frontend accessibility checker.
114 </label>
115 <p class="description">Toggle visibility of the accessibility checker overlay on the frontend for testing purposes. Enabling this will make it visible to logged-in admins only.</p>
116 </td>
117 </tr>
118 </table>
119
120 <h3>General Accessibility Enhancements</h3>
121
122 <table class="form-table general-table">
123
124 <tr>
125 <th scope="row">Language</th>
126 <td>
127 <input type="text" name="ariaat_general_settings[language]" value="<?php echo esc_attr($settings['language'] ?? ''); ?>" placeholder="e.g. en, en-AU" class="regular-text" />
128 <p class="description">If your site is already setting the Language, this will override it.</p>
129 </td>
130 </tr>
131
132 <tr>
133 <th scope="row">Skip Link Target</th>
134 <td>
135 <input type="text" name="ariaat_general_settings[skip_link]" value="<?php echo esc_attr($settings['skip_link'] ?? ''); ?>" class="regular-text" placeholder=".main-content" />
136 <p class="description">Enter a CSS selector for the main content area (e.g. <code>.main-content</code>). If provided, a “Skip to content” link will be added at the top of the page but will only be visible to keyboard and screen reader users.</p>
137 </td>
138 </tr>
139
140 <tr>
141 <th scope="row">Show Focus Outline</th>
142 <td>
143 <label>
144 <input type="checkbox" name="ariaat_general_settings[focus_outline]" value="1" <?php checked($settings['focus_outline'] ?? '', '1'); ?> />
145 Ensures keyboard focus outlines are visible for better navigation.
146 </label>
147 </td>
148 </tr>
149
150 <tr>
151 <th scope="row">Fix Tab Order</th>
152 <td>
153 <label>
154 <input type="checkbox" name="ariaat_general_settings[fix_tabindex]" value="1" <?php checked($settings['fix_tabindex'] ?? '', '1'); ?> />
155 Remove tabindex values greater than 0 to maintain a logical focus order.
156 </label>
157 </td>
158 </tr>
159
160 <tr>
161 <th scope="row">Make Viewport Scalable</th>
162 <td>
163 <label>
164 <input type="checkbox" name="ariaat_general_settings[make_viewport_scalable]" value="1" <?php checked($settings['make_viewport_scalable'] ?? '', '1'); ?> />
165 Remove <code>user-scalable=no</code> from the viewport meta tag to allow pinch-zooming.
166 </label>
167 </td>
168 </tr>
169
170
171 </table>
172
173 <?php
174 } else if ($active_tab === 'aria') {
175 settings_fields('ariaat_aria_group');
176 $items = get_option('ariaat_aria_mappings', []);
177 ?>
178
179 <h3>Menu ARIA Labels</h3>
180 <p class="desc">
181 Select your Nav menus to automatically apply <code>aria-label</code> attributes to the links within that menu.
182 </p>
183
184 <?php
185 $all_menus = wp_get_nav_menus();
186 $menus = apply_filters('ariaat_allowed_menus', array_slice($all_menus, 0, 2), $all_menus);
187 $selected = get_option('ariaat_aria_menus', []);
188
189 foreach ($menus as $menu) {
190 $checked = in_array($menu->term_id, $selected);
191 ?>
192 <label style="display:block; margin-bottom:4px;">
193 <input type="checkbox" name="ariaat_aria_menus[]" value="<?php echo esc_attr($menu->term_id); ?>" <?php checked($checked); ?> />
194 <?php echo esc_html($menu->name); ?>
195 </label>
196 <?php
197 }
198 ?>
199 <hr>
200 <h3>Custom ARIA Attributes</h3>
201 <p class="desc">
202 Add ARIA attributes to specific elements on your site using CSS selectors.
203 </p>
204 <table class="form-table" id="aria-table">
205 <thead>
206 <tr>
207 <th>HTML Selector</th>
208 <th>ARIA Attribute</th>
209 <th>Value</th>
210 <th></th>
211 </tr>
212 </thead>
213 <tbody>
214 <?php foreach ($items as $index => $item) : ?>
215 <tr>
216 <td><input type="text" name="ariaat_aria_mappings[<?php echo esc_attr($index); ?>][selector]" value="<?php echo esc_attr($item['selector']); ?>" class="regular-text" /></td>
217 <td>
218 <select name="ariaat_aria_mappings[<?php echo esc_attr($index); ?>][attribute]">
219 <?php foreach ($this->get_aria_attributes() as $attr => $attr_item): ?>
220 <option value="<?php echo esc_attr($attr); ?>" <?php selected($item['attribute'], $attr); ?>>
221 <?php echo esc_html($attr_item['label']); ?>
222 </option>
223 <?php endforeach; ?>
224 </select>
225 </td>
226 <td><input type="text" name="ariaat_aria_mappings[<?php echo esc_attr($index); ?>][value]" value="<?php echo esc_attr($item['value']); ?>" class="regular-text" /></td>
227 <td><button type="button" class="button remove-row">Remove</button></td>
228 </tr>
229 <?php endforeach; ?>
230 </tbody>
231 </table>
232
233 <p><button type="button" class="button" id="add-aria-row">Add ARIA Attribute</button></p>
234 <?php
235
236
237 } elseif ($active_tab == 'roles') {
238 settings_fields('ariaat_role_group');
239 $items = get_option('ariaat_role_mappings', []);
240 ?>
241
242 <h3>Menu Roles</h3>
243 <p class="desc">
244 Add a <code>role="navigation"</code> to selected menus for better screen reader support.
245 </p>
246
247 <?php
248 $all_menus = wp_get_nav_menus();
249 $menus = apply_filters('ariaat_allowed_menus', array_slice($all_menus, 0, 2), $all_menus);
250 $selected_roles = get_option('ariaat_role_menus', []);
251
252 foreach ($menus as $menu) {
253 $checked = in_array($menu->term_id, $selected_roles);
254 ?>
255 <label style="display:block; margin-bottom:4px;">
256 <input type="checkbox" name="ariaat_role_menus[]" value="<?php echo esc_attr($menu->term_id); ?>" <?php checked($checked); ?> />
257 <?php echo esc_html($menu->name); ?>
258 </label>
259 <?php
260 }
261 ?>
262 <hr>
263 <h3>Custom Roles</h3>
264 <p class="desc">
265 Assign ARIA roles to specific elements on your site using CSS selectors.
266 </p>
267
268 <table class="form-table" id="role-table">
269 <thead>
270 <tr>
271 <th>HTML Selector</th>
272 <th>Role</th>
273 <th></th>
274 </tr>
275 </thead>
276 <tbody>
277 <?php foreach ($items as $index => $item) : ?>
278 <tr>
279 <td><input type="text" name="ariaat_role_mappings[<?php echo esc_attr($index); ?>][selector]" value="<?php echo esc_attr($item['selector']); ?>" class="regular-text" /></td>
280 <td>
281 <select name="ariaat_role_mappings[<?php echo esc_attr($index); ?>][role]">
282 <?php foreach ($this->get_role_options() as $role => $role_item): ?>
283 <option value="<?php echo esc_attr($role); ?>" <?php selected($item['role'], $role); ?>>
284 <?php echo esc_html($role_item['label']); ?>
285 </option>
286 <?php endforeach; ?>
287 </select>
288 </td>
289 <td><button type="button" class="button remove-row">Remove</button></td>
290 </tr>
291 <?php endforeach; ?>
292 </tbody>
293 </table>
294
295 <p><button type="button" class="button" id="add-role-row">Add Role</button></p>
296 <?php
297
298
299 } else if( $active_tab == 'contrast' ) {
300 settings_fields('ariaat_contrast_group');
301 $items = get_option('ariaat_contrast_mappings', []);
302 ?>
303
304 <h3>High Contrast Adjustments</h3>
305 <p class="desc">
306 Apply custom foreground and background colors to specific elements to improve visual contrast and accessibility. This is especially useful for meeting WCAG contrast ratio requirements and making content easier to read for users with visual impairments.
307 </p>
308
309 <table class="form-table" id="contrast-table">
310 <thead>
311 <tr>
312 <th>HTML Selector</th>
313 <th>Text</th>
314 <th>Background</th>
315 <th>Contrast</th>
316 <th></th>
317 </tr>
318 </thead>
319 <tbody>
320 <?php foreach ($items as $index => $item) : ?>
321 <tr>
322 <td><input type="text" name="ariaat_contrast_mappings[<?php echo esc_attr( $index ) ?>][selector]" value="<?php echo esc_attr($item['selector']) ?>" class="regular-text" /></td>
323 <td>
324 <input type="color"
325 id="text-color-picker-<?php echo esc_attr($index); ?>"
326 class="text-color"
327 data-index="<?php echo esc_attr($index); ?>"
328 value="<?php echo esc_attr($item['color']); ?>"
329 >
330 <input type="hidden"
331 name="ariaat_contrast_mappings[<?php echo esc_attr($index); ?>][color]"
332 id="real-text-color-<?php echo esc_attr($index); ?>"
333 value="<?php echo esc_attr($item['color']); ?>"
334 >
335 <button type="button" class="button clear-color" data-target="<?php echo esc_attr($index); ?>" data-type="text">Clear</button>
336 </td>
337 <td>
338 <input type="color"
339 id="bg-color-picker-<?php echo esc_attr($index); ?>"
340 class="bg-color"
341 data-index="<?php echo esc_attr($index); ?>"
342 value="<?php echo esc_attr($item['background']); ?>"
343 >
344 <input type="hidden"
345 name="ariaat_contrast_mappings[<?php echo esc_attr($index); ?>][background]"
346 id="real-bg-color-<?php echo esc_attr($index); ?>"
347 value="<?php echo esc_attr($item['background']); ?>"
348 >
349 <button type="button" class="button clear-color" data-target="<?php echo esc_attr($index); ?>" data-type="bg">Clear</button>
350 </td>
351 <td>
352 <div class="contrast-result" id="contrast-result-<?php echo esc_attr( $index ); ?>"></div>
353 </td>
354
355 <td><button type="button" class="button remove-row">Remove</button></td>
356 </tr>
357 <?php endforeach; ?>
358 </tbody>
359 </table>
360 <p><button type="button" class="button" id="add-contrast-row">Add Contrast Item</button></p>
361 <?php
362
363 } else if ($active_tab === 'images') {
364 settings_fields('ariaat_images_group');
365 $settings = get_option('ariaat_image_settings', []);
366
367 $show_all = isset($_POST['ariaat_image_settings']['show_all'])
368 ? boolval($_POST['ariaat_image_settings']['show_all'])
369 : (!empty($settings['show_all']));
370
371 $paged = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
372 $per_page = 5;
373 $offset = ($paged - 1) * $per_page;
374
375 $meta_query = $show_all ? [] : [
376 'relation' => 'OR',
377 [
378 'key' => '_wp_attachment_image_alt',
379 'value' => '',
380 'compare' => '='
381 ],
382 [
383 'key' => '_wp_attachment_image_alt',
384 'value' => ' ',
385 'compare' => '='
386 ],
387 [
388 'key' => '_wp_attachment_image_alt',
389 'compare' => 'NOT EXISTS'
390 ]
391 ];
392
393 $query = new WP_Query([
394 'post_type' => 'attachment',
395 'post_mime_type' => 'image',
396 'post_status' => 'inherit',
397 'posts_per_page' => $per_page,
398 'offset' => $offset,
399 'meta_query' => $meta_query
400 ]);
401
402 $attachments = $query->posts;
403 $total = $query->found_posts;
404 $total_pages = ceil($total / $per_page);
405 ?>
406
407 <h3>Images Missing Alt Text</h3>
408 <p class="desc">
409 Lists images on your site that are missing alt text. Add the alt text below and click "Save" to update each image. Does not scan images that are within themes or plugins, only images from your WordPress Media Library.
410 </p>
411 <p>
412 <label>
413 <input type="checkbox" name="ariaat_image_settings[show_all]" value="1"
414 <?php checked($settings['show_all'] ?? '', '1'); ?> />
415 Show all images (not just those missing alt text)
416 </label>
417 </p>
418
419 <?php if (empty($attachments)) : ?>
420 <p>No images without alt text were found.</p>
421 <?php else : ?>
422 <table class="widefat fixed striped">
423 <thead>
424 <tr>
425 <th>ID</th>
426 <th>Thumbnail</th>
427 <th>Alt Tag</th>
428 <th>Save</th>
429 </tr>
430 </thead>
431 <tbody>
432 <?php foreach ($attachments as $attachment) :
433 $id = $attachment->ID;
434 $alt = get_post_meta($id, '_wp_attachment_image_alt', true);
435 $thumb = wp_get_attachment_image_url($id, [48, 48]);
436 $nonce = wp_create_nonce("ariaat_update_alt_{$id}");
437 ?>
438 <tr data-id="<?php echo esc_attr($id); ?>">
439 <td><?php echo esc_html($id); ?></td>
440 <td><img src="<?php echo esc_url($thumb); ?>" width="48" height="48" /></td>
441 <td><input type="text" class="ariaat-alt" value="<?php echo esc_attr($alt); ?>" placeholder="no alt tag" /></td>
442 <td>
443 <button class="button ariaat-save-alt"
444 data-id="<?php echo esc_attr($id); ?>"
445 data-nonce="<?php echo esc_attr($nonce); ?>">
446 Save
447 </button>
448 </td>
449 </tr>
450 <?php endforeach; ?>
451 </tbody>
452 </table>
453
454 <?php if ($total_pages > 1) : ?>
455 <div class="ariaat-pagination">
456 <?php
457 $base_url = remove_query_arg(['paged']);
458 for ($i = 1; $i <= $total_pages; $i++) :
459 $url = add_query_arg('paged', $i, $base_url);
460 $active_class = ($i == $paged) ? 'active' : '';
461 echo "<a class='{$active_class}' href='" . esc_url($url) . "'>$i</a> ";
462 endfor;
463 ?>
464 </div>
465 <?php endif; ?>
466
467 <?php endif;
468 }
469
470
471
472
473 do_action( 'ariaat_before_admin_submit_button', $active_tab );
474
475 submit_button();
476 ?>
477
478 </form>
479
480 </div>
481
482 <div class="sidebar_cell">
483 <?php $this->sidebar_help( $active_tab ); ?>
484 </div>
485
486 </div>
487
488 <?php
489 }
490
491
492 // sidebar
493 public function sidebar_help( $active_tab ) {
494 ?>
495 <div class="box">
496 <h3>PRO Plugin</h3>
497
498 <p><strong>More Features</strong></p>
499 <p>
500 The PRO plugin provides extra features:
501 </p>
502 <ul>
503 <li><span class="dashicons dashicons-saved"></span> Unlimited Menus in ARIA labels</li>
504 <li><span class="dashicons dashicons-saved"></span> Unlimited Menus in Roles</li>
505 <li><span class="dashicons dashicons-saved"></span> All ARIA attributes in dropdown</li>
506 <li><span class="dashicons dashicons-saved"></span> All Roles in dropdown</li>
507 </ul>
508 <a class="button" href="https://wcagforwp.com/downloads/pro">View PRO Plugin</a>
509 </div>
510 <?php
511 $method = 'sidebar_' . str_replace( '-', '_', $active_tab );
512 if ( method_exists( $this, $method ) ) {
513 $this->$method( $active_tab );
514 } else {
515 $this->sidebar_general( $active_tab );
516 }
517 }
518
519
520 // sidebar
521 public function sidebar_general() {
522
523 ?>
524 <div class="box">
525 <h3>Help</h3>
526
527 <p><strong>Language</strong></p>
528 <p>
529 This sets the default <code>lang</code> attribute in your site’s HTML. It helps screen readers and search engines understand what language your site is written in.
530 <br>For example, use <code>en</code> for English, <code>en-AU</code> for Australian English, <code>fr</code> for French, etc.
531 <br><strong>Tip:</strong> This should match the main language used across your website.
532 </p>
533
534 <p><strong>Skip Link Target</strong></p>
535 <p>
536 Adds a “Skip to content” link at the very top of your site. This improves accessibility for keyboard and screen reader users by letting them jump straight to the main content.
537 <br>Enter a CSS selector that matches your main content area, like <code>#primary</code> or <code>.site-main</code>. This should point to the container that wraps your main article or page content.
538 <br><strong>Tip:</strong> You can inspect your site using right-click “Inspect” to find the correct ID or class.
539 </p>
540
541 <p><strong>Focus Outline</strong></p>
542 <p>
543 Ensures that keyboard users can clearly see which element is currently focused - like buttons, links, or form fields. Some themes hide this outline by default, which can make navigation difficult.
544 <br>This setting forces the outline to remain visible for better usability and compliance with WCAG.
545 </p>
546 </div>
547
548
549
550 <?php
551 }
552
553
554 // sidebar
555 public function sidebar_aria() {
556
557 ?>
558 <div class="box">
559 <h3>Menu ARIA Labels</h3>
560
561 <p><strong>What it does</strong><br>
562 Adds <code>aria-label</code> attributes to links in the menu when the <code>title</code> is different from the visible text.</p>
563
564 <p><strong>Why it matters</strong><br>
565 This helps screen readers provide more context. <code>title</code> attributes are not reliably announced by screen readers. Using <code>aria-label</code> improves accessibility and clarity.</p>
566
567 <p><strong>When to use</strong><br>
568 Ideal when your menu link text is short (e.g. “Home”) but you’ve added a longer title like “Go to homepage” in the Menu editor.</p>
569
570 <p><strong>Example</strong><br>
571 If a link shows “About” and the title is “Learn more about our company”, this becomes:<br>
572 <code>&lt;a href="/about" aria-label="Learn more about our company"&gt;About&lt;/a&gt;</code></p>
573
574 <p><strong>Where to set titles</strong><br>
575 Add title attributes <a target="_blank" href="<?php echo esc_url( admin_url('/nav-menus.php') );?>">here</a> or go to <strong>Appearance Menus</strong>. Open any menu item and use the “Title Attribute field. Enable it via “Screen Options” if it’s hidden. </p>
576
577 <p><strong>Limitations</strong><br>
578 Only applies when the <code>title</code> and link text differ. If no <code>title</code> exists, nothing will be added.</p>
579 </div>
580
581 <div class="box">
582 <h3>Custom ARIA Attributes</h3>
583 <p><strong>HTML Selector</strong></p>
584 <p>
585 The HTML selector is the item that you wish to target. For example, to add an aria-label attribute to the
586 <code><?php echo esc_attr( htmlentities('<div class="header"></div>') ); ?></code> on your site, you would set the HTML selector to
587 <code>.header</code>.
588 </p>
589
590 <p><strong>ARIA Attribute</strong></p>
591 <p>
592 Choose which ARIA attribute you want to apply, such as <code>aria-label</code> or <code>aria-hidden</code>.
593 These attributes help assistive technologies better understand the purpose of elements on your site.
594 <br><a href="https://www.w3.org/WAI/ARIA/apg/practices/" target="_blank">View ARIA Authoring Practices</a>
595 </p>
596
597 <p><strong>Value</strong></p>
598 <p>
599 The value is what will be inserted into the ARIA attribute. For example, if you’re using <code>aria-label</code>,
600 you might enter <code>Main Navigation</code> to describe the element’s purpose.
601 </p>
602
603
604 </div>
605
606
607 <?php
608 }
609
610 // sidebar
611 public function sidebar_roles() {
612 ?>
613 <div class="box">
614 <h3>Menu Roles</h3>
615
616 <p><strong>What it does</strong><br>
617 Adds a <code>role="navigation"</code> to selected menus to help screen readers identify them as navigation areas.</p>
618
619 <p><strong>Why it matters</strong><br>
620 Not all themes include ARIA roles by default. This role improves accessibility by signaling the purpose of the menu structure.</p>
621
622 <p><strong>When to use</strong><br>
623 Use this when your theme’s menu is missing a semantic container (like a <code>&lt;nav&gt;</code> tag) or lacks a <code>role</code> attribute.</p>
624
625 <p><strong>Best practice</strong><br>
626 ARIA roles should only be added when the HTML is not already semantic. For example, use <code>role="navigation"</code> on a <code>&lt;div&gt;</code> - but not on a <code>&lt;nav&gt;</code> unless it’s missing the role.</p>
627
628 <p><strong>Limitations</strong><br>
629 This only applies to menus created using WordPress’s <code>wp_nav_menu()</code>. It cannot modify HTML added manually by your theme.</p>
630 </div>
631
632 <div class="box">
633 <h3>Custom Roles</h3>
634
635 <p><strong>What it does</strong><br>
636 Lets you assign ARIA roles (like <code>main</code>, <code>banner</code>, or <code>search</code>) to specific elements using CSS selectors.</p>
637
638 <p><strong>When to use</strong><br>
639 Useful for marking important sections of your site when semantic elements like <code>&lt;main&gt;</code>, <code>&lt;header&gt;</code>, or <code>&lt;aside&gt;</code> are not being used. Avoid using roles redundantly on elements that are already semantic.</p>
640
641 <p><strong>HTML Selector</strong><br>
642 Target the element you want to apply a role to - for example: <code>.sidebar</code> or <code>#main-content</code>.</p>
643
644 <p><strong>Role</strong><br>
645 Choose the appropriate role based on the element’s purpose. For example, use <code>main</code> for primary content, or <code>complementary</code> for sidebars.
646 <br><a href="https://www.w3.org/WAI/ARIA/apg/roles/" target="_blank">View all landmark roles</a></p>
647 </div>
648 <?php
649 }
650
651 public function sidebar_contrast() {
652 ?>
653 <div class="box">
654 <h3>High Contrast Adjustments</h3>
655
656 <p><strong>What it does</strong><br>
657 Allows you to manually set text and background colors on specific elements to improve readability and meet WCAG contrast requirements.</p>
658
659 <p><strong>Why it matters</strong><br>
660 Insufficient contrast is one of the most common accessibility issues. Low contrast can make text unreadable for users with vision impairments, especially in bright or dim environments.</p>
661
662 <p><strong>When to use</strong><br>
663 Use this when you have areas on your site with poor contrast (e.g. light gray text on a white background). This feature is ideal for fixing contrast issues without editing your theme's CSS directly.</p>
664
665 <p><strong>HTML Selector</strong><br>
666 The selector is the element you want to target. For example, to apply contrast to:<br>
667 <code><?php echo esc_html('<div class="content-box">...</div>'); ?></code><br>
668 use the selector <code>.content-box</code>.</p>
669
670 <p><strong>Text & Background Colors</strong><br>
671 Choose a readable foreground (text) and background color. The tool will calculate the contrast ratio and tell you if it passes WCAG AA or AAA standards.</p>
672
673 <p><strong>Limitations</strong><br>
674 This is best used for specific tweaks - not full theme styling.</p>
675
676 <p><a href="https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html" target="_blank">Learn more about color contrast requirements</a></p>
677 </div>
678 <?php
679 }
680
681
682 private function get_aria_attributes() {
683 $attributes = [
684 'aria-describedby' => ['label' => 'aria-describedby'],
685 'aria-disabled' => ['label' => 'aria-disabled'],
686 'aria-expanded' => ['label' => 'aria-expanded'],
687 'aria-hidden' => ['label' => 'aria-hidden'],
688 'aria-label' => ['label' => 'aria-label'],
689 'aria-labelledby' => ['label' => 'aria-labelledby'],
690 ];
691
692 /**
693 * Filter the list of ARIA attributes available in the plugin.
694 *
695 * @param array $attributes The default set of ARIA attributes.
696 */
697 return apply_filters('ariaat_aria_attributes_options', $attributes);
698 }
699
700
701 private function get_role_options() {
702 $roles = [
703 'banner' => ['label' => 'banner'],
704 'button' => ['label' => 'button'],
705 'checkbox' => ['label' => 'checkbox'],
706 'complementary' => ['label' => 'complementary'],
707 'contentinfo' => ['label' => 'contentinfo'],
708 'form' => ['label' => 'form'],
709 'grid' => ['label' => 'grid'],
710 'heading' => ['label' => 'heading'],
711 'img' => ['label' => 'img'],
712 'link' => ['label' => 'link'],
713 'list' => ['label' => 'list'],
714 'listitem' => ['label' => 'listitem'],
715 'main' => ['label' => 'main'],
716 'navigation' => ['label' => 'navigation'],
717 'region' => ['label' => 'region'],
718 'row' => ['label' => 'row'],
719 'rowheader' => ['label' => 'rowheader'],
720 'search' => ['label' => 'search'],
721 'table' => ['label' => 'table'],
722 'textbox' => ['label' => 'textbox'],
723 ];
724
725 /**
726 * Filter the list of available roles.
727 *
728 * @param array $roles Array of role definitions.
729 */
730 return apply_filters('ariaat_roles_options', $roles);
731 }
732
733
734 public function sanitize_array($input) {
735 if (!is_array($input)) {
736 return sanitize_text_field($input);
737 }
738
739 foreach ($input as $key => $item) {
740 if (is_array($item)) {
741 foreach ($item as $subkey => $value) {
742 // Sanitize based on known keys
743 if (in_array($subkey, ['selector'], true)) {
744 // Allow basic CSS selectors: letters, numbers, dashes, underscores, dots, #, >, space, :
745 $input[$key][$subkey] = preg_replace('/[^a-zA-Z0-9\s\.\#\>\:\[\]\=\"~\+\-\*(),]/', '', $value);
746 } elseif (in_array($subkey, ['attribute', 'role'], true)) {
747 // Whitelist attribute/role names to be alphanumeric with optional dashes
748 $input[$key][$subkey] = preg_replace('/[^a-zA-Z0-9\-_]/', '', $value);
749 } else {
750 $input[$key][$subkey] = sanitize_text_field($value);
751 }
752 }
753 } else {
754 $input[$key] = sanitize_text_field($item);
755 }
756 }
757
758 return $input;
759 }
760
761
762
763 public function sanitize_menu_selection($input) {
764 $allowed_menus = array_keys($this->get_all_menus());
765
766 if( ! $input || ! array( $allowed_menus ) || ! array( $input ) )
767 return;
768 $selected = array_intersect($input, $allowed_menus);
769
770 return $selected;
771 }
772
773 public function sanitize_general_settings($input) {
774
775 $output = [];
776
777 // Language setting
778 $output['language'] = isset($input['language']) ? sanitize_text_field($input['language']) : '';
779
780 $output['skip_link'] = isset($input['skip_link']) ? sanitize_text_field($input['skip_link']) : '';
781
782 $output['enable_frontend_checker'] = isset($input['enable_frontend_checker']) ? '1' : '';
783 $output['focus_outline'] = isset($input['focus_outline']) ? '1' : '';
784 $output['fix_tabindex'] = isset($input['fix_tabindex']) ? '1' : '';
785 $output['make_viewport_scalable'] = isset($input['make_viewport_scalable']) ? '1' : '';
786
787 return $output;
788
789 }
790
791
792 }
793
794 // Initialize the class
795 new ARIAAT_Admin();
796