@@ -39,44 +39,33 @@ function a11y_addon_update_check() {
3939}
4040add_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 */
6656function 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-
170140function 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-
247206function a11y_addon_hide_dropdown_counts ( $ return , $ params ) {
248207 return false ;
249208}
@@ -267,48 +226,3 @@ function a11y_addon_disable_auto_refresh() {
267226<?php
268227}
269228add_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