Skip to content

Commit a11e52f

Browse files
committed
Some improvements
- Remove some non a11y specific features - Use vanilla JS instead of jQuery - Restrict JS to loading only on pages using FacetWP - Improve pagination accessibility - Add type="reset" to reset button
1 parent 984864a commit a11e52f

File tree

1 file changed

+71
-157
lines changed

1 file changed

+71
-157
lines changed

a11y-add-on-for-facetwp.php

Lines changed: 71 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -39,44 +39,33 @@ function a11y_addon_update_check() {
3939
}
4040
add_action( 'plugins_loaded', 'a11y_addon_update_check' );
4141

42-
43-
/**
44-
* Enqueue jQuery because FacetWP just assumes it's enqueued.
45-
*/
46-
function a11y_addon_facet_assets() {
47-
wp_enqueue_script('jquery');
48-
}
49-
add_action( 'wp_enqueue_scripts', 'a11y_addon_facet_assets' );
50-
51-
5242
/**
5343
* Adjusts markup for specific facets so they use real input elements
5444
* Adds matching label for and ids to all facets
5545
*
5646
* @param string $output HTML
5747
* @param array $params FacetWP field parameters
58-
*
48+
*
5949
* @return string Updated HTML output for a facet
60-
*
50+
*
6151
* @todo consider whether a combination of totally custom output and str_replace make sense or whether doing something with the WP HTML API might make more sense in the long term
62-
*
52+
*
6353
* most of this courtesy of Mark Root-Wiley
6454
* @link https://github.com/mrwweb/accessibility-addon-for-facetwp
6555
*/
6656
function a11y_addon_transform_facet_markup( $output, $params ) {
67-
6857
$facet_type = $params['facet']['type'];
6958

70-
switch ($facet_type) {
71-
59+
switch ( $facet_type ) {
7260
case 'checkboxes':
73-
// Note: The trick to this working was moving the facetwp-checkbox class and data-value attribute to the `input`. Clicking the label works because the input element still emits a click event when the label is clicked. Leaving that class and attribute on the wrapping list item resulted in two events being fired when the label was clicked.
74-
$output = sprintf('<fieldset><legend>%1$s</legend>',
75-
$params['facet']['label'] );
61+
// Note: The trick to this working was moving the facetwp-checkbox class and data-value attribute to the `input`.
62+
// Clicking the label works because the input element still emits a click event when the label is clicked.
63+
// Leaving that class and attribute on the wrapping list item resulted in two events being fired when the label was clicked.
64+
$output = '';
7665
foreach( $params['values'] as $value ) {
7766
if( $value['counter'] > 0 || ! $params['facet']['preserve_ghosts'] === 'no' ) {
7867
$output .= sprintf(
79-
'<div>
68+
'<div class="facetwp-checkbox-wrapper">
8069
<input type="checkbox" id="%3$s"%1$s value="%2$s" class="facetwp-checkbox%1$s" data-value="%2$s">
8170
<label for="%3$s">
8271
<span class="facetwp-display-value">%4$s</span>
@@ -91,71 +80,53 @@ function a11y_addon_transform_facet_markup( $output, $params ) {
9180
);
9281
}
9382
}
94-
$output .= '</fieldset>';
9583
break;
9684

9785
case 'search':
98-
// use search landmark and insert a real button
99-
$output = '<search>' . $output . '</search>';
10086
// remove the fake button
10187
$output = str_replace( '<i class="facetwp-icon"></i>', '', $output );
88+
10289
// add label to search input
10390
$id = $params['facet']['name'];
104-
$output = str_replace(
105-
'<input', '<div class="trec-facetwp-search-wrapper"><input id="' . esc_attr( $id ) . '"', $output );
106-
91+
$output = str_replace( '<input', '<div class="trec-facetwp-search-wrapper"><input id="' . esc_attr( $id ) . '"', $output );
92+
10793
// placeholders are bad for UX
10894
$output = str_replace( 'placeholder="Enter keywords"', '', $output );
10995
break;
11096

11197
case 'dropdown':
112-
11398
$output = str_replace( 'facetwp-dropdown', 'facetwp-dropdown a11y-addon-filter', $output );
11499

115-
$id_string = 'id="'.$params['facet']['name'].'" class=';
100+
$id_string = 'id="' . $params['facet']['name'] . '" class=';
116101

117102
$output = str_replace('class=', $id_string, $output);
118-
119-
break;
120-
121-
case 'radio':
122-
$output = sprintf('<fieldset><legend>%1$s</legend>',
123-
$params['facet']['label'] );
124-
foreach( $params['values'] as $value ) {
125-
$output .= sprintf(
126-
'<div><input type="radio" id="%1$s" name="%3$s" value="%2$s">
127-
<label for="%1$s">%2$s</label></div>',
128-
esc_attr( 'radio-'.$value['facet_value'] ),
129-
esc_html( $value['facet_display_value'] ),
130-
esc_attr( $params['facet']['name'] )
131-
);
132-
}
133-
134-
$output .= '</fieldset>';
135103
break;
136104

137105
case 'reset':
138-
139-
$output = str_replace('button','button type="reset"',$output);
140-
141-
break;
142-
143-
case 'pager':
144-
145-
$output = sprintf('
146-
<nav class="navigation pagination" aria-label="Pagination"><h2 class="screen-reader-text">Pagination</h2>%1$s</nav>',
147-
$output);
148-
106+
$output = str_replace('<button', '<button type="reset"', $output);
149107
break;
150108

151109
default:
152110

153111
$id_string = 'id="'.$params['facet']['name'].'" class=';
154112

155113
$output = str_replace('class=', $id_string, $output);
114+
break;
115+
116+
case 'pager':
117+
// Use nav element for pager
118+
$output = str_replace( '<div', '<nav aria-label="' . esc_html__( 'Pagination', 'aawp' ) . '"', $output );
119+
$output = str_replace( '</div>', '</nav>', $output );
156120

121+
// Add role="presentation" to dots & active item so screen readers don't read them as links
122+
$output = str_replace( 'facetwp-page dots"', 'facetwp-page dots" role="presentation"', $output );
123+
$output = str_replace( 'facetwp-page active"', 'facetwp-page active" role="presentation"', $output );
124+
125+
// Change page links to buttons
126+
$output = str_replace( 'a ', 'button ', $output );
127+
break;
157128
}
158-
129+
159130
return $output;
160131
}
161132

@@ -166,84 +137,72 @@ function a11y_addon_transform_facet_markup( $output, $params ) {
166137
* Programatically add labels above filters
167138
* @link https://facetwp.com/add-labels-above-each-facet/
168139
*/
169-
170140
function a11y_addon_add_facet_labels() {
171141
?>
172142
<script>
173-
(function($) {
174-
175-
function remove_underscores( name ) {
176-
return name.replace(/_/g, ' ');
177-
}
178-
179-
// Make enter & space work for links
180-
$(document).on('keydown', '.facetwp-page, .facetwp-toggle, .facetwp-selection-value', function(e) {
181-
var keyCode = e.originalEvent.keyCode;
182-
if ( 32 == keyCode || 13 == keyCode ) {
183-
e.preventDefault();
184-
$(this).click();
185-
}
186-
});
187-
188-
$(document).on('keydown', '.facetwp-checkbox, .facetwp-radio', function(e) {
189-
var keyCode = e.originalEvent.keyCode;
190-
if ( 32 == keyCode || 13 == keyCode ) {
191-
var is_checked = $(this).hasClass('checked');
192-
193-
if (!is_checked) {
194-
$(this).attr('aria-checked', 'true');
195-
} else {
196-
$(this).attr('aria-checked', 'false');
197-
}
198-
199-
e.preventDefault();
200-
$(this).click();
201-
}
202-
});
203-
204-
$(document).on('facetwp-loaded', function() {
143+
(function() {
144+
document.addEventListener('facetwp-loaded', function() {
145+
// Add labels
146+
var facets = document.querySelectorAll('.facetwp-facet');
205147

206-
// pager
207-
$('.facetwp-pager').attr('role', 'navigation');
148+
facets.forEach(function(facet) {
149+
var facet_name = facet.getAttribute('data-name');
150+
var facet_type = facet.getAttribute('data-type');
208151

209-
// Add labels
210-
$('.facetwp-facet').each(function() {
211-
var $facet = $(this);
212-
var facet_name = $facet.attr('data-name');
213-
var facet_type = $facet.attr('data-type');
214-
215-
if ( facet_name && facet_type ) {
216-
// Don't label some facets
217-
if ( facet_type.match(/checkboxes|radio|pager|reset|results_count/g) ) {
152+
if (facet_name && facet_type) {
153+
// Exclude some facets from getting labels
154+
if (facet_name.match(/pagination/g) ||
155+
facet_name.match(/reset/g) ||
156+
facet_name.match(/results_count/g)) {
218157
return;
219158
}
220159

221160
var facet_label = FWP.settings.labels[facet_name];
222161

223-
if ($facet.closest('.facet-wrap').length < 1 && $facet.closest('.facetwp-flyout').length < 1) {
224-
225-
//wrapper div
226-
$facet.wrap(`<div class="facet-wrap facet-wrap-${facet_name}"></div>`);
227-
228-
//label
229-
$facet.before('<label class="facet-label" for="'+facet_name.replace(/\s/g, '')+'">' + facet_label + '</label>');
230-
162+
if (!facet.closest('.facet-wrap') && !facet.closest('.facetwp-flyout')) {
163+
if (facet_type.match(/checkboxes/g) || facet_type.match(/radio/g)) {
164+
// Checkboxes & radio buttons need a fieldset/legend created here using role group & arialabelledby
165+
var wrapDiv = document.createElement('div');
166+
wrapDiv.className = 'facet-wrap facet-wrap-' + facet_name;
167+
wrapDiv.setAttribute('role', 'group');
168+
wrapDiv.setAttribute('aria-labelledby', facet_name + '_label');
169+
170+
var labelDiv = document.createElement('div');
171+
labelDiv.id = facet_name + '_label';
172+
labelDiv.className = 'facet-label';
173+
labelDiv.textContent = facet_label;
174+
175+
facet.parentNode.insertBefore(wrapDiv, facet);
176+
wrapDiv.appendChild(labelDiv);
177+
wrapDiv.appendChild(facet);
178+
} else {
179+
var wrapDiv = document.createElement('div');
180+
wrapDiv.className = 'facet-wrap facet-wrap-' + facet_name;
181+
182+
var label = document.createElement('label');
183+
label.className = 'facet-label';
184+
label.setAttribute('for', facet_name.replace(/\s/g, '')); // remove spaces for id
185+
label.textContent = facet_label;
186+
187+
facet.parentNode.insertBefore(wrapDiv, facet);
188+
wrapDiv.appendChild(label);
189+
wrapDiv.appendChild(facet);
190+
}
231191
}
232192
}
233193
});
234194
});
235-
})(jQuery);
195+
})();
236196
</script>
237197
<?php
238198
}
239199

240-
add_action( 'wp_head', 'a11y_addon_add_facet_labels', 100 );
200+
add_action( 'facetwp_scripts', 'a11y_addon_add_facet_labels', 100 );
241201

242202
/**
243203
* Hide counts in all dropdowns
244204
* @link https://facetwp.com/help-center/facets/facet-types/dropdown/
245205
*/
246-
247206
function a11y_addon_hide_dropdown_counts( $return, $params ) {
248207
return false;
249208
}
@@ -267,48 +226,3 @@ function a11y_addon_disable_auto_refresh() {
267226
<?php
268227
}
269228
add_action( 'facetwp_scripts', 'a11y_addon_disable_auto_refresh', 100 );
270-
271-
// Customize icon for prev/next pagination links.
272-
function a11y_addon_facetwp_facet_pager_link($html, $params) {
273-
if ( 'next' == $params['extra_class'] ) {
274-
$icon = 'Next <svg class="icon" aria-hidden="true"><use xlink:href="#caret-right"/></svg></svg>';
275-
$html = str_replace( 'Next', $icon, $html );
276-
}
277-
278-
if ( 'prev' == $params['extra_class'] ) {
279-
$icon = '<svg class="icon" aria-hidden="true"><use xlink:href="#caret-left"/></svg></svg> Prev';
280-
$html = str_replace( 'Prev', $icon, $html );
281-
}
282-
283-
return $html;
284-
}
285-
add_action( 'facetwp_facet_pager_link', 'a11y_addon_facetwp_facet_pager_link', 100, 2 );
286-
287-
/**
288-
* Scroll back to top of results when pager is clicked
289-
* @link https://facetwp.com/how-to-scroll-the-page-on-facet-interaction/#scroll-when-a-pager-facet-is-used
290-
**/
291-
292-
function a11y_addon_scroll_on_pager_interaction() {
293-
?>
294-
<script>
295-
(function($) {
296-
$(document).on('facetwp-refresh', function() {
297-
if ( FWP.soft_refresh == true ) {
298-
FWP.enable_scroll = true;
299-
} else {
300-
FWP.enable_scroll = false;
301-
}
302-
});
303-
$(document).on('facetwp-loaded', function() {
304-
if (FWP.enable_scroll == true) {
305-
$('html, body').animate({
306-
scrollTop: $('.facetwp-template').offset().top
307-
}, 500);
308-
}
309-
});
310-
})(jQuery);
311-
</script>
312-
<?php
313-
}
314-
add_action( 'facetwp_scripts', 'a11y_addon_scroll_on_pager_interaction' );

0 commit comments

Comments
 (0)